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