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