VirtualBox

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

Last change on this file since 69498 was 58466, checked in by vboxsync, 9 years ago

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

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

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