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