VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c@ 105670

Last change on this file since 105670 was 101291, checked in by vboxsync, 17 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 191.5 KB
Line 
1/** @file
2Entry and initialization module for the browser.
3
4Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5(C) Copyright 2020 - 2022 Hewlett Packard Enterprise Development LP<BR>
6SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "Setup.h"
11
12SETUP_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
38EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
39EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
40EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
41EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
42
43UINTN gBrowserContextCount = 0;
44LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
45LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
46LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
47LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
48LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList);
49
50BOOLEAN mSystemSubmit = FALSE;
51BOOLEAN gResetRequiredFormLevel;
52BOOLEAN gResetRequiredSystemLevel = FALSE;
53BOOLEAN gExitRequired;
54BOOLEAN gFlagReconnect;
55BOOLEAN gCallbackReconnect;
56BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
57BOOLEAN mBrowserScopeFirstSet = TRUE;
58EXIT_HANDLER ExitHandlerFunction = NULL;
59FORM_BROWSER_FORMSET *mSystemLevelFormSet;
60
61//
62// Browser Global Strings
63//
64CHAR16 *gEmptyString;
65CHAR16 *mUnknownString = L"!";
66
67extern EFI_GUID mCurrentFormSetGuid;
68extern EFI_HII_HANDLE mCurrentHiiHandle;
69extern UINT16 mCurrentFormId;
70extern 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**/
84FORM_ENTRY_INFO *
85UiAddMenuList (
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**/
123EFI_FORM_ID
124GetFirstFormId (
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**/
148FORM_ENTRY_INFO *
149UiFindMenuList (
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**/
212FORM_ENTRY_INFO *
213UiFindParentMenu (
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**/
266VOID
267UiFreeMenuList (
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**/
288VOID
289UiCopyMenuList (
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**/
324VOID
325LoadAllHiiFormset (
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**/
398UINT32
399PopupErrorMessage (
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**/
466EFI_STATUS
467EFIAPI
468SendForm (
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**/
626EFI_STATUS
627ProcessStorage (
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**/
726EFI_STATUS
727EFIAPI
728BrowserCallback (
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**/
854VOID
855EFIAPI
856FormDisplayCallback (
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**/
882EFI_STATUS
883EFIAPI
884InitializeSetup (
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**/
980EFI_STRING_ID
981NewString (
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**/
1003EFI_STATUS
1004DeleteString (
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**/
1026CHAR16 *
1027GetToken (
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**/
1054VOID
1055NewStringCpy (
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**/
1075VOID
1076NewStringCat (
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**/
1112EFI_STATUS
1113GetValueByName (
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**/
1162EFI_STATUS
1163SetValueByName (
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**/
1227EFI_STATUS
1228StorageToConfigResp (
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**/
1303EFI_STATUS
1304ConfigRespToStorage (
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**/
1383VOID
1384GetBitsQuestionValue (
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**/
1418VOID
1419SetBitsQuestionValue (
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**/
1449EFI_STATUS
1450BufferToValue (
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**/
1580EFI_STATUS
1581GetQuestionValue (
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**/
1912EFI_STATUS
1913SetQuestionValue (
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**/
2249EFI_STATUS
2250ValidateQuestion (
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**/
2363EFI_STATUS
2364ValueChangedValidation (
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**/
2405EFI_STATUS
2406NoSubmitCheck (
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**/
2463EFI_STATUS
2464SynchronizeStorage (
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**/
2551VOID
2552SendDiscardInfoToDriver (
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**/
2622VOID
2623SubmitCallbackForForm (
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**/
2679VOID
2680SubmitCallback (
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**/
2711BOOLEAN
2712ValidateHiiHandle (
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**/
2750BOOLEAN
2751ValidateFormSet (
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**/
2781VOID
2782UpdateFlagForForm (
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**/
2835VOID
2836ValueChangeResetFlagUpdate (
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**/
2875BOOLEAN
2876FindQuestionFromProgress (
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**/
3026VOID
3027GetSyncRestoreConfigRequest (
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**/
3127UINT32
3128ConfirmSaveFail (
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**/
3166UINT32
3167ConfirmNoSubmitFail (
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**/
3207EFI_STATUS
3208DiscardForm (
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**/
3338EFI_STATUS
3339SubmitForForm (
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**/
3486EFI_STATUS
3487SubmitForFormSet (
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**/
3694EFI_STATUS
3695SubmitForSystem (
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**/
3858EFI_STATUS
3859SubmitForm (
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**/
3895VOID
3896EFIAPI
3897HiiToLower (
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**/
3929CHAR16 *
3930GetOffsetFromConfigResp (
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**/
4003EFI_STATUS
4004GetDefaultValueFromAltCfg (
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**/
4071INTN
4072GetDefaultIdForCallBack (
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**/
4103UINT64
4104GetArrayData (
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**/
4148VOID
4149SetArrayData (
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**/
4190QUESTION_OPTION *
4191ValueToOption (
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**/
4232EFI_STATUS
4233GetQuestionDefault (
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 //
4276ReGetDefault:
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**/
4589VOID
4590ExtractAltCfgForForm (
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**/
4692VOID
4693CleanAltCfgForForm (
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**/
4720VOID
4721ExtractAltCfgForFormSet (
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**/
4800VOID
4801CleanAltCfgForFormSet (
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**/
4843EFI_STATUS
4844ExtractDefault (
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**/
5010BOOLEAN
5011IsQuestionValueChanged (
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**/
5130EFI_STATUS
5131LoadFormConfig (
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**/
5180EFI_STATUS
5181LoadFormSetConfig (
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**/
5220VOID
5221RemoveElement (
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**/
5254VOID
5255RemoveConfigRequest (
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**/
5338VOID
5339CleanBrowserStorage (
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**/
5380BOOLEAN
5381ElementValidation (
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**/
5397VOID
5398AppendConfigRequest (
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**/
5448BOOLEAN
5449ConfigRequestAdjust (
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**/
5566VOID
5567LoadStorage (
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 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
5638 //
5639 // Call GetVariable directly for EfiVarStore
5640 //
5641 Status = gRT->GetVariable (Storage->BrowserStorage->Name, &(Storage->BrowserStorage->Guid), NULL, (UINTN *)(&(Storage->BrowserStorage->Size)), Storage->BrowserStorage->EditBuffer);
5642 if (EFI_ERROR (Status)) {
5643 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
5644 }
5645 } else {
5646 //
5647 // Request current settings from Configuration Driver
5648 //
5649 Status = mHiiConfigRouting->ExtractConfig (
5650 mHiiConfigRouting,
5651 ConfigRequest,
5652 &Progress,
5653 &Result
5654 );
5655
5656 //
5657 // If get value fail, extract default from IFR binary
5658 //
5659 if (EFI_ERROR (Status)) {
5660 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
5661 } else {
5662 //
5663 // Convert Result from <ConfigAltResp> to <ConfigResp>
5664 //
5665 StrPtr = StrStr (Result, L"&GUID=");
5666 if (StrPtr != NULL) {
5667 *StrPtr = L'\0';
5668 }
5669
5670 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
5671 FreePool (Result);
5672 }
5673 }
5674
5675 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
5676
5677 //
5678 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
5679 //
5680 SynchronizeStorage (Storage->BrowserStorage, NULL, TRUE);
5681
5682 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
5683 if (ConfigRequest != NULL) {
5684 FreePool (ConfigRequest);
5685 }
5686 }
5687}
5688
5689/**
5690 Get Value changed status from old question.
5691
5692 @param NewFormSet FormSet data structure.
5693 @param OldQuestion Old question which has value changed.
5694
5695**/
5696VOID
5697SyncStatusForQuestion (
5698 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5699 IN FORM_BROWSER_STATEMENT *OldQuestion
5700 )
5701{
5702 LIST_ENTRY *Link;
5703 LIST_ENTRY *QuestionLink;
5704 FORM_BROWSER_FORM *Form;
5705 FORM_BROWSER_STATEMENT *Question;
5706
5707 //
5708 // For each form in one formset.
5709 //
5710 Link = GetFirstNode (&NewFormSet->FormListHead);
5711 while (!IsNull (&NewFormSet->FormListHead, Link)) {
5712 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5713 Link = GetNextNode (&NewFormSet->FormListHead, Link);
5714
5715 //
5716 // for each question in one form.
5717 //
5718 QuestionLink = GetFirstNode (&Form->StatementListHead);
5719 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5720 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5721 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5722
5723 if (Question->QuestionId == OldQuestion->QuestionId) {
5724 Question->ValueChanged = TRUE;
5725 return;
5726 }
5727 }
5728 }
5729}
5730
5731/**
5732 Get Value changed status from old formset.
5733
5734 @param NewFormSet FormSet data structure.
5735 @param OldFormSet FormSet data structure.
5736
5737**/
5738VOID
5739SyncStatusForFormSet (
5740 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5741 IN FORM_BROWSER_FORMSET *OldFormSet
5742 )
5743{
5744 LIST_ENTRY *Link;
5745 LIST_ENTRY *QuestionLink;
5746 FORM_BROWSER_FORM *Form;
5747 FORM_BROWSER_STATEMENT *Question;
5748
5749 //
5750 // For each form in one formset.
5751 //
5752 Link = GetFirstNode (&OldFormSet->FormListHead);
5753 while (!IsNull (&OldFormSet->FormListHead, Link)) {
5754 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5755 Link = GetNextNode (&OldFormSet->FormListHead, Link);
5756
5757 //
5758 // for each question in one form.
5759 //
5760 QuestionLink = GetFirstNode (&Form->StatementListHead);
5761 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5762 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5763 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5764
5765 if (!Question->ValueChanged) {
5766 continue;
5767 }
5768
5769 //
5770 // Find the same question in new formset and update the value changed flag.
5771 //
5772 SyncStatusForQuestion (NewFormSet, Question);
5773 }
5774 }
5775}
5776
5777/**
5778 Get current setting of Questions.
5779
5780 @param FormSet FormSet data structure.
5781
5782**/
5783VOID
5784InitializeCurrentSetting (
5785 IN OUT FORM_BROWSER_FORMSET *FormSet
5786 )
5787{
5788 LIST_ENTRY *Link;
5789 FORMSET_STORAGE *Storage;
5790 FORM_BROWSER_FORMSET *OldFormSet;
5791
5792 //
5793 // Try to find pre FormSet in the maintain backup list.
5794 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
5795 //
5796 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
5797 if (OldFormSet != NULL) {
5798 SyncStatusForFormSet (FormSet, OldFormSet);
5799 RemoveEntryList (&OldFormSet->Link);
5800 DestroyFormSet (OldFormSet);
5801 }
5802
5803 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
5804
5805 //
5806 // Extract default from IFR binary for no storage questions.
5807 //
5808 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
5809
5810 //
5811 // Request current settings from Configuration Driver
5812 //
5813 Link = GetFirstNode (&FormSet->StorageListHead);
5814 while (!IsNull (&FormSet->StorageListHead, Link)) {
5815 Storage = FORMSET_STORAGE_FROM_LINK (Link);
5816
5817 LoadStorage (FormSet, Storage);
5818
5819 Link = GetNextNode (&FormSet->StorageListHead, Link);
5820 }
5821}
5822
5823/**
5824 Fetch the Ifr binary data of a FormSet.
5825
5826 @param Handle PackageList Handle
5827 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5828 specified (NULL or zero GUID), take the first
5829 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5830 found in package list.
5831 On output, GUID of the formset found(if not NULL).
5832 @param BinaryLength The length of the FormSet IFR binary.
5833 @param BinaryData The buffer designed to receive the FormSet.
5834
5835 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
5836 BufferLength was updated.
5837 @retval EFI_INVALID_PARAMETER The handle is unknown.
5838 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
5839 be found with the requested FormId.
5840
5841**/
5842EFI_STATUS
5843GetIfrBinaryData (
5844 IN EFI_HII_HANDLE Handle,
5845 IN OUT EFI_GUID *FormSetGuid,
5846 OUT UINTN *BinaryLength,
5847 OUT UINT8 **BinaryData
5848 )
5849{
5850 EFI_STATUS Status;
5851 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
5852 UINTN BufferSize;
5853 UINT8 *Package;
5854 UINT8 *OpCodeData;
5855 UINT32 Offset;
5856 UINT32 Offset2;
5857 UINT32 PackageListLength;
5858 EFI_HII_PACKAGE_HEADER PackageHeader;
5859 UINT8 Index;
5860 UINT8 NumberOfClassGuid;
5861 BOOLEAN ClassGuidMatch;
5862 EFI_GUID *ClassGuid;
5863 EFI_GUID *ComparingGuid;
5864
5865 OpCodeData = NULL;
5866 Package = NULL;
5867 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
5868
5869 //
5870 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
5871 //
5872 if (FormSetGuid == NULL) {
5873 ComparingGuid = &gZeroGuid;
5874 } else {
5875 ComparingGuid = FormSetGuid;
5876 }
5877
5878 //
5879 // Get HII PackageList
5880 //
5881 BufferSize = 0;
5882 HiiPackageList = NULL;
5883 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5884 if (Status == EFI_BUFFER_TOO_SMALL) {
5885 HiiPackageList = AllocatePool (BufferSize);
5886 ASSERT (HiiPackageList != NULL);
5887
5888 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5889 }
5890
5891 if (EFI_ERROR (Status)) {
5892 return Status;
5893 }
5894
5895 ASSERT (HiiPackageList != NULL);
5896
5897 //
5898 // Get Form package from this HII package List
5899 //
5900 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
5901 Offset2 = 0;
5902 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
5903
5904 ClassGuidMatch = FALSE;
5905 while (Offset < PackageListLength) {
5906 Package = ((UINT8 *)HiiPackageList) + Offset;
5907 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
5908
5909 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
5910 //
5911 // Search FormSet in this Form Package
5912 //
5913 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
5914 while (Offset2 < PackageHeader.Length) {
5915 OpCodeData = Package + Offset2;
5916
5917 if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
5918 //
5919 // Try to compare against formset GUID
5920 //
5921 if (IsZeroGuid (ComparingGuid) ||
5922 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER))))
5923 {
5924 break;
5925 }
5926
5927 if (((EFI_IFR_OP_HEADER *)OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
5928 //
5929 // Try to compare against formset class GUID
5930 //
5931 NumberOfClassGuid = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
5932 ClassGuid = (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET));
5933 for (Index = 0; Index < NumberOfClassGuid; Index++) {
5934 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
5935 ClassGuidMatch = TRUE;
5936 break;
5937 }
5938 }
5939
5940 if (ClassGuidMatch) {
5941 break;
5942 }
5943 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
5944 ClassGuidMatch = TRUE;
5945 break;
5946 }
5947 }
5948
5949 Offset2 += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
5950 }
5951
5952 if (Offset2 < PackageHeader.Length) {
5953 //
5954 // Target formset found
5955 //
5956 break;
5957 }
5958 }
5959
5960 Offset += PackageHeader.Length;
5961 }
5962
5963 if (Offset >= PackageListLength) {
5964 //
5965 // Form package not found in this Package List
5966 //
5967 FreePool (HiiPackageList);
5968 return EFI_NOT_FOUND;
5969 }
5970
5971 if (FormSetGuid != NULL) {
5972 //
5973 // Return the FormSet GUID
5974 //
5975 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *)OpCodeData)->Guid, sizeof (EFI_GUID));
5976 }
5977
5978 //
5979 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
5980 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
5981 // of the Form Package.
5982 //
5983 *BinaryLength = PackageHeader.Length - Offset2;
5984 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
5985
5986 FreePool (HiiPackageList);
5987
5988 if (*BinaryData == NULL) {
5989 return EFI_OUT_OF_RESOURCES;
5990 }
5991
5992 return EFI_SUCCESS;
5993}
5994
5995/**
5996 Initialize the internal data structure of a FormSet.
5997
5998 @param Handle PackageList Handle
5999 @param FormSetGuid On input, GUID or class GUID of a formset. If not
6000 specified (NULL or zero GUID), take the first
6001 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
6002 found in package list.
6003 On output, GUID of the formset found(if not NULL).
6004 @param FormSet FormSet data structure.
6005
6006 @retval EFI_SUCCESS The function completed successfully.
6007 @retval EFI_NOT_FOUND The specified FormSet could not be found.
6008
6009**/
6010EFI_STATUS
6011InitializeFormSet (
6012 IN EFI_HII_HANDLE Handle,
6013 IN OUT EFI_GUID *FormSetGuid,
6014 OUT FORM_BROWSER_FORMSET *FormSet
6015 )
6016{
6017 EFI_STATUS Status;
6018 EFI_HANDLE DriverHandle;
6019
6020 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
6021 if (EFI_ERROR (Status)) {
6022 return Status;
6023 }
6024
6025 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
6026 FormSet->HiiHandle = Handle;
6027 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
6028 FormSet->QuestionInited = FALSE;
6029
6030 //
6031 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
6032 //
6033 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
6034 if (EFI_ERROR (Status)) {
6035 return Status;
6036 }
6037
6038 FormSet->DriverHandle = DriverHandle;
6039 Status = gBS->HandleProtocol (
6040 DriverHandle,
6041 &gEfiHiiConfigAccessProtocolGuid,
6042 (VOID **)&FormSet->ConfigAccess
6043 );
6044 if (EFI_ERROR (Status)) {
6045 //
6046 // Configuration Driver don't attach ConfigAccess protocol to its HII package
6047 // list, then there will be no configuration action required
6048 //
6049 FormSet->ConfigAccess = NULL;
6050 }
6051
6052 //
6053 // Parse the IFR binary OpCodes
6054 //
6055 Status = ParseOpCodes (FormSet);
6056
6057 return Status;
6058}
6059
6060/**
6061 Save globals used by previous call to SendForm(). SendForm() may be called from
6062 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
6063 So, save globals of previous call to SendForm() and restore them upon exit.
6064
6065**/
6066VOID
6067SaveBrowserContext (
6068 VOID
6069 )
6070{
6071 BROWSER_CONTEXT *Context;
6072 FORM_ENTRY_INFO *MenuList;
6073 FORM_BROWSER_FORMSET *FormSet;
6074
6075 gBrowserContextCount++;
6076 if (gBrowserContextCount == 1) {
6077 //
6078 // This is not reentry of SendForm(), no context to save
6079 //
6080 return;
6081 }
6082
6083 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
6084 ASSERT (Context != NULL);
6085
6086 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
6087
6088 //
6089 // Save FormBrowser context
6090 //
6091 Context->Selection = gCurrentSelection;
6092 Context->ResetRequired = gResetRequiredFormLevel;
6093 Context->FlagReconnect = gFlagReconnect;
6094 Context->CallbackReconnect = gCallbackReconnect;
6095 Context->ExitRequired = gExitRequired;
6096 Context->HiiHandle = mCurrentHiiHandle;
6097 Context->FormId = mCurrentFormId;
6098 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
6099 Context->SystemLevelFormSet = mSystemLevelFormSet;
6100 Context->CurFakeQestId = mCurFakeQestId;
6101 Context->HiiPackageListUpdated = mHiiPackageListUpdated;
6102 Context->FinishRetrieveCall = mFinishRetrieveCall;
6103
6104 //
6105 // Save the menu history data.
6106 //
6107 InitializeListHead (&Context->FormHistoryList);
6108 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
6109 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
6110 RemoveEntryList (&MenuList->Link);
6111
6112 InsertTailList (&Context->FormHistoryList, &MenuList->Link);
6113 }
6114
6115 //
6116 // Save formset list.
6117 //
6118 InitializeListHead (&Context->FormSetList);
6119 while (!IsListEmpty (&gBrowserFormSetList)) {
6120 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink);
6121 RemoveEntryList (&FormSet->Link);
6122
6123 InsertTailList (&Context->FormSetList, &FormSet->Link);
6124 }
6125
6126 //
6127 // Insert to FormBrowser context list
6128 //
6129 InsertHeadList (&gBrowserContextList, &Context->Link);
6130}
6131
6132/**
6133 Restore globals used by previous call to SendForm().
6134
6135**/
6136VOID
6137RestoreBrowserContext (
6138 VOID
6139 )
6140{
6141 LIST_ENTRY *Link;
6142 BROWSER_CONTEXT *Context;
6143 FORM_ENTRY_INFO *MenuList;
6144 FORM_BROWSER_FORMSET *FormSet;
6145
6146 ASSERT (gBrowserContextCount != 0);
6147 gBrowserContextCount--;
6148 if (gBrowserContextCount == 0) {
6149 //
6150 // This is not reentry of SendForm(), no context to restore
6151 //
6152 return;
6153 }
6154
6155 ASSERT (!IsListEmpty (&gBrowserContextList));
6156
6157 Link = GetFirstNode (&gBrowserContextList);
6158 Context = BROWSER_CONTEXT_FROM_LINK (Link);
6159
6160 //
6161 // Restore FormBrowser context
6162 //
6163 gCurrentSelection = Context->Selection;
6164 gResetRequiredFormLevel = Context->ResetRequired;
6165 gFlagReconnect = Context->FlagReconnect;
6166 gCallbackReconnect = Context->CallbackReconnect;
6167 gExitRequired = Context->ExitRequired;
6168 mCurrentHiiHandle = Context->HiiHandle;
6169 mCurrentFormId = Context->FormId;
6170 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
6171 mSystemLevelFormSet = Context->SystemLevelFormSet;
6172 mCurFakeQestId = Context->CurFakeQestId;
6173 mHiiPackageListUpdated = Context->HiiPackageListUpdated;
6174 mFinishRetrieveCall = Context->FinishRetrieveCall;
6175
6176 //
6177 // Restore the menu history data.
6178 //
6179 while (!IsListEmpty (&Context->FormHistoryList)) {
6180 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
6181 RemoveEntryList (&MenuList->Link);
6182
6183 InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
6184 }
6185
6186 //
6187 // Restore the Formset data.
6188 //
6189 while (!IsListEmpty (&Context->FormSetList)) {
6190 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink);
6191 RemoveEntryList (&FormSet->Link);
6192
6193 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
6194 }
6195
6196 //
6197 // Remove from FormBrowser context list
6198 //
6199 RemoveEntryList (&Context->Link);
6200 gBS->FreePool (Context);
6201}
6202
6203/**
6204 Find the matched FormSet context in the backup maintain list based on HiiHandle.
6205
6206 @param Handle The Hii Handle.
6207
6208 @return the found FormSet context. If no found, NULL will return.
6209
6210**/
6211FORM_BROWSER_FORMSET *
6212GetFormSetFromHiiHandle (
6213 EFI_HII_HANDLE Handle
6214 )
6215{
6216 LIST_ENTRY *Link;
6217 FORM_BROWSER_FORMSET *FormSet;
6218
6219 Link = GetFirstNode (&gBrowserFormSetList);
6220 while (!IsNull (&gBrowserFormSetList, Link)) {
6221 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6222 Link = GetNextNode (&gBrowserFormSetList, Link);
6223 if (!ValidateFormSet (FormSet)) {
6224 continue;
6225 }
6226
6227 if (FormSet->HiiHandle == Handle) {
6228 return FormSet;
6229 }
6230 }
6231
6232 return NULL;
6233}
6234
6235/**
6236 Check whether the input HII handle is the FormSet that is being used.
6237
6238 @param Handle The Hii Handle.
6239
6240 @retval TRUE HII handle is being used.
6241 @retval FALSE HII handle is not being used.
6242
6243**/
6244BOOLEAN
6245IsHiiHandleInBrowserContext (
6246 EFI_HII_HANDLE Handle
6247 )
6248{
6249 LIST_ENTRY *Link;
6250 BROWSER_CONTEXT *Context;
6251
6252 //
6253 // HiiHandle is Current FormSet.
6254 //
6255 if (mCurrentHiiHandle == Handle) {
6256 return TRUE;
6257 }
6258
6259 //
6260 // Check whether HiiHandle is in BrowserContext.
6261 //
6262 Link = GetFirstNode (&gBrowserContextList);
6263 while (!IsNull (&gBrowserContextList, Link)) {
6264 Context = BROWSER_CONTEXT_FROM_LINK (Link);
6265 if (Context->HiiHandle == Handle) {
6266 //
6267 // HiiHandle is in BrowserContext
6268 //
6269 return TRUE;
6270 }
6271
6272 Link = GetNextNode (&gBrowserContextList, Link);
6273 }
6274
6275 return FALSE;
6276}
6277
6278/**
6279 Perform Password check.
6280 Passwork may be encrypted by driver that requires the specific check.
6281
6282 @param Form Form where Password Statement is in.
6283 @param Statement Password statement
6284 @param PasswordString Password string to be checked. It may be NULL.
6285 NULL means to restore password.
6286 "" string can be used to checked whether old password does exist.
6287
6288 @return Status Status of Password check.
6289**/
6290EFI_STATUS
6291EFIAPI
6292PasswordCheck (
6293 IN FORM_DISPLAY_ENGINE_FORM *Form,
6294 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
6295 IN EFI_STRING PasswordString OPTIONAL
6296 )
6297{
6298 EFI_STATUS Status;
6299 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
6300 EFI_BROWSER_ACTION_REQUEST ActionRequest;
6301 EFI_IFR_TYPE_VALUE IfrTypeValue;
6302 FORM_BROWSER_STATEMENT *Question;
6303
6304 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
6305 Question = GetBrowserStatement (Statement);
6306 ASSERT (Question != NULL);
6307
6308 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
6309 if (ConfigAccess == NULL) {
6310 return EFI_UNSUPPORTED;
6311 }
6312 } else {
6313 //
6314 // If a password doesn't have the CALLBACK flag, browser will not handle it.
6315 //
6316 return EFI_UNSUPPORTED;
6317 }
6318
6319 //
6320 // Prepare password string in HII database
6321 //
6322 if (PasswordString != NULL) {
6323 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
6324 } else {
6325 IfrTypeValue.string = 0;
6326 }
6327
6328 //
6329 // Send password to Configuration Driver for validation
6330 //
6331 Status = ConfigAccess->Callback (
6332 ConfigAccess,
6333 EFI_BROWSER_ACTION_CHANGING,
6334 Question->QuestionId,
6335 Question->HiiValue.Type,
6336 &IfrTypeValue,
6337 &ActionRequest
6338 );
6339
6340 //
6341 // Remove password string from HII database
6342 //
6343 if (PasswordString != NULL) {
6344 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
6345 }
6346
6347 return Status;
6348}
6349
6350/**
6351 Find the registered HotKey based on KeyData.
6352
6353 @param[in] KeyData A pointer to a buffer that describes the keystroke
6354 information for the hot key.
6355
6356 @return The registered HotKey context. If no found, NULL will return.
6357**/
6358BROWSER_HOT_KEY *
6359GetHotKeyFromRegisterList (
6360 IN EFI_INPUT_KEY *KeyData
6361 )
6362{
6363 LIST_ENTRY *Link;
6364 BROWSER_HOT_KEY *HotKey;
6365
6366 Link = GetFirstNode (&gBrowserHotKeyList);
6367 while (!IsNull (&gBrowserHotKeyList, Link)) {
6368 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
6369 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
6370 return HotKey;
6371 }
6372
6373 Link = GetNextNode (&gBrowserHotKeyList, Link);
6374 }
6375
6376 return NULL;
6377}
6378
6379/**
6380 Configure what scope the hot key will impact.
6381 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
6382 If no scope is set, the default scope will be FormSet level.
6383 After all registered hot keys are removed, previous Scope can reset to another level.
6384
6385 @param[in] Scope Scope level to be set.
6386
6387 @retval EFI_SUCCESS Scope is set correctly.
6388 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
6389 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
6390
6391**/
6392EFI_STATUS
6393EFIAPI
6394SetScope (
6395 IN BROWSER_SETTING_SCOPE Scope
6396 )
6397{
6398 if (Scope >= MaxLevel) {
6399 return EFI_INVALID_PARAMETER;
6400 }
6401
6402 //
6403 // When no hot key registered in system or on the first setting,
6404 // Scope can be set.
6405 //
6406 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
6407 gBrowserSettingScope = Scope;
6408 mBrowserScopeFirstSet = FALSE;
6409 } else if (Scope != gBrowserSettingScope) {
6410 return EFI_UNSUPPORTED;
6411 }
6412
6413 return EFI_SUCCESS;
6414}
6415
6416/**
6417 Register the hot key with its browser action, or unregistered the hot key.
6418 Only support hot key that is not printable character (control key, function key, etc.).
6419 If the action value is zero, the hot key will be unregistered if it has been registered.
6420 If the same hot key has been registered, the new action and help string will override the previous ones.
6421
6422 @param[in] KeyData A pointer to a buffer that describes the keystroke
6423 information for the hot key. Its type is EFI_INPUT_KEY to
6424 be supported by all ConsoleIn devices.
6425 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
6426 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
6427 @param[in] HelpString Help string that describes the hot key information.
6428 Its value may be NULL for the unregistered hot key.
6429
6430 @retval EFI_SUCCESS Hot key is registered or unregistered.
6431 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
6432 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
6433 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
6434 @retval EFI_ALREADY_STARTED Key already been registered for one hot key.
6435**/
6436EFI_STATUS
6437EFIAPI
6438RegisterHotKey (
6439 IN EFI_INPUT_KEY *KeyData,
6440 IN UINT32 Action,
6441 IN UINT16 DefaultId,
6442 IN EFI_STRING HelpString OPTIONAL
6443 )
6444{
6445 BROWSER_HOT_KEY *HotKey;
6446
6447 //
6448 // Check input parameters.
6449 //
6450 if ((KeyData == NULL) || (KeyData->UnicodeChar != CHAR_NULL) ||
6451 ((Action != BROWSER_ACTION_UNREGISTER) && (HelpString == NULL)))
6452 {
6453 return EFI_INVALID_PARAMETER;
6454 }
6455
6456 //
6457 // Check whether the input KeyData is in BrowserHotKeyList.
6458 //
6459 HotKey = GetHotKeyFromRegisterList (KeyData);
6460
6461 //
6462 // Unregister HotKey
6463 //
6464 if (Action == BROWSER_ACTION_UNREGISTER) {
6465 if (HotKey != NULL) {
6466 //
6467 // The registered HotKey is found.
6468 // Remove it from List, and free its resource.
6469 //
6470 RemoveEntryList (&HotKey->Link);
6471 FreePool (HotKey->KeyData);
6472 FreePool (HotKey->HelpString);
6473 return EFI_SUCCESS;
6474 } else {
6475 //
6476 // The registered HotKey is not found.
6477 //
6478 return EFI_NOT_FOUND;
6479 }
6480 }
6481
6482 if (HotKey != NULL) {
6483 return EFI_ALREADY_STARTED;
6484 }
6485
6486 //
6487 // Create new Key, and add it into List.
6488 //
6489 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
6490 ASSERT (HotKey != NULL);
6491 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
6492 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
6493 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
6494
6495 //
6496 // Fill HotKey information.
6497 //
6498 HotKey->Action = Action;
6499 HotKey->DefaultId = DefaultId;
6500 if (HotKey->HelpString != NULL) {
6501 FreePool (HotKey->HelpString);
6502 }
6503
6504 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
6505
6506 return EFI_SUCCESS;
6507}
6508
6509/**
6510 Register Exit handler function.
6511 When more than one handler function is registered, the latter one will override the previous one.
6512 When NULL handler is specified, the previous Exit handler will be unregistered.
6513
6514 @param[in] Handler Pointer to handler function.
6515
6516**/
6517VOID
6518EFIAPI
6519RegiserExitHandler (
6520 IN EXIT_HANDLER Handler
6521 )
6522{
6523 ExitHandlerFunction = Handler;
6524 return;
6525}
6526
6527/**
6528 Check whether the browser data has been modified.
6529
6530 @retval TRUE Browser data is modified.
6531 @retval FALSE No browser data is modified.
6532
6533**/
6534BOOLEAN
6535EFIAPI
6536IsBrowserDataModified (
6537 VOID
6538 )
6539{
6540 LIST_ENTRY *Link;
6541 FORM_BROWSER_FORMSET *FormSet;
6542
6543 switch (gBrowserSettingScope) {
6544 case FormLevel:
6545 if (gCurrentSelection == NULL) {
6546 return FALSE;
6547 }
6548
6549 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
6550
6551 case FormSetLevel:
6552 if (gCurrentSelection == NULL) {
6553 return FALSE;
6554 }
6555
6556 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
6557
6558 case SystemLevel:
6559 Link = GetFirstNode (&gBrowserFormSetList);
6560 while (!IsNull (&gBrowserFormSetList, Link)) {
6561 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6562 if (!ValidateFormSet (FormSet)) {
6563 continue;
6564 }
6565
6566 if (IsNvUpdateRequiredForFormSet (FormSet)) {
6567 return TRUE;
6568 }
6569
6570 Link = GetNextNode (&gBrowserFormSetList, Link);
6571 }
6572
6573 return FALSE;
6574
6575 default:
6576 return FALSE;
6577 }
6578}
6579
6580/**
6581 Execute the action requested by the Action parameter.
6582
6583 @param[in] Action Execute the request action.
6584 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
6585
6586 @retval EFI_SUCCESS Execute the request action succss.
6587 @retval EFI_INVALID_PARAMETER The input action value is invalid.
6588
6589**/
6590EFI_STATUS
6591EFIAPI
6592ExecuteAction (
6593 IN UINT32 Action,
6594 IN UINT16 DefaultId
6595 )
6596{
6597 EFI_STATUS Status;
6598 FORM_BROWSER_FORMSET *FormSet;
6599 FORM_BROWSER_FORM *Form;
6600
6601 if ((gBrowserSettingScope < SystemLevel) && (gCurrentSelection == NULL)) {
6602 return EFI_NOT_READY;
6603 }
6604
6605 Status = EFI_SUCCESS;
6606 FormSet = NULL;
6607 Form = NULL;
6608 if (gBrowserSettingScope < SystemLevel) {
6609 FormSet = gCurrentSelection->FormSet;
6610 Form = gCurrentSelection->Form;
6611 }
6612
6613 //
6614 // Executet the discard action.
6615 //
6616 if ((Action & BROWSER_ACTION_DISCARD) != 0) {
6617 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
6618 if (EFI_ERROR (Status)) {
6619 return Status;
6620 }
6621 }
6622
6623 //
6624 // Executet the difault action.
6625 //
6626 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
6627 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
6628 if (EFI_ERROR (Status)) {
6629 return Status;
6630 }
6631
6632 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
6633 }
6634
6635 //
6636 // Executet the submit action.
6637 //
6638 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
6639 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
6640 if (EFI_ERROR (Status)) {
6641 return Status;
6642 }
6643 }
6644
6645 //
6646 // Executet the reset action.
6647 //
6648 if ((Action & BROWSER_ACTION_RESET) != 0) {
6649 gResetRequiredFormLevel = TRUE;
6650 gResetRequiredSystemLevel = TRUE;
6651 }
6652
6653 //
6654 // Executet the exit action.
6655 //
6656 if ((Action & BROWSER_ACTION_EXIT) != 0) {
6657 DiscardForm (FormSet, Form, gBrowserSettingScope);
6658 if (gBrowserSettingScope == SystemLevel) {
6659 if (ExitHandlerFunction != NULL) {
6660 ExitHandlerFunction ();
6661 }
6662 }
6663
6664 gExitRequired = TRUE;
6665 }
6666
6667 return Status;
6668}
6669
6670/**
6671 Create reminder to let user to choose save or discard the changed browser data.
6672 Caller can use it to actively check the changed browser data.
6673
6674 @retval BROWSER_NO_CHANGES No browser data is changed.
6675 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
6676 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
6677 @retval BROWSER_KEEP_CURRENT Browser keep current changes.
6678
6679**/
6680UINT32
6681EFIAPI
6682SaveReminder (
6683 VOID
6684 )
6685{
6686 LIST_ENTRY *Link;
6687 FORM_BROWSER_FORMSET *FormSet;
6688 BOOLEAN IsDataChanged;
6689 UINT32 DataSavedAction;
6690 UINT32 ConfirmRet;
6691
6692 DataSavedAction = BROWSER_NO_CHANGES;
6693 IsDataChanged = FALSE;
6694 Link = GetFirstNode (&gBrowserFormSetList);
6695 while (!IsNull (&gBrowserFormSetList, Link)) {
6696 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6697 Link = GetNextNode (&gBrowserFormSetList, Link);
6698 if (!ValidateFormSet (FormSet)) {
6699 continue;
6700 }
6701
6702 if (IsNvUpdateRequiredForFormSet (FormSet)) {
6703 IsDataChanged = TRUE;
6704 break;
6705 }
6706 }
6707
6708 //
6709 // No data is changed. No save is required.
6710 //
6711 if (!IsDataChanged) {
6712 return DataSavedAction;
6713 }
6714
6715 //
6716 // If data is changed, prompt user to save or discard it.
6717 //
6718 do {
6719 ConfirmRet = (UINT32)mFormDisplay->ConfirmDataChange ();
6720
6721 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
6722 SubmitForm (NULL, NULL, SystemLevel);
6723 DataSavedAction = BROWSER_SAVE_CHANGES;
6724 break;
6725 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
6726 DiscardForm (NULL, NULL, SystemLevel);
6727 DataSavedAction = BROWSER_DISCARD_CHANGES;
6728 break;
6729 } else if (ConfirmRet == BROWSER_ACTION_NONE) {
6730 DataSavedAction = BROWSER_KEEP_CURRENT;
6731 break;
6732 }
6733 } while (1);
6734
6735 return DataSavedAction;
6736}
6737
6738/**
6739 Check whether the Reset Required for the browser
6740
6741 @retval TRUE Browser required to reset after exit.
6742 @retval FALSE Browser not need to reset after exit.
6743
6744**/
6745BOOLEAN
6746EFIAPI
6747IsResetRequired (
6748 VOID
6749 )
6750{
6751 return gResetRequiredSystemLevel;
6752}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette