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