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