]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
92474cd282da8992c5c71f6048af0d3a1198c952
[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 FormSet. If the formset is not validate, remove it from the list.
2396
2397 @param FormSet The input FormSet 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 if (!Find) {
2453 CleanBrowserStorage(FormSet);
2454 RemoveEntryList (&FormSet->Link);
2455 DestroyFormSet (FormSet);
2456 }
2457
2458 return Find;
2459 }
2460 /**
2461 Check whether need to enable the reset flag in form level.
2462 Also clean all ValueChanged flag in question.
2463
2464 @param SetFlag Whether need to set the Reset Flag.
2465 @param FormSet FormSet data structure.
2466 @param Form Form data structure.
2467
2468 **/
2469 VOID
2470 UpdateFlagForForm (
2471 IN BOOLEAN SetFlag,
2472 IN FORM_BROWSER_FORMSET *FormSet,
2473 IN FORM_BROWSER_FORM *Form
2474 )
2475 {
2476 LIST_ENTRY *Link;
2477 FORM_BROWSER_STATEMENT *Question;
2478 BOOLEAN OldValue;
2479
2480 Link = GetFirstNode (&Form->StatementListHead);
2481 while (!IsNull (&Form->StatementListHead, Link)) {
2482 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2483 Link = GetNextNode (&Form->StatementListHead, Link);
2484
2485 if (!Question->ValueChanged) {
2486 continue;
2487 }
2488
2489 OldValue = Question->ValueChanged;
2490
2491 //
2492 // Compare the buffer and editbuffer data to see whether the data has been saved.
2493 //
2494 Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);
2495
2496 //
2497 // Only the changed data has been saved, then need to set the reset flag.
2498 //
2499 if (SetFlag && OldValue && !Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {
2500 gResetRequired = TRUE;
2501 }
2502 }
2503 }
2504
2505 /**
2506 Check whether need to enable the reset flag.
2507 Also clean ValueChanged flag for all statements.
2508
2509 Form level or formset level, only one.
2510
2511 @param SetFlag Whether need to set the Reset Flag.
2512 @param FormSet FormSet data structure.
2513 @param Form Form data structure.
2514
2515 **/
2516 VOID
2517 ValueChangeResetFlagUpdate (
2518 IN BOOLEAN SetFlag,
2519 IN FORM_BROWSER_FORMSET *FormSet,
2520 IN FORM_BROWSER_FORM *Form
2521 )
2522 {
2523 FORM_BROWSER_FORM *CurrentForm;
2524 LIST_ENTRY *Link;
2525
2526 if (Form != NULL) {
2527 UpdateFlagForForm(SetFlag, FormSet, Form);
2528 return;
2529 }
2530
2531 Link = GetFirstNode (&FormSet->FormListHead);
2532 while (!IsNull (&FormSet->FormListHead, Link)) {
2533 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
2534 Link = GetNextNode (&FormSet->FormListHead, Link);
2535
2536 UpdateFlagForForm(SetFlag, FormSet, CurrentForm);
2537 }
2538 }
2539
2540 /**
2541 Base on the return Progress string to find the form.
2542
2543 Base on the first return Offset/Width (Name) string to find the form
2544 which keep this string.
2545
2546 @param FormSet FormSet data structure.
2547 @param Storage Storage which has this Progress string.
2548 @param Progress The Progress string which has the first fail string.
2549 @param RetForm The return form for this progress string.
2550 @param RetQuestion The return question for the error progress string.
2551
2552 @retval TRUE Find the error form and statement for this error progress string.
2553 @retval FALSE Not find the error form.
2554
2555 **/
2556 BOOLEAN
2557 FindQuestionFromProgress (
2558 IN FORM_BROWSER_FORMSET *FormSet,
2559 IN BROWSER_STORAGE *Storage,
2560 IN EFI_STRING Progress,
2561 OUT FORM_BROWSER_FORM **RetForm,
2562 OUT FORM_BROWSER_STATEMENT **RetQuestion
2563 )
2564 {
2565 LIST_ENTRY *Link;
2566 LIST_ENTRY *LinkStorage;
2567 LIST_ENTRY *LinkStatement;
2568 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2569 FORM_BROWSER_FORM *Form;
2570 EFI_STRING EndStr;
2571 FORM_BROWSER_STATEMENT *Statement;
2572
2573 ASSERT ((*Progress == '&') || (*Progress == 'G'));
2574
2575 ConfigInfo = NULL;
2576 *RetForm = NULL;
2577 *RetQuestion = NULL;
2578
2579 //
2580 // Skip the first "&" or the ConfigHdr part.
2581 //
2582 if (*Progress == '&') {
2583 Progress++;
2584 } else {
2585 //
2586 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2587 //
2588 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2589 //
2590 // For Name/Value type, Skip the ConfigHdr part.
2591 //
2592 EndStr = StrStr (Progress, L"PATH=");
2593 while (*EndStr != '&') {
2594 EndStr++;
2595 }
2596
2597 *EndStr = '\0';
2598 } else {
2599 //
2600 // For Buffer type, Skip the ConfigHdr part.
2601 //
2602 EndStr = StrStr (Progress, L"&OFFSET=");
2603 *EndStr = '\0';
2604 }
2605
2606 Progress = EndStr + 1;
2607 }
2608
2609 //
2610 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2611 //
2612 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2613 //
2614 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
2615 // here, just keep the "Fred" string.
2616 //
2617 EndStr = StrStr (Progress, L"=");
2618 *EndStr = '\0';
2619 } else {
2620 //
2621 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
2622 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
2623 //
2624 EndStr = StrStr (Progress, L"&VALUE=");
2625 *EndStr = '\0';
2626 }
2627
2628 //
2629 // Search in the form list.
2630 //
2631 Link = GetFirstNode (&FormSet->FormListHead);
2632 while (!IsNull (&FormSet->FormListHead, Link)) {
2633 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2634 Link = GetNextNode (&FormSet->FormListHead, Link);
2635
2636 //
2637 // Search in the ConfigReqeust list in this form.
2638 //
2639 LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
2640 while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
2641 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
2642 LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
2643
2644 if (Storage != ConfigInfo->Storage) {
2645 continue;
2646 }
2647
2648 if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
2649 //
2650 // Find the OffsetWidth string in this form.
2651 //
2652 *RetForm = Form;
2653 break;
2654 }
2655 }
2656
2657 if (*RetForm != NULL) {
2658 LinkStatement = GetFirstNode (&Form->StatementListHead);
2659 while (!IsNull (&Form->StatementListHead, LinkStatement)) {
2660 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
2661 LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
2662
2663 if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {
2664 *RetQuestion = Statement;
2665 break;
2666 }
2667 }
2668 }
2669
2670 if (*RetForm != NULL) {
2671 break;
2672 }
2673 }
2674
2675 //
2676 // restore the OffsetWidth string to the original format.
2677 //
2678 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2679 *EndStr = '=';
2680 } else {
2681 *EndStr = '&';
2682 }
2683
2684 return (BOOLEAN) (*RetForm != NULL);
2685 }
2686
2687 /**
2688 Popup an save error info and get user input.
2689
2690 @param TitleId The form title id.
2691 @param HiiHandle The hii handle for this package.
2692
2693 @retval UINT32 The user select option for the save fail.
2694 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
2695 **/
2696 UINT32
2697 ConfirmSaveFail (
2698 IN EFI_STRING_ID TitleId,
2699 IN EFI_HII_HANDLE HiiHandle
2700 )
2701 {
2702 CHAR16 *FormTitle;
2703 CHAR16 *StringBuffer;
2704 UINT32 RetVal;
2705
2706 FormTitle = GetToken (TitleId, HiiHandle);
2707
2708 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
2709 ASSERT (StringBuffer != NULL);
2710
2711 UnicodeSPrint (
2712 StringBuffer,
2713 24 * sizeof (CHAR16) + StrSize (FormTitle),
2714 L"Submit Fail For Form: %s.",
2715 FormTitle
2716 );
2717
2718 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
2719
2720 FreePool (StringBuffer);
2721 FreePool (FormTitle);
2722
2723 return RetVal;
2724 }
2725
2726 /**
2727 Popup an NO_SUBMIT_IF error info and get user input.
2728
2729 @param TitleId The form title id.
2730 @param HiiHandle The hii handle for this package.
2731
2732 @retval UINT32 The user select option for the save fail.
2733 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
2734 **/
2735 UINT32
2736 ConfirmNoSubmitFail (
2737 IN EFI_STRING_ID TitleId,
2738 IN EFI_HII_HANDLE HiiHandle
2739 )
2740 {
2741 CHAR16 *FormTitle;
2742 CHAR16 *StringBuffer;
2743 UINT32 RetVal;
2744
2745 FormTitle = GetToken (TitleId, HiiHandle);
2746
2747 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
2748 ASSERT (StringBuffer != NULL);
2749
2750 UnicodeSPrint (
2751 StringBuffer,
2752 24 * sizeof (CHAR16) + StrSize (FormTitle),
2753 L"NO_SUBMIT_IF error For Form: %s.",
2754 FormTitle
2755 );
2756
2757 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
2758
2759 FreePool (StringBuffer);
2760 FreePool (FormTitle);
2761
2762 return RetVal;
2763 }
2764
2765 /**
2766 Discard data based on the input setting scope (Form, FormSet or System).
2767
2768 @param FormSet FormSet data structure.
2769 @param Form Form data structure.
2770 @param SettingScope Setting Scope for Discard action.
2771
2772 @retval EFI_SUCCESS The function completed successfully.
2773 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2774
2775 **/
2776 EFI_STATUS
2777 DiscardForm (
2778 IN FORM_BROWSER_FORMSET *FormSet,
2779 IN FORM_BROWSER_FORM *Form,
2780 IN BROWSER_SETTING_SCOPE SettingScope
2781 )
2782 {
2783 LIST_ENTRY *Link;
2784 FORMSET_STORAGE *Storage;
2785 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2786 FORM_BROWSER_FORMSET *LocalFormSet;
2787 FORM_BROWSER_FORMSET *OldFormSet;
2788
2789 //
2790 // Check the supported setting level.
2791 //
2792 if (SettingScope >= MaxLevel) {
2793 return EFI_UNSUPPORTED;
2794 }
2795
2796 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
2797 ConfigInfo = NULL;
2798 Link = GetFirstNode (&Form->ConfigRequestHead);
2799 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2800 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2801 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2802
2803 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2804 continue;
2805 }
2806
2807 //
2808 // Skip if there is no RequestElement
2809 //
2810 if (ConfigInfo->ElementCount == 0) {
2811 continue;
2812 }
2813
2814 //
2815 // Prepare <ConfigResp>
2816 //
2817 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
2818
2819 //
2820 // Call callback with Changed type to inform the driver.
2821 //
2822 SendDiscardInfoToDriver (FormSet, Form);
2823 }
2824
2825 ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
2826 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
2827
2828 //
2829 // Discard Buffer storage or Name/Value storage
2830 //
2831 Link = GetFirstNode (&FormSet->StorageListHead);
2832 while (!IsNull (&FormSet->StorageListHead, Link)) {
2833 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2834 Link = GetNextNode (&FormSet->StorageListHead, Link);
2835
2836 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2837 continue;
2838 }
2839
2840 //
2841 // Skip if there is no RequestElement
2842 //
2843 if (Storage->ElementCount == 0) {
2844 continue;
2845 }
2846
2847 SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
2848 }
2849
2850 Link = GetFirstNode (&FormSet->FormListHead);
2851 while (!IsNull (&FormSet->FormListHead, Link)) {
2852 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2853 Link = GetNextNode (&FormSet->FormListHead, Link);
2854
2855 //
2856 // Call callback with Changed type to inform the driver.
2857 //
2858 SendDiscardInfoToDriver (FormSet, Form);
2859 }
2860
2861 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
2862 } else if (SettingScope == SystemLevel) {
2863 //
2864 // System Level Discard.
2865 //
2866 OldFormSet = mSystemLevelFormSet;
2867
2868 //
2869 // Discard changed value for each FormSet in the maintain list.
2870 //
2871 Link = GetFirstNode (&gBrowserFormSetList);
2872 while (!IsNull (&gBrowserFormSetList, Link)) {
2873 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2874 Link = GetNextNode (&gBrowserFormSetList, Link);
2875 if (!ValidateFormSet(LocalFormSet)) {
2876 continue;
2877 }
2878
2879 mSystemLevelFormSet = LocalFormSet;
2880
2881 DiscardForm (LocalFormSet, NULL, FormSetLevel);
2882 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2883 //
2884 // Remove maintain backup list after discard except for the current using FormSet.
2885 //
2886 CleanBrowserStorage(LocalFormSet);
2887 RemoveEntryList (&LocalFormSet->Link);
2888 DestroyFormSet (LocalFormSet);
2889 }
2890 }
2891
2892 mSystemLevelFormSet = OldFormSet;
2893 }
2894
2895 return EFI_SUCCESS;
2896 }
2897
2898 /**
2899 Submit data for a form.
2900
2901 @param FormSet FormSet data structure.
2902 @param Form Form data structure.
2903
2904 @retval EFI_SUCCESS The function completed successfully.
2905 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2906
2907 **/
2908 EFI_STATUS
2909 SubmitForForm (
2910 IN FORM_BROWSER_FORMSET *FormSet,
2911 IN FORM_BROWSER_FORM *Form
2912 )
2913 {
2914 EFI_STATUS Status;
2915 LIST_ENTRY *Link;
2916 EFI_STRING ConfigResp;
2917 EFI_STRING Progress;
2918 BROWSER_STORAGE *Storage;
2919 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2920
2921 if (!IsNvUpdateRequiredForForm (Form)) {
2922 return EFI_SUCCESS;
2923 }
2924
2925 Status = NoSubmitCheck (FormSet, &Form, NULL);
2926 if (EFI_ERROR (Status)) {
2927 return Status;
2928 }
2929
2930 Link = GetFirstNode (&Form->ConfigRequestHead);
2931 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2932 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2933 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2934
2935 Storage = ConfigInfo->Storage;
2936 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2937 continue;
2938 }
2939
2940 //
2941 // Skip if there is no RequestElement
2942 //
2943 if (ConfigInfo->ElementCount == 0) {
2944 continue;
2945 }
2946
2947 //
2948 // 1. Prepare <ConfigResp>
2949 //
2950 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
2951 if (EFI_ERROR (Status)) {
2952 return Status;
2953 }
2954
2955 //
2956 // 2. Set value to hii config routine protocol.
2957 //
2958 Status = mHiiConfigRouting->RouteConfig (
2959 mHiiConfigRouting,
2960 ConfigResp,
2961 &Progress
2962 );
2963 FreePool (ConfigResp);
2964
2965 if (EFI_ERROR (Status)) {
2966 InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
2967 continue;
2968 }
2969
2970 //
2971 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
2972 //
2973 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
2974 }
2975
2976 //
2977 // 4. Process the save failed storage.
2978 //
2979 if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
2980 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
2981 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
2982 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
2983 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
2984 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
2985
2986 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
2987
2988 Status = EFI_SUCCESS;
2989 }
2990 } else {
2991 Status = EFI_UNSUPPORTED;
2992 }
2993
2994 //
2995 // Free Form save fail list.
2996 //
2997 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
2998 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
2999 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
3000 RemoveEntryList (&ConfigInfo->SaveFailLink);
3001 }
3002 }
3003
3004 //
3005 // 5. Update the NV flag.
3006 //
3007 ValueChangeResetFlagUpdate(TRUE, FormSet, Form);
3008
3009 return Status;
3010 }
3011
3012 /**
3013 Submit data for a formset.
3014
3015 @param FormSet FormSet data structure.
3016 @param SkipProcessFail Whether skip to process the save failed storage.
3017 If submit formset is called when do system level save,
3018 set this value to true and process the failed formset
3019 together.
3020 if submit formset is called when do formset level save,
3021 set the value to false and process the failed storage
3022 right after process all storages for this formset.
3023
3024 @retval EFI_SUCCESS The function completed successfully.
3025 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3026
3027 **/
3028 EFI_STATUS
3029 SubmitForFormSet (
3030 IN FORM_BROWSER_FORMSET *FormSet,
3031 IN BOOLEAN SkipProcessFail
3032 )
3033 {
3034 EFI_STATUS Status;
3035 LIST_ENTRY *Link;
3036 EFI_STRING ConfigResp;
3037 EFI_STRING Progress;
3038 BROWSER_STORAGE *Storage;
3039 FORMSET_STORAGE *FormSetStorage;
3040 FORM_BROWSER_FORM *Form;
3041 BOOLEAN HasInserted;
3042 FORM_BROWSER_STATEMENT *Question;
3043
3044 HasInserted = FALSE;
3045
3046 if (!IsNvUpdateRequiredForFormSet (FormSet)) {
3047 return EFI_SUCCESS;
3048 }
3049
3050 Form = NULL;
3051 Status = NoSubmitCheck (FormSet, &Form, &Question);
3052 if (EFI_ERROR (Status)) {
3053 if (SkipProcessFail) {
3054 //
3055 // Process NO_SUBMIT check first, so insert it at head.
3056 //
3057 FormSet->SaveFailForm = Form;
3058 FormSet->SaveFailStatement = Question;
3059 InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
3060 }
3061
3062 return Status;
3063 }
3064
3065 Form = NULL;
3066 Question = NULL;
3067 //
3068 // Submit Buffer storage or Name/Value storage
3069 //
3070 Link = GetFirstNode (&FormSet->StorageListHead);
3071 while (!IsNull (&FormSet->StorageListHead, Link)) {
3072 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
3073 Storage = FormSetStorage->BrowserStorage;
3074 Link = GetNextNode (&FormSet->StorageListHead, Link);
3075
3076 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3077 continue;
3078 }
3079
3080 //
3081 // Skip if there is no RequestElement
3082 //
3083 if (FormSetStorage->ElementCount == 0) {
3084 continue;
3085 }
3086
3087 //
3088 // 1. Prepare <ConfigResp>
3089 //
3090 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
3091 if (EFI_ERROR (Status)) {
3092 return Status;
3093 }
3094
3095 //
3096 // 2. Send <ConfigResp> to Routine config Protocol.
3097 //
3098 Status = mHiiConfigRouting->RouteConfig (
3099 mHiiConfigRouting,
3100 ConfigResp,
3101 &Progress
3102 );
3103 if (EFI_ERROR (Status)) {
3104 InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
3105 if (!HasInserted) {
3106 //
3107 // Call submit formset for system level, save the formset info
3108 // and process later.
3109 //
3110 FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);
3111 ASSERT (Form != NULL && Question != NULL);
3112 FormSet->SaveFailForm = Form;
3113 FormSet->SaveFailStatement = Question;
3114 if (SkipProcessFail) {
3115 InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
3116 }
3117 HasInserted = TRUE;
3118 }
3119
3120 FreePool (ConfigResp);
3121 continue;
3122 }
3123
3124 FreePool (ConfigResp);
3125 //
3126 // 3. Config success, update storage shadow Buffer
3127 //
3128 SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
3129 }
3130
3131 //
3132 // 4. Has save fail storage need to handle.
3133 //
3134 if (Form != NULL) {
3135 if (!SkipProcessFail) {
3136 //
3137 // If not in system level, just handl the save failed storage here.
3138 //
3139 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
3140 Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
3141 while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
3142 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
3143 Storage = FormSetStorage->BrowserStorage;
3144 Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
3145
3146 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3147
3148 Status = EFI_SUCCESS;
3149 }
3150 } else {
3151 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
3152
3153 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
3154 gCurrentSelection->Handle = FormSet->HiiHandle;
3155 CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
3156 gCurrentSelection->FormId = Form->FormId;
3157 gCurrentSelection->QuestionId = Question->QuestionId;
3158
3159 Status = EFI_UNSUPPORTED;
3160 }
3161
3162 //
3163 // Free FormSet save fail list.
3164 //
3165 while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
3166 Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
3167 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
3168 RemoveEntryList (&FormSetStorage->SaveFailLink);
3169 }
3170 } else {
3171 //
3172 // If in system level, just return error and handle the failed formset later.
3173 //
3174 Status = EFI_UNSUPPORTED;
3175 }
3176 }
3177
3178 //
3179 // 5. Update the NV flag.
3180 //
3181 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
3182
3183 return Status;
3184 }
3185
3186 /**
3187 Submit data for all formsets.
3188
3189 @retval EFI_SUCCESS The function completed successfully.
3190 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3191
3192 **/
3193 EFI_STATUS
3194 SubmitForSystem (
3195 VOID
3196 )
3197 {
3198 EFI_STATUS Status;
3199 LIST_ENTRY *Link;
3200 LIST_ENTRY *StorageLink;
3201 BROWSER_STORAGE *Storage;
3202 FORMSET_STORAGE *FormSetStorage;
3203 FORM_BROWSER_FORM *Form;
3204 FORM_BROWSER_FORMSET *LocalFormSet;
3205 UINT32 UserSelection;
3206 FORM_BROWSER_STATEMENT *Question;
3207
3208 mSystemSubmit = TRUE;
3209 Link = GetFirstNode (&gBrowserFormSetList);
3210 while (!IsNull (&gBrowserFormSetList, Link)) {
3211 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3212 Link = GetNextNode (&gBrowserFormSetList, Link);
3213 if (!ValidateFormSet(LocalFormSet)) {
3214 continue;
3215 }
3216
3217 Status = SubmitForFormSet (LocalFormSet, TRUE);
3218 if (EFI_ERROR (Status)) {
3219 continue;
3220 }
3221
3222 //
3223 // Remove maintain backup list after save except for the current using FormSet.
3224 //
3225 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3226 CleanBrowserStorage(LocalFormSet);
3227 RemoveEntryList (&LocalFormSet->Link);
3228 DestroyFormSet (LocalFormSet);
3229 }
3230 }
3231 mSystemSubmit = FALSE;
3232
3233 Status = EFI_SUCCESS;
3234
3235 //
3236 // Process the save failed formsets.
3237 //
3238 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3239 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
3240 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
3241 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
3242
3243 if (!ValidateFormSet(LocalFormSet)) {
3244 continue;
3245 }
3246
3247 Form = LocalFormSet->SaveFailForm;
3248 Question= LocalFormSet->SaveFailStatement;
3249
3250 //
3251 // Confirm with user, get user input.
3252 //
3253 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3254 //
3255 // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
3256 //
3257 UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
3258 } else {
3259 UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
3260 }
3261
3262 if (UserSelection == BROWSER_ACTION_DISCARD) {
3263 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3264 StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
3265 while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
3266 FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
3267 Storage = FormSetStorage->BrowserStorage;
3268 StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
3269
3270 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3271 }
3272 } else {
3273 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
3274 while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
3275 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
3276 Storage = FormSetStorage->BrowserStorage;
3277 StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
3278
3279 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3280 }
3281 }
3282
3283 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3284 CleanBrowserStorage(LocalFormSet);
3285 RemoveEntryList (&LocalFormSet->Link);
3286 RemoveEntryList (&LocalFormSet->SaveFailLink);
3287 DestroyFormSet (LocalFormSet);
3288 } else {
3289 ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);
3290 }
3291 } else {
3292 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3293 NoSubmitCheck (LocalFormSet, &Form, &Question);
3294 }
3295
3296 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
3297
3298 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
3299 gCurrentSelection->Handle = LocalFormSet->HiiHandle;
3300 CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
3301 gCurrentSelection->FormId = Form->FormId;
3302 gCurrentSelection->QuestionId = Question->QuestionId;
3303
3304 Status = EFI_UNSUPPORTED;
3305 break;
3306 }
3307 }
3308
3309 //
3310 // Clean the list which will not process.
3311 //
3312 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3313 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3314 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
3315 RemoveEntryList (&LocalFormSet->SaveFailLink);
3316
3317 while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3318 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
3319 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
3320 RemoveEntryList (&FormSetStorage->SaveFailLink);
3321 }
3322 }
3323
3324 return Status;
3325 }
3326
3327 /**
3328 Submit data based on the input Setting level (Form, FormSet or System).
3329
3330 @param FormSet FormSet data structure.
3331 @param Form Form data structure.
3332 @param SettingScope Setting Scope for Submit action.
3333
3334 @retval EFI_SUCCESS The function completed successfully.
3335 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3336
3337 **/
3338 EFI_STATUS
3339 SubmitForm (
3340 IN FORM_BROWSER_FORMSET *FormSet,
3341 IN FORM_BROWSER_FORM *Form,
3342 IN BROWSER_SETTING_SCOPE SettingScope
3343 )
3344 {
3345 EFI_STATUS Status;
3346
3347 switch (SettingScope) {
3348 case FormLevel:
3349 Status = SubmitForForm(FormSet, Form);
3350 break;
3351
3352 case FormSetLevel:
3353 Status = SubmitForFormSet (FormSet, FALSE);
3354 break;
3355
3356 case SystemLevel:
3357 Status = SubmitForSystem ();
3358 break;
3359
3360 default:
3361 Status = EFI_UNSUPPORTED;
3362 break;
3363 }
3364
3365 return Status;
3366 }
3367
3368 /**
3369 Get Question default value from AltCfg string.
3370
3371 @param FormSet The form set.
3372 @param Question The question.
3373 @param DefaultId The default Id.
3374
3375 @retval EFI_SUCCESS Question is reset to default value.
3376
3377 **/
3378 EFI_STATUS
3379 GetDefaultValueFromAltCfg (
3380 IN FORM_BROWSER_FORMSET *FormSet,
3381 IN OUT FORM_BROWSER_STATEMENT *Question,
3382 IN UINT16 DefaultId
3383 )
3384 {
3385 BOOLEAN IsBufferStorage;
3386 BOOLEAN IsString;
3387 UINTN Length;
3388 BROWSER_STORAGE *Storage;
3389 CHAR16 *ConfigRequest;
3390 CHAR16 *Progress;
3391 CHAR16 *Result;
3392 CHAR16 *ConfigResp;
3393 CHAR16 *Value;
3394 CHAR16 *StringPtr;
3395 UINTN LengthStr;
3396 UINT8 *Dst;
3397 CHAR16 TemStr[5];
3398 UINTN Index;
3399 UINT8 DigitUint8;
3400 EFI_STATUS Status;
3401
3402 Status = EFI_NOT_FOUND;
3403 Length = 0;
3404 Dst = NULL;
3405 ConfigRequest = NULL;
3406 Result = NULL;
3407 ConfigResp = NULL;
3408 Value = NULL;
3409 Storage = Question->Storage;
3410
3411 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
3412 return Status;
3413 }
3414
3415 //
3416 // Question Value is provided by Buffer Storage or NameValue Storage
3417 //
3418 if (Question->BufferValue != NULL) {
3419 //
3420 // This Question is password or orderedlist
3421 //
3422 Dst = Question->BufferValue;
3423 } else {
3424 //
3425 // Other type of Questions
3426 //
3427 Dst = (UINT8 *) &Question->HiiValue.Value;
3428 }
3429
3430 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
3431 IsBufferStorage = TRUE;
3432 } else {
3433 IsBufferStorage = FALSE;
3434 }
3435 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
3436
3437 //
3438 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
3439 // <ConfigHdr> + "&" + <VariableName>
3440 //
3441 if (IsBufferStorage) {
3442 Length = StrLen (Storage->ConfigHdr);
3443 Length += StrLen (Question->BlockName);
3444 } else {
3445 Length = StrLen (Storage->ConfigHdr);
3446 Length += StrLen (Question->VariableName) + 1;
3447 }
3448 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
3449 ASSERT (ConfigRequest != NULL);
3450
3451 StrCpy (ConfigRequest, Storage->ConfigHdr);
3452 if (IsBufferStorage) {
3453 StrCat (ConfigRequest, Question->BlockName);
3454 } else {
3455 StrCat (ConfigRequest, L"&");
3456 StrCat (ConfigRequest, Question->VariableName);
3457 }
3458
3459 Status = mHiiConfigRouting->ExtractConfig (
3460 mHiiConfigRouting,
3461 ConfigRequest,
3462 &Progress,
3463 &Result
3464 );
3465 if (EFI_ERROR (Status)) {
3466 goto Done;
3467 }
3468
3469 //
3470 // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
3471 // Get the default configuration string according to the default ID.
3472 //
3473 Status = mHiiConfigRouting->GetAltConfig (
3474 mHiiConfigRouting,
3475 Result,
3476 &Storage->Guid,
3477 Storage->Name,
3478 NULL,
3479 &DefaultId, // it can be NULL to get the current setting.
3480 &ConfigResp
3481 );
3482
3483 //
3484 // The required setting can't be found. So, it is not required to be validated and set.
3485 //
3486 if (EFI_ERROR (Status)) {
3487 goto Done;
3488 }
3489
3490 if (ConfigResp == NULL) {
3491 Status = EFI_NOT_FOUND;
3492 goto Done;
3493 }
3494
3495 //
3496 // Skip <ConfigRequest>
3497 //
3498 if (IsBufferStorage) {
3499 Value = StrStr (ConfigResp, L"&VALUE");
3500 ASSERT (Value != NULL);
3501 //
3502 // Skip "&VALUE"
3503 //
3504 Value = Value + 6;
3505 } else {
3506 Value = StrStr (ConfigResp, Question->VariableName);
3507 ASSERT (Value != NULL);
3508
3509 Value = Value + StrLen (Question->VariableName);
3510 }
3511 if (*Value != '=') {
3512 Status = EFI_NOT_FOUND;
3513 goto Done;
3514 }
3515 //
3516 // Skip '=', point to value
3517 //
3518 Value = Value + 1;
3519
3520 //
3521 // Suppress <AltResp> if any
3522 //
3523 StringPtr = Value;
3524 while (*StringPtr != L'\0' && *StringPtr != L'&') {
3525 StringPtr++;
3526 }
3527 *StringPtr = L'\0';
3528
3529 LengthStr = StrLen (Value);
3530 if (!IsBufferStorage && IsString) {
3531 StringPtr = (CHAR16 *) Dst;
3532 ZeroMem (TemStr, sizeof (TemStr));
3533 for (Index = 0; Index < LengthStr; Index += 4) {
3534 StrnCpy (TemStr, Value + Index, 4);
3535 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
3536 }
3537 //
3538 // Add tailing L'\0' character
3539 //
3540 StringPtr[Index/4] = L'\0';
3541 } else {
3542 ZeroMem (TemStr, sizeof (TemStr));
3543 for (Index = 0; Index < LengthStr; Index ++) {
3544 TemStr[0] = Value[LengthStr - Index - 1];
3545 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
3546 if ((Index & 1) == 0) {
3547 Dst [Index/2] = DigitUint8;
3548 } else {
3549 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
3550 }
3551 }
3552 }
3553
3554 Done:
3555 if (ConfigRequest != NULL){
3556 FreePool (ConfigRequest);
3557 }
3558
3559 if (ConfigResp != NULL) {
3560 FreePool (ConfigResp);
3561 }
3562
3563 if (Result != NULL) {
3564 FreePool (Result);
3565 }
3566
3567 return Status;
3568 }
3569
3570 /**
3571 Get default Id value used for browser.
3572
3573 @param DefaultId The default id value used by hii.
3574
3575 @retval Browser used default value.
3576
3577 **/
3578 INTN
3579 GetDefaultIdForCallBack (
3580 UINTN DefaultId
3581 )
3582 {
3583 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
3584 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
3585 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3586 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
3587 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
3588 return EFI_BROWSER_ACTION_DEFAULT_SAFE;
3589 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
3590 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
3591 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
3592 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
3593 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
3594 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
3595 } else {
3596 return -1;
3597 }
3598 }
3599
3600
3601
3602 /**
3603 Return data element in an Array by its Index.
3604
3605 @param Array The data array.
3606 @param Type Type of the data in this array.
3607 @param Index Zero based index for data in this array.
3608
3609 @retval Value The data to be returned
3610
3611 **/
3612 UINT64
3613 GetArrayData (
3614 IN VOID *Array,
3615 IN UINT8 Type,
3616 IN UINTN Index
3617 )
3618 {
3619 UINT64 Data;
3620
3621 ASSERT (Array != NULL);
3622
3623 Data = 0;
3624 switch (Type) {
3625 case EFI_IFR_TYPE_NUM_SIZE_8:
3626 Data = (UINT64) *(((UINT8 *) Array) + Index);
3627 break;
3628
3629 case EFI_IFR_TYPE_NUM_SIZE_16:
3630 Data = (UINT64) *(((UINT16 *) Array) + Index);
3631 break;
3632
3633 case EFI_IFR_TYPE_NUM_SIZE_32:
3634 Data = (UINT64) *(((UINT32 *) Array) + Index);
3635 break;
3636
3637 case EFI_IFR_TYPE_NUM_SIZE_64:
3638 Data = (UINT64) *(((UINT64 *) Array) + Index);
3639 break;
3640
3641 default:
3642 break;
3643 }
3644
3645 return Data;
3646 }
3647
3648
3649 /**
3650 Set value of a data element in an Array by its Index.
3651
3652 @param Array The data array.
3653 @param Type Type of the data in this array.
3654 @param Index Zero based index for data in this array.
3655 @param Value The value to be set.
3656
3657 **/
3658 VOID
3659 SetArrayData (
3660 IN VOID *Array,
3661 IN UINT8 Type,
3662 IN UINTN Index,
3663 IN UINT64 Value
3664 )
3665 {
3666
3667 ASSERT (Array != NULL);
3668
3669 switch (Type) {
3670 case EFI_IFR_TYPE_NUM_SIZE_8:
3671 *(((UINT8 *) Array) + Index) = (UINT8) Value;
3672 break;
3673
3674 case EFI_IFR_TYPE_NUM_SIZE_16:
3675 *(((UINT16 *) Array) + Index) = (UINT16) Value;
3676 break;
3677
3678 case EFI_IFR_TYPE_NUM_SIZE_32:
3679 *(((UINT32 *) Array) + Index) = (UINT32) Value;
3680 break;
3681
3682 case EFI_IFR_TYPE_NUM_SIZE_64:
3683 *(((UINT64 *) Array) + Index) = (UINT64) Value;
3684 break;
3685
3686 default:
3687 break;
3688 }
3689 }
3690
3691 /**
3692 Search an Option of a Question by its value.
3693
3694 @param Question The Question
3695 @param OptionValue Value for Option to be searched.
3696
3697 @retval Pointer Pointer to the found Option.
3698 @retval NULL Option not found.
3699
3700 **/
3701 QUESTION_OPTION *
3702 ValueToOption (
3703 IN FORM_BROWSER_STATEMENT *Question,
3704 IN EFI_HII_VALUE *OptionValue
3705 )
3706 {
3707 LIST_ENTRY *Link;
3708 QUESTION_OPTION *Option;
3709 INTN Result;
3710
3711 Link = GetFirstNode (&Question->OptionListHead);
3712 while (!IsNull (&Question->OptionListHead, Link)) {
3713 Option = QUESTION_OPTION_FROM_LINK (Link);
3714
3715 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
3716 //
3717 // Check the suppressif condition, only a valid option can be return.
3718 //
3719 if ((Option->SuppressExpression == NULL) ||
3720 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
3721 return Option;
3722 }
3723 }
3724
3725 Link = GetNextNode (&Question->OptionListHead, Link);
3726 }
3727
3728 return NULL;
3729 }
3730
3731
3732 /**
3733 Reset Question to its default value.
3734
3735 @param FormSet The form set.
3736 @param Form The form.
3737 @param Question The question.
3738 @param DefaultId The Class of the default.
3739
3740 @retval EFI_SUCCESS Question is reset to default value.
3741
3742 **/
3743 EFI_STATUS
3744 GetQuestionDefault (
3745 IN FORM_BROWSER_FORMSET *FormSet,
3746 IN FORM_BROWSER_FORM *Form,
3747 IN FORM_BROWSER_STATEMENT *Question,
3748 IN UINT16 DefaultId
3749 )
3750 {
3751 EFI_STATUS Status;
3752 LIST_ENTRY *Link;
3753 QUESTION_DEFAULT *Default;
3754 QUESTION_OPTION *Option;
3755 EFI_HII_VALUE *HiiValue;
3756 UINT8 Index;
3757 EFI_STRING StrValue;
3758 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
3759 EFI_BROWSER_ACTION_REQUEST ActionRequest;
3760 INTN Action;
3761 CHAR16 *NewString;
3762
3763 Status = EFI_NOT_FOUND;
3764 StrValue = NULL;
3765
3766 //
3767 // Statement don't have storage, skip them
3768 //
3769 if (Question->QuestionId == 0) {
3770 return Status;
3771 }
3772
3773 //
3774 // There are Five ways to specify default value for a Question:
3775 // 1, use call back function (highest priority)
3776 // 2, use ExtractConfig function
3777 // 3, use nested EFI_IFR_DEFAULT
3778 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
3779 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
3780 //
3781 HiiValue = &Question->HiiValue;
3782
3783 //
3784 // Get Question defaut value from call back function.
3785 //
3786 ConfigAccess = FormSet->ConfigAccess;
3787 Action = GetDefaultIdForCallBack (DefaultId);
3788 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
3789 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
3790 Status = ConfigAccess->Callback (
3791 ConfigAccess,
3792 Action,
3793 Question->QuestionId,
3794 HiiValue->Type,
3795 &HiiValue->Value,
3796 &ActionRequest
3797 );
3798 if (!EFI_ERROR (Status)) {
3799 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3800 NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
3801 ASSERT (NewString != NULL);
3802
3803 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
3804 if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
3805 CopyMem (Question->BufferValue, NewString, StrSize (NewString));
3806 } else {
3807 CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
3808 }
3809
3810 FreePool (NewString);
3811 }
3812 return Status;
3813 }
3814 }
3815
3816 //
3817 // Get default value from altcfg string.
3818 //
3819 if (ConfigAccess != NULL) {
3820 Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);
3821 if (!EFI_ERROR (Status)) {
3822 return Status;
3823 }
3824 }
3825
3826 //
3827 // EFI_IFR_DEFAULT has highest priority
3828 //
3829 if (!IsListEmpty (&Question->DefaultListHead)) {
3830 Link = GetFirstNode (&Question->DefaultListHead);
3831 while (!IsNull (&Question->DefaultListHead, Link)) {
3832 Default = QUESTION_DEFAULT_FROM_LINK (Link);
3833
3834 if (Default->DefaultId == DefaultId) {
3835 if (Default->ValueExpression != NULL) {
3836 //
3837 // Default is provided by an Expression, evaluate it
3838 //
3839 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
3840 if (EFI_ERROR (Status)) {
3841 return Status;
3842 }
3843
3844 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
3845 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
3846 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
3847 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
3848 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
3849 } else {
3850 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
3851 Question->HiiValue.BufferLen = Question->StorageWidth;
3852 }
3853 FreePool (Default->ValueExpression->Result.Buffer);
3854 }
3855 HiiValue->Type = Default->ValueExpression->Result.Type;
3856 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
3857 } else {
3858 //
3859 // Default value is embedded in EFI_IFR_DEFAULT
3860 //
3861 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
3862 }
3863
3864 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3865 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
3866 if (StrValue == NULL) {
3867 return EFI_NOT_FOUND;
3868 }
3869 if (Question->StorageWidth > StrSize (StrValue)) {
3870 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
3871 } else {
3872 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
3873 }
3874 }
3875
3876 return EFI_SUCCESS;
3877 }
3878
3879 Link = GetNextNode (&Question->DefaultListHead, Link);
3880 }
3881 }
3882
3883 //
3884 // EFI_ONE_OF_OPTION
3885 //
3886 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
3887 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3888 //
3889 // OneOfOption could only provide Standard and Manufacturing default
3890 //
3891 Link = GetFirstNode (&Question->OptionListHead);
3892 while (!IsNull (&Question->OptionListHead, Link)) {
3893 Option = QUESTION_OPTION_FROM_LINK (Link);
3894 Link = GetNextNode (&Question->OptionListHead, Link);
3895
3896 if ((Option->SuppressExpression != NULL) &&
3897 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3898 continue;
3899 }
3900
3901 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
3902 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
3903 ) {
3904 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3905
3906 return EFI_SUCCESS;
3907 }
3908 }
3909 }
3910 }
3911
3912 //
3913 // EFI_IFR_CHECKBOX - lowest priority
3914 //
3915 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
3916 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3917 //
3918 // Checkbox could only provide Standard and Manufacturing default
3919 //
3920 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
3921 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
3922 ) {
3923 HiiValue->Value.b = TRUE;
3924 } else {
3925 HiiValue->Value.b = FALSE;
3926 }
3927
3928 return EFI_SUCCESS;
3929 }
3930 }
3931
3932 //
3933 // For Questions without default
3934 //
3935 Status = EFI_NOT_FOUND;
3936 switch (Question->Operand) {
3937 case EFI_IFR_NUMERIC_OP:
3938 //
3939 // Take minimum value as numeric default value
3940 //
3941 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
3942 HiiValue->Value.u64 = Question->Minimum;
3943 Status = EFI_SUCCESS;
3944 }
3945 break;
3946
3947 case EFI_IFR_ONE_OF_OP:
3948 //
3949 // Take first oneof option as oneof's default value
3950 //
3951 if (ValueToOption (Question, HiiValue) == NULL) {
3952 Link = GetFirstNode (&Question->OptionListHead);
3953 while (!IsNull (&Question->OptionListHead, Link)) {
3954 Option = QUESTION_OPTION_FROM_LINK (Link);
3955 Link = GetNextNode (&Question->OptionListHead, Link);
3956
3957 if ((Option->SuppressExpression != NULL) &&
3958 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3959 continue;
3960 }
3961
3962 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3963 Status = EFI_SUCCESS;
3964 break;
3965 }
3966 }
3967 break;
3968
3969 case EFI_IFR_ORDERED_LIST_OP:
3970 //
3971 // Take option sequence in IFR as ordered list's default value
3972 //
3973 Index = 0;
3974 Link = GetFirstNode (&Question->OptionListHead);
3975 while (!IsNull (&Question->OptionListHead, Link)) {
3976 Status = EFI_SUCCESS;
3977 Option = QUESTION_OPTION_FROM_LINK (Link);
3978 Link = GetNextNode (&Question->OptionListHead, Link);
3979
3980 if ((Option->SuppressExpression != NULL) &&
3981 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3982 continue;
3983 }
3984
3985 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
3986
3987 Index++;
3988 if (Index >= Question->MaxContainers) {
3989 break;
3990 }
3991 }
3992 break;
3993
3994 default:
3995 break;
3996 }
3997
3998 return Status;
3999 }
4000
4001
4002 /**
4003 Reset Questions to their initial value or default value in a Form, Formset or System.
4004
4005 GetDefaultValueScope parameter decides which questions will reset
4006 to its default value.
4007
4008 @param FormSet FormSet data structure.
4009 @param Form Form data structure.
4010 @param DefaultId The Class of the default.
4011 @param SettingScope Setting Scope for Default action.
4012 @param GetDefaultValueScope Get default value scope.
4013 @param Storage Get default value only for this storage.
4014 @param RetrieveValueFirst Whether call the retrieve call back to
4015 get the initial value before get default
4016 value.
4017
4018 @retval EFI_SUCCESS The function completed successfully.
4019 @retval EFI_UNSUPPORTED Unsupport SettingScope.
4020
4021 **/
4022 EFI_STATUS
4023 ExtractDefault (
4024 IN FORM_BROWSER_FORMSET *FormSet,
4025 IN FORM_BROWSER_FORM *Form,
4026 IN UINT16 DefaultId,
4027 IN BROWSER_SETTING_SCOPE SettingScope,
4028 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
4029 IN BROWSER_STORAGE *Storage OPTIONAL,
4030 IN BOOLEAN RetrieveValueFirst
4031 )
4032 {
4033 EFI_STATUS Status;
4034 LIST_ENTRY *FormLink;
4035 LIST_ENTRY *Link;
4036 FORM_BROWSER_STATEMENT *Question;
4037 FORM_BROWSER_FORMSET *LocalFormSet;
4038 FORM_BROWSER_FORMSET *OldFormSet;
4039
4040 Status = EFI_SUCCESS;
4041
4042 //
4043 // Check the supported setting level.
4044 //
4045 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
4046 return EFI_UNSUPPORTED;
4047 }
4048
4049 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
4050 return EFI_UNSUPPORTED;
4051 }
4052
4053 if (SettingScope == FormLevel) {
4054 //
4055 // Extract Form default
4056 //
4057 Link = GetFirstNode (&Form->StatementListHead);
4058 while (!IsNull (&Form->StatementListHead, Link)) {
4059 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
4060 Link = GetNextNode (&Form->StatementListHead, Link);
4061
4062 //
4063 // If get default value only for this storage, check the storage first.
4064 //
4065 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
4066 continue;
4067 }
4068
4069 //
4070 // If get default value only for no storage question, just skip the question which has storage.
4071 //
4072 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
4073 continue;
4074 }
4075
4076 //
4077 // If Question is disabled, don't reset it to default
4078 //
4079 if (Question->Expression != NULL) {
4080 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
4081 continue;
4082 }
4083 }
4084
4085 if (RetrieveValueFirst) {
4086 //
4087 // Call the Retrieve call back to get the initial question value.
4088 //
4089 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
4090 }
4091
4092 //
4093 // If not request to get the initial value or get initial value fail, then get default value.
4094 //
4095 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
4096 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
4097 if (EFI_ERROR (Status)) {
4098 continue;
4099 }
4100 }
4101
4102 //
4103 // Synchronize Buffer storage's Edit buffer
4104 //
4105 if ((Question->Storage != NULL) &&
4106 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
4107 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4108 }
4109 }
4110 } else if (SettingScope == FormSetLevel) {
4111 FormLink = GetFirstNode (&FormSet->FormListHead);
4112 while (!IsNull (&FormSet->FormListHead, FormLink)) {
4113 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
4114 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
4115 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
4116 }
4117 } else if (SettingScope == SystemLevel) {
4118 //
4119 // Preload all Hii formset.
4120 //
4121 LoadAllHiiFormset();
4122
4123 OldFormSet = mSystemLevelFormSet;
4124
4125 //
4126 // Set Default Value for each FormSet in the maintain list.
4127 //
4128 Link = GetFirstNode (&gBrowserFormSetList);
4129 while (!IsNull (&gBrowserFormSetList, Link)) {
4130 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4131 Link = GetNextNode (&gBrowserFormSetList, Link);
4132 if (!ValidateFormSet(LocalFormSet)) {
4133 continue;
4134 }
4135
4136 mSystemLevelFormSet = LocalFormSet;
4137
4138 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
4139 }
4140
4141 mSystemLevelFormSet = OldFormSet;
4142 }
4143
4144 return EFI_SUCCESS;
4145 }
4146
4147
4148 /**
4149 Validate whether this question's value has changed.
4150
4151 @param FormSet FormSet data structure.
4152 @param Form Form data structure.
4153 @param Question Question to be initialized.
4154 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
4155
4156 @retval TRUE Question's value has changed.
4157 @retval FALSE Question's value has not changed
4158
4159 **/
4160 BOOLEAN
4161 IsQuestionValueChanged (
4162 IN FORM_BROWSER_FORMSET *FormSet,
4163 IN FORM_BROWSER_FORM *Form,
4164 IN OUT FORM_BROWSER_STATEMENT *Question,
4165 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
4166 )
4167 {
4168 EFI_HII_VALUE BackUpValue;
4169 CHAR8 *BackUpBuffer;
4170 EFI_HII_VALUE BackUpValue2;
4171 CHAR8 *BackUpBuffer2;
4172 EFI_STATUS Status;
4173 BOOLEAN ValueChanged;
4174 UINTN BufferWidth;
4175
4176 //
4177 // For quetion without storage, always mark it as data not changed.
4178 //
4179 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
4180 return FALSE;
4181 }
4182
4183 BackUpBuffer = NULL;
4184 BackUpBuffer2 = NULL;
4185 ValueChanged = FALSE;
4186
4187 switch (Question->Operand) {
4188 case EFI_IFR_ORDERED_LIST_OP:
4189 BufferWidth = Question->StorageWidth;
4190 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
4191 ASSERT (BackUpBuffer != NULL);
4192 break;
4193
4194 case EFI_IFR_STRING_OP:
4195 case EFI_IFR_PASSWORD_OP:
4196 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
4197 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
4198 ASSERT (BackUpBuffer != NULL);
4199 break;
4200
4201 default:
4202 BufferWidth = 0;
4203 break;
4204 }
4205 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
4206
4207 if (GetValueFrom == GetSetValueWithBothBuffer) {
4208 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4209 ASSERT_EFI_ERROR(Status);
4210
4211 switch (Question->Operand) {
4212 case EFI_IFR_ORDERED_LIST_OP:
4213 BufferWidth = Question->StorageWidth;
4214 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
4215 ASSERT (BackUpBuffer2 != NULL);
4216 break;
4217
4218 case EFI_IFR_STRING_OP:
4219 case EFI_IFR_PASSWORD_OP:
4220 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
4221 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
4222 ASSERT (BackUpBuffer2 != NULL);
4223 break;
4224
4225 default:
4226 BufferWidth = 0;
4227 break;
4228 }
4229 CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
4230
4231 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
4232 ASSERT_EFI_ERROR(Status);
4233
4234 if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
4235 CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {
4236 ValueChanged = TRUE;
4237 }
4238 } else {
4239 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
4240 ASSERT_EFI_ERROR(Status);
4241
4242 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
4243 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
4244 ValueChanged = TRUE;
4245 }
4246 }
4247
4248 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
4249 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
4250
4251 if (BackUpBuffer != NULL) {
4252 FreePool (BackUpBuffer);
4253 }
4254
4255 if (BackUpBuffer2 != NULL) {
4256 FreePool (BackUpBuffer2);
4257 }
4258
4259 Question->ValueChanged = ValueChanged;
4260
4261 return ValueChanged;
4262 }
4263
4264 /**
4265 Initialize Question's Edit copy from Storage.
4266
4267 @param Selection Selection contains the information about
4268 the Selection, form and formset to be displayed.
4269 Selection action may be updated in retrieve callback.
4270 If Selection is NULL, only initialize Question value.
4271 @param FormSet FormSet data structure.
4272 @param Form Form data structure.
4273
4274 @retval EFI_SUCCESS The function completed successfully.
4275
4276 **/
4277 EFI_STATUS
4278 LoadFormConfig (
4279 IN OUT UI_MENU_SELECTION *Selection,
4280 IN FORM_BROWSER_FORMSET *FormSet,
4281 IN FORM_BROWSER_FORM *Form
4282 )
4283 {
4284 EFI_STATUS Status;
4285 LIST_ENTRY *Link;
4286 FORM_BROWSER_STATEMENT *Question;
4287
4288 Link = GetFirstNode (&Form->StatementListHead);
4289 while (!IsNull (&Form->StatementListHead, Link)) {
4290 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
4291
4292 //
4293 // Initialize local copy of Value for each Question
4294 //
4295 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
4296 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
4297 } else {
4298 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4299 }
4300 if (EFI_ERROR (Status)) {
4301 return Status;
4302 }
4303
4304 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
4305 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
4306 }
4307
4308 Link = GetNextNode (&Form->StatementListHead, Link);
4309 }
4310
4311 return EFI_SUCCESS;
4312 }
4313
4314 /**
4315 Initialize Question's Edit copy from Storage for the whole Formset.
4316
4317 @param Selection Selection contains the information about
4318 the Selection, form and formset to be displayed.
4319 Selection action may be updated in retrieve callback.
4320 If Selection is NULL, only initialize Question value.
4321 @param FormSet FormSet data structure.
4322
4323 @retval EFI_SUCCESS The function completed successfully.
4324
4325 **/
4326 EFI_STATUS
4327 LoadFormSetConfig (
4328 IN OUT UI_MENU_SELECTION *Selection,
4329 IN FORM_BROWSER_FORMSET *FormSet
4330 )
4331 {
4332 EFI_STATUS Status;
4333 LIST_ENTRY *Link;
4334 FORM_BROWSER_FORM *Form;
4335
4336 Link = GetFirstNode (&FormSet->FormListHead);
4337 while (!IsNull (&FormSet->FormListHead, Link)) {
4338 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4339
4340 //
4341 // Initialize local copy of Value for each Form
4342 //
4343 Status = LoadFormConfig (Selection, FormSet, Form);
4344 if (EFI_ERROR (Status)) {
4345 return Status;
4346 }
4347
4348 Link = GetNextNode (&FormSet->FormListHead, Link);
4349 }
4350
4351 //
4352 // Finished question initialization.
4353 //
4354 FormSet->QuestionInited = TRUE;
4355
4356 return EFI_SUCCESS;
4357 }
4358
4359 /**
4360 Remove the Request element from the Config Request.
4361
4362 @param Storage Pointer to the browser storage.
4363 @param RequestElement The pointer to the Request element.
4364
4365 **/
4366 VOID
4367 RemoveElement (
4368 IN OUT BROWSER_STORAGE *Storage,
4369 IN CHAR16 *RequestElement
4370 )
4371 {
4372 CHAR16 *NewStr;
4373 CHAR16 *DestStr;
4374
4375 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
4376
4377 NewStr = StrStr (Storage->ConfigRequest, RequestElement);
4378
4379 if (NewStr == NULL) {
4380 return;
4381 }
4382
4383 //
4384 // Remove this element from this ConfigRequest.
4385 //
4386 DestStr = NewStr;
4387 NewStr += StrLen (RequestElement);
4388 CopyMem (DestStr, NewStr, StrSize (NewStr));
4389
4390 Storage->SpareStrLen += StrLen (RequestElement);
4391 }
4392
4393 /**
4394 Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
4395
4396 @param Storage Pointer to the browser storage.
4397 @param ConfigRequest The pointer to the Request element.
4398
4399 **/
4400 VOID
4401 RemoveConfigRequest (
4402 BROWSER_STORAGE *Storage,
4403 CHAR16 *ConfigRequest
4404 )
4405 {
4406 CHAR16 *RequestElement;
4407 CHAR16 *NextRequestElement;
4408 CHAR16 *SearchKey;
4409
4410 //
4411 // No request element in it, just return.
4412 //
4413 if (ConfigRequest == NULL) {
4414 return;
4415 }
4416
4417 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4418 //
4419 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
4420 //
4421 SearchKey = L"&";
4422 } else {
4423 //
4424 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
4425 //
4426 SearchKey = L"&OFFSET";
4427 }
4428
4429 //
4430 // Find SearchKey storage
4431 //
4432 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4433 RequestElement = StrStr (ConfigRequest, L"PATH");
4434 ASSERT (RequestElement != NULL);
4435 RequestElement = StrStr (RequestElement, SearchKey);
4436 } else {
4437 RequestElement = StrStr (ConfigRequest, SearchKey);
4438 }
4439
4440 while (RequestElement != NULL) {
4441 //
4442 // +1 to avoid find header itself.
4443 //
4444 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
4445
4446 //
4447 // The last Request element in configRequest string.
4448 //
4449 if (NextRequestElement != NULL) {
4450 //
4451 // Replace "&" with '\0'.
4452 //
4453 *NextRequestElement = L'\0';
4454 }
4455
4456 RemoveElement (Storage, RequestElement);
4457
4458 if (NextRequestElement != NULL) {
4459 //
4460 // Restore '&' with '\0' for later used.
4461 //
4462 *NextRequestElement = L'&';
4463 }
4464
4465 RequestElement = NextRequestElement;
4466 }
4467
4468 //
4469 // If no request element remain, just remove the ConfigRequest string.
4470 //
4471 if (StrCmp (Storage->ConfigRequest, Storage->ConfigHdr) == 0) {
4472 FreePool (Storage->ConfigRequest);
4473 Storage->ConfigRequest = NULL;
4474 Storage->SpareStrLen = 0;
4475 }
4476 }
4477
4478 /**
4479 Base on the current formset info, clean the ConfigRequest string in browser storage.
4480
4481 @param FormSet Pointer of the FormSet
4482
4483 **/
4484 VOID
4485 CleanBrowserStorage (
4486 IN OUT FORM_BROWSER_FORMSET *FormSet
4487 )
4488 {
4489 LIST_ENTRY *Link;
4490 FORMSET_STORAGE *Storage;
4491
4492 Link = GetFirstNode (&FormSet->StorageListHead);
4493 while (!IsNull (&FormSet->StorageListHead, Link)) {
4494 Storage = FORMSET_STORAGE_FROM_LINK (Link);
4495 Link = GetNextNode (&FormSet->StorageListHead, Link);
4496
4497 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
4498 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
4499 continue;
4500 }
4501
4502 RemoveConfigRequest (Storage->BrowserStorage, Storage->ConfigRequest);
4503 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
4504 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4505 if (Storage->BrowserStorage->ConfigRequest != NULL) {
4506 FreePool (Storage->BrowserStorage->ConfigRequest);
4507 Storage->BrowserStorage->ConfigRequest = NULL;
4508 }
4509 Storage->BrowserStorage->Initialized = FALSE;
4510 }
4511 }
4512 }
4513
4514 /**
4515 Check whether current element in the ConfigReqeust string.
4516
4517 @param BrowserStorage Storage which includes ConfigReqeust.
4518 @param RequestElement New element need to check.
4519
4520 @retval TRUE The Element is in the ConfigReqeust string.
4521 @retval FALSE The Element not in the configReqeust String.
4522
4523 **/
4524 BOOLEAN
4525 ElementValidation (
4526 BROWSER_STORAGE *BrowserStorage,
4527 CHAR16 *RequestElement
4528 )
4529 {
4530 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
4531 }
4532
4533 /**
4534 Append the Request element to the Config Request.
4535
4536 @param ConfigRequest Current ConfigRequest info.
4537 @param SpareStrLen Current remain free buffer for config reqeust.
4538 @param RequestElement New Request element.
4539
4540 **/
4541 VOID
4542 AppendConfigRequest (
4543 IN OUT CHAR16 **ConfigRequest,
4544 IN OUT UINTN *SpareStrLen,
4545 IN CHAR16 *RequestElement
4546 )
4547 {
4548 CHAR16 *NewStr;
4549 UINTN StringSize;
4550 UINTN StrLength;
4551
4552 StrLength = StrLen (RequestElement);
4553
4554 //
4555 // Append <RequestElement> to <ConfigRequest>
4556 //
4557 if (StrLength > *SpareStrLen) {
4558 //
4559 // Old String buffer is not sufficient for RequestElement, allocate a new one
4560 //
4561 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
4562 NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));
4563 ASSERT (NewStr != NULL);
4564
4565 if (*ConfigRequest != NULL) {
4566 CopyMem (NewStr, *ConfigRequest, StringSize);
4567 FreePool (*ConfigRequest);
4568 }
4569 *ConfigRequest = NewStr;
4570 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
4571 }
4572
4573 StrCat (*ConfigRequest, RequestElement);
4574 *SpareStrLen -= StrLength;
4575 }
4576
4577 /**
4578 Adjust the config request info, remove the request elements which already in AllConfigRequest string.
4579
4580 @param Storage Form set Storage.
4581 @param Request The input request string.
4582 @param RespString Whether the input is ConfigRequest or ConfigResp format.
4583
4584 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
4585 @retval FALSE All elements covered by current used elements.
4586
4587 **/
4588 BOOLEAN
4589 ConfigRequestAdjust (
4590 IN BROWSER_STORAGE *Storage,
4591 IN CHAR16 *Request,
4592 IN BOOLEAN RespString
4593 )
4594 {
4595 CHAR16 *RequestElement;
4596 CHAR16 *NextRequestElement;
4597 CHAR16 *NextElementBakup;
4598 UINTN SpareBufLen;
4599 CHAR16 *SearchKey;
4600 CHAR16 *ValueKey;
4601 BOOLEAN RetVal;
4602 CHAR16 *ConfigRequest;
4603
4604 SpareBufLen = 0;
4605 RetVal = FALSE;
4606 NextElementBakup = NULL;
4607 ValueKey = NULL;
4608
4609 if (Request != NULL) {
4610 ConfigRequest = Request;
4611 } else {
4612 ConfigRequest = Storage->ConfigRequest;
4613 }
4614
4615 if (Storage->ConfigRequest == NULL) {
4616 Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
4617 return TRUE;
4618 }
4619
4620 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4621 //
4622 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
4623 //
4624 SearchKey = L"&";
4625 } else {
4626 //
4627 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
4628 //
4629 SearchKey = L"&OFFSET";
4630 ValueKey = L"&VALUE";
4631 }
4632
4633 //
4634 // Find SearchKey storage
4635 //
4636 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4637 RequestElement = StrStr (ConfigRequest, L"PATH");
4638 ASSERT (RequestElement != NULL);
4639 RequestElement = StrStr (RequestElement, SearchKey);
4640 } else {
4641 RequestElement = StrStr (ConfigRequest, SearchKey);
4642 }
4643
4644 while (RequestElement != NULL) {
4645
4646 //
4647 // +1 to avoid find header itself.
4648 //
4649 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
4650
4651 //
4652 // The last Request element in configRequest string.
4653 //
4654 if (NextRequestElement != NULL) {
4655 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4656 NextElementBakup = NextRequestElement;
4657 NextRequestElement = StrStr (RequestElement, ValueKey);
4658 ASSERT (NextRequestElement != NULL);
4659 }
4660 //
4661 // Replace "&" with '\0'.
4662 //
4663 *NextRequestElement = L'\0';
4664 } else {
4665 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4666 NextElementBakup = NextRequestElement;
4667 NextRequestElement = StrStr (RequestElement, ValueKey);
4668 ASSERT (NextRequestElement != NULL);
4669 //
4670 // Replace "&" with '\0'.
4671 //
4672 *NextRequestElement = L'\0';
4673 }
4674 }
4675
4676 if (!ElementValidation (Storage, RequestElement)) {
4677 //
4678 // Add this element to the Storage->BrowserStorage->AllRequestElement.
4679 //
4680 AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
4681 RetVal = TRUE;
4682 }
4683
4684 if (NextRequestElement != NULL) {
4685 //
4686 // Restore '&' with '\0' for later used.
4687 //
4688 *NextRequestElement = L'&';
4689 }
4690
4691 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4692 RequestElement = NextElementBakup;
4693 } else {
4694 RequestElement = NextRequestElement;
4695 }
4696 }
4697
4698 return RetVal;
4699 }
4700
4701 /**
4702
4703 Base on ConfigRequest info to get default value for current formset.
4704
4705 ConfigRequest info include the info about which questions in current formset need to
4706 get default value. This function only get these questions default value.
4707
4708 @param FormSet FormSet data structure.
4709 @param Storage Storage need to update value.
4710 @param ConfigRequest The config request string.
4711
4712 **/
4713 VOID
4714 GetDefaultForFormset (
4715 IN FORM_BROWSER_FORMSET *FormSet,
4716 IN BROWSER_STORAGE *Storage,
4717 IN CHAR16 *ConfigRequest
4718 )
4719 {
4720 UINT8 *BackUpBuf;
4721 UINTN BufferSize;
4722 LIST_ENTRY BackUpList;
4723 NAME_VALUE_NODE *Node;
4724 LIST_ENTRY *Link;
4725 LIST_ENTRY *NodeLink;
4726 NAME_VALUE_NODE *TmpNode;
4727 EFI_STATUS Status;
4728 EFI_STRING Progress;
4729 EFI_STRING Result;
4730
4731 BackUpBuf = NULL;
4732 InitializeListHead(&BackUpList);
4733
4734 //
4735 // Back update the edit buffer.
4736 //
4737 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
4738 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4739 BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);
4740 ASSERT (BackUpBuf != NULL);
4741 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4742 Link = GetFirstNode (&Storage->NameValueListHead);
4743 while (!IsNull (&Storage->NameValueListHead, Link)) {
4744 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4745 Link = GetNextNode (&Storage->NameValueListHead, Link);
4746
4747 //
4748 // Only back Node belong to this formset.
4749 //
4750 if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {
4751 continue;
4752 }
4753
4754 TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);
4755 ASSERT (TmpNode != NULL);
4756 TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);
4757 ASSERT (TmpNode->Name != NULL);
4758 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
4759 ASSERT (TmpNode->EditValue != NULL);
4760
4761 InsertTailList(&BackUpList, &TmpNode->Link);
4762 }
4763 }
4764
4765 //
4766 // Get default value.
4767 //
4768 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);
4769
4770 //
4771 // Update the question value based on the input ConfigRequest.
4772 //
4773 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
4774 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4775 ASSERT (BackUpBuf != NULL);
4776 BufferSize = Storage->Size;
4777 Status = mHiiConfigRouting->BlockToConfig(
4778 mHiiConfigRouting,
4779 ConfigRequest,
4780 Storage->EditBuffer,
4781 BufferSize,
4782 &Result,
4783 &Progress
4784 );
4785 ASSERT_EFI_ERROR (Status);
4786
4787 Status = mHiiConfigRouting->ConfigToBlock (
4788 mHiiConfigRouting,
4789 Result,
4790 BackUpBuf,
4791 &BufferSize,
4792 &Progress
4793 );
4794 ASSERT_EFI_ERROR (Status);
4795
4796 if (Result != NULL) {
4797 FreePool (Result);
4798 }
4799
4800 CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);
4801 FreePool (BackUpBuf);
4802 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4803 //
4804 // Update question value, only element in ConfigReqeust will be update.
4805 //
4806 Link = GetFirstNode (&BackUpList);
4807 while (!IsNull (&BackUpList, Link)) {
4808 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4809 Link = GetNextNode (&BackUpList, Link);
4810
4811 if (StrStr (ConfigRequest, Node->Name) != NULL) {
4812 continue;
4813 }
4814
4815 NodeLink = GetFirstNode (&Storage->NameValueListHead);
4816 while (!IsNull (&Storage->NameValueListHead, NodeLink)) {
4817 TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink);
4818 NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);
4819
4820 if (StrCmp (Node->Name, TmpNode->Name) != 0) {
4821 continue;
4822 }
4823
4824 FreePool (TmpNode->EditValue);
4825 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
4826
4827 RemoveEntryList (&Node->Link);
4828 FreePool (Node->EditValue);
4829 FreePool (Node->Name);
4830 FreePool (Node);
4831 }
4832 }
4833
4834 //
4835 // Restore the Name/Value node.
4836 //
4837 Link = GetFirstNode (&BackUpList);
4838 while (!IsNull (&BackUpList, Link)) {
4839 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4840 Link = GetNextNode (&BackUpList, Link);
4841
4842 //
4843 // Free this node.
4844 //
4845 RemoveEntryList (&Node->Link);
4846 FreePool (Node->EditValue);
4847 FreePool (Node->Name);
4848 FreePool (Node);
4849 }
4850 }
4851 }
4852
4853 /**
4854 Fill storage's edit copy with settings requested from Configuration Driver.
4855
4856 @param FormSet FormSet data structure.
4857 @param Storage Buffer Storage.
4858
4859 **/
4860 VOID
4861 LoadStorage (
4862 IN FORM_BROWSER_FORMSET *FormSet,
4863 IN FORMSET_STORAGE *Storage
4864 )
4865 {
4866 EFI_STATUS Status;
4867 EFI_STRING Progress;
4868 EFI_STRING Result;
4869 CHAR16 *StrPtr;
4870 EFI_STRING ConfigRequest;
4871 UINTN StrLen;
4872
4873 ConfigRequest = NULL;
4874
4875 switch (Storage->BrowserStorage->Type) {
4876 case EFI_HII_VARSTORE_EFI_VARIABLE:
4877 return;
4878
4879 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
4880 if (Storage->BrowserStorage->ConfigRequest != NULL) {
4881 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
4882 return;
4883 }
4884 break;
4885
4886 case EFI_HII_VARSTORE_BUFFER:
4887 case EFI_HII_VARSTORE_NAME_VALUE:
4888 //
4889 // Skip if there is no RequestElement.
4890 //
4891 if (Storage->ElementCount == 0) {
4892 return;
4893 }
4894
4895 //
4896 // Just update the ConfigRequest, if storage already initialized.
4897 //
4898 if (Storage->BrowserStorage->Initialized) {
4899 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
4900 return;
4901 }
4902
4903 Storage->BrowserStorage->Initialized = TRUE;
4904 break;
4905
4906 default:
4907 return;
4908 }
4909
4910 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
4911 //
4912 // Create the config request string to get all fields for this storage.
4913 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
4914 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
4915 //
4916 StrLen = StrSize (Storage->BrowserStorage->ConfigHdr) + 20 * sizeof (CHAR16);
4917 ConfigRequest = AllocateZeroPool (StrLen);
4918 ASSERT (ConfigRequest != NULL);
4919 UnicodeSPrint (
4920 ConfigRequest,
4921 StrLen,
4922 L"%s&OFFSET=0&WIDTH=%04x",
4923 Storage->BrowserStorage->ConfigHdr,
4924 Storage->BrowserStorage->Size);
4925 } else {
4926 ConfigRequest = Storage->ConfigRequest;
4927 }
4928
4929 //
4930 // Request current settings from Configuration Driver
4931 //
4932 Status = mHiiConfigRouting->ExtractConfig (
4933 mHiiConfigRouting,
4934 ConfigRequest,
4935 &Progress,
4936 &Result
4937 );
4938
4939 //
4940 // If get value fail, extract default from IFR binary
4941 //
4942 if (EFI_ERROR (Status)) {
4943 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);
4944 } else {
4945 //
4946 // Convert Result from <ConfigAltResp> to <ConfigResp>
4947 //
4948 StrPtr = StrStr (Result, L"&GUID=");
4949 if (StrPtr != NULL) {
4950 *StrPtr = L'\0';
4951 }
4952
4953 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
4954 FreePool (Result);
4955 }
4956
4957 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
4958
4959 //
4960 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
4961 //
4962 SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);
4963
4964 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
4965 if (ConfigRequest != NULL) {
4966 FreePool (ConfigRequest);
4967 }
4968 }
4969 }
4970
4971 /**
4972 Get Value changed status from old question.
4973
4974 @param NewFormSet FormSet data structure.
4975 @param OldQuestion Old question which has value changed.
4976
4977 **/
4978 VOID
4979 SyncStatusForQuestion (
4980 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
4981 IN FORM_BROWSER_STATEMENT *OldQuestion
4982 )
4983 {
4984 LIST_ENTRY *Link;
4985 LIST_ENTRY *QuestionLink;
4986 FORM_BROWSER_FORM *Form;
4987 FORM_BROWSER_STATEMENT *Question;
4988
4989 //
4990 // For each form in one formset.
4991 //
4992 Link = GetFirstNode (&NewFormSet->FormListHead);
4993 while (!IsNull (&NewFormSet->FormListHead, Link)) {
4994 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4995 Link = GetNextNode (&NewFormSet->FormListHead, Link);
4996
4997 //
4998 // for each question in one form.
4999 //
5000 QuestionLink = GetFirstNode (&Form->StatementListHead);
5001 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5002 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5003 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5004
5005 if (Question->QuestionId == OldQuestion->QuestionId) {
5006 Question->ValueChanged = TRUE;
5007 return;
5008 }
5009 }
5010 }
5011 }
5012
5013 /**
5014 Get Value changed status from old formset.
5015
5016 @param NewFormSet FormSet data structure.
5017 @param OldFormSet FormSet data structure.
5018
5019 **/
5020 VOID
5021 SyncStatusForFormSet (
5022 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5023 IN FORM_BROWSER_FORMSET *OldFormSet
5024 )
5025 {
5026 LIST_ENTRY *Link;
5027 LIST_ENTRY *QuestionLink;
5028 FORM_BROWSER_FORM *Form;
5029 FORM_BROWSER_STATEMENT *Question;
5030
5031 //
5032 // For each form in one formset.
5033 //
5034 Link = GetFirstNode (&OldFormSet->FormListHead);
5035 while (!IsNull (&OldFormSet->FormListHead, Link)) {
5036 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5037 Link = GetNextNode (&OldFormSet->FormListHead, Link);
5038
5039 //
5040 // for each question in one form.
5041 //
5042 QuestionLink = GetFirstNode (&Form->StatementListHead);
5043 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5044 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5045 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5046
5047 if (!Question->ValueChanged) {
5048 continue;
5049 }
5050
5051 //
5052 // Find the same question in new formset and update the value changed flag.
5053 //
5054 SyncStatusForQuestion (NewFormSet, Question);
5055 }
5056 }
5057 }
5058
5059 /**
5060 Get current setting of Questions.
5061
5062 @param FormSet FormSet data structure.
5063
5064 **/
5065 VOID
5066 InitializeCurrentSetting (
5067 IN OUT FORM_BROWSER_FORMSET *FormSet
5068 )
5069 {
5070 LIST_ENTRY *Link;
5071 FORMSET_STORAGE *Storage;
5072 FORM_BROWSER_FORMSET *OldFormSet;
5073
5074 //
5075 // Try to find pre FormSet in the maintain backup list.
5076 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
5077 //
5078 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
5079 if (OldFormSet != NULL) {
5080 SyncStatusForFormSet (FormSet, OldFormSet);
5081 RemoveEntryList (&OldFormSet->Link);
5082 DestroyFormSet (OldFormSet);
5083 }
5084 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
5085
5086 //
5087 // Extract default from IFR binary for no storage questions.
5088 //
5089 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);
5090
5091 //
5092 // Request current settings from Configuration Driver
5093 //
5094 Link = GetFirstNode (&FormSet->StorageListHead);
5095 while (!IsNull (&FormSet->StorageListHead, Link)) {
5096 Storage = FORMSET_STORAGE_FROM_LINK (Link);
5097
5098 LoadStorage (FormSet, Storage);
5099
5100 Link = GetNextNode (&FormSet->StorageListHead, Link);
5101 }
5102 }
5103
5104
5105 /**
5106 Fetch the Ifr binary data of a FormSet.
5107
5108 @param Handle PackageList Handle
5109 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5110 specified (NULL or zero GUID), take the first
5111 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5112 found in package list.
5113 On output, GUID of the formset found(if not NULL).
5114 @param BinaryLength The length of the FormSet IFR binary.
5115 @param BinaryData The buffer designed to receive the FormSet.
5116
5117 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
5118 BufferLength was updated.
5119 @retval EFI_INVALID_PARAMETER The handle is unknown.
5120 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
5121 be found with the requested FormId.
5122
5123 **/
5124 EFI_STATUS
5125 GetIfrBinaryData (
5126 IN EFI_HII_HANDLE Handle,
5127 IN OUT EFI_GUID *FormSetGuid,
5128 OUT UINTN *BinaryLength,
5129 OUT UINT8 **BinaryData
5130 )
5131 {
5132 EFI_STATUS Status;
5133 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
5134 UINTN BufferSize;
5135 UINT8 *Package;
5136 UINT8 *OpCodeData;
5137 UINT32 Offset;
5138 UINT32 Offset2;
5139 UINT32 PackageListLength;
5140 EFI_HII_PACKAGE_HEADER PackageHeader;
5141 UINT8 Index;
5142 UINT8 NumberOfClassGuid;
5143 BOOLEAN ClassGuidMatch;
5144 EFI_GUID *ClassGuid;
5145 EFI_GUID *ComparingGuid;
5146
5147 OpCodeData = NULL;
5148 Package = NULL;
5149 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
5150
5151 //
5152 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
5153 //
5154 if (FormSetGuid == NULL) {
5155 ComparingGuid = &gZeroGuid;
5156 } else {
5157 ComparingGuid = FormSetGuid;
5158 }
5159
5160 //
5161 // Get HII PackageList
5162 //
5163 BufferSize = 0;
5164 HiiPackageList = NULL;
5165 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5166 if (Status == EFI_BUFFER_TOO_SMALL) {
5167 HiiPackageList = AllocatePool (BufferSize);
5168 ASSERT (HiiPackageList != NULL);
5169
5170 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5171 }
5172 if (EFI_ERROR (Status)) {
5173 return Status;
5174 }
5175 ASSERT (HiiPackageList != NULL);
5176
5177 //
5178 // Get Form package from this HII package List
5179 //
5180 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
5181 Offset2 = 0;
5182 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
5183
5184 ClassGuidMatch = FALSE;
5185 while (Offset < PackageListLength) {
5186 Package = ((UINT8 *) HiiPackageList) + Offset;
5187 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
5188
5189 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
5190 //
5191 // Search FormSet in this Form Package
5192 //
5193 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
5194 while (Offset2 < PackageHeader.Length) {
5195 OpCodeData = Package + Offset2;
5196
5197 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
5198 //
5199 // Try to compare against formset GUID
5200 //
5201 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
5202 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
5203 break;
5204 }
5205
5206 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
5207 //
5208 // Try to compare against formset class GUID
5209 //
5210 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
5211 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
5212 for (Index = 0; Index < NumberOfClassGuid; Index++) {
5213 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
5214 ClassGuidMatch = TRUE;
5215 break;
5216 }
5217 }
5218 if (ClassGuidMatch) {
5219 break;
5220 }
5221 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
5222 ClassGuidMatch = TRUE;
5223 break;
5224 }
5225 }
5226
5227 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
5228 }
5229
5230 if (Offset2 < PackageHeader.Length) {
5231 //
5232 // Target formset found
5233 //
5234 break;
5235 }
5236 }
5237
5238 Offset += PackageHeader.Length;
5239 }
5240
5241 if (Offset >= PackageListLength) {
5242 //
5243 // Form package not found in this Package List
5244 //
5245 FreePool (HiiPackageList);
5246 return EFI_NOT_FOUND;
5247 }
5248
5249 if (FormSetGuid != NULL) {
5250 //
5251 // Return the FormSet GUID
5252 //
5253 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
5254 }
5255
5256 //
5257 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
5258 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
5259 // of the Form Package.
5260 //
5261 *BinaryLength = PackageHeader.Length - Offset2;
5262 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
5263
5264 FreePool (HiiPackageList);
5265
5266 if (*BinaryData == NULL) {
5267 return EFI_OUT_OF_RESOURCES;
5268 }
5269
5270 return EFI_SUCCESS;
5271 }
5272
5273
5274 /**
5275 Initialize the internal data structure of a FormSet.
5276
5277 @param Handle PackageList Handle
5278 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5279 specified (NULL or zero GUID), take the first
5280 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5281 found in package list.
5282 On output, GUID of the formset found(if not NULL).
5283 @param FormSet FormSet data structure.
5284
5285 @retval EFI_SUCCESS The function completed successfully.
5286 @retval EFI_NOT_FOUND The specified FormSet could not be found.
5287
5288 **/
5289 EFI_STATUS
5290 InitializeFormSet (
5291 IN EFI_HII_HANDLE Handle,
5292 IN OUT EFI_GUID *FormSetGuid,
5293 OUT FORM_BROWSER_FORMSET *FormSet
5294 )
5295 {
5296 EFI_STATUS Status;
5297 EFI_HANDLE DriverHandle;
5298
5299 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
5300 if (EFI_ERROR (Status)) {
5301 return Status;
5302 }
5303
5304 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
5305 FormSet->HiiHandle = Handle;
5306 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
5307 FormSet->QuestionInited = FALSE;
5308
5309 //
5310 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
5311 //
5312 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
5313 if (EFI_ERROR (Status)) {
5314 return Status;
5315 }
5316 FormSet->DriverHandle = DriverHandle;
5317 Status = gBS->HandleProtocol (
5318 DriverHandle,
5319 &gEfiHiiConfigAccessProtocolGuid,
5320 (VOID **) &FormSet->ConfigAccess
5321 );
5322 if (EFI_ERROR (Status)) {
5323 //
5324 // Configuration Driver don't attach ConfigAccess protocol to its HII package
5325 // list, then there will be no configuration action required
5326 //
5327 FormSet->ConfigAccess = NULL;
5328 }
5329
5330 //
5331 // Parse the IFR binary OpCodes
5332 //
5333 Status = ParseOpCodes (FormSet);
5334
5335 return Status;
5336 }
5337
5338
5339 /**
5340 Save globals used by previous call to SendForm(). SendForm() may be called from
5341 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
5342 So, save globals of previous call to SendForm() and restore them upon exit.
5343
5344 **/
5345 VOID
5346 SaveBrowserContext (
5347 VOID
5348 )
5349 {
5350 BROWSER_CONTEXT *Context;
5351 FORM_ENTRY_INFO *MenuList;
5352
5353 gBrowserContextCount++;
5354 if (gBrowserContextCount == 1) {
5355 //
5356 // This is not reentry of SendForm(), no context to save
5357 //
5358 return;
5359 }
5360
5361 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
5362 ASSERT (Context != NULL);
5363
5364 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
5365
5366 //
5367 // Save FormBrowser context
5368 //
5369 Context->Selection = gCurrentSelection;
5370 Context->ResetRequired = gResetRequired;
5371 Context->ExitRequired = gExitRequired;
5372 Context->HiiHandle = mCurrentHiiHandle;
5373 Context->FormId = mCurrentFormId;
5374 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
5375
5376 //
5377 // Save the menu history data.
5378 //
5379 InitializeListHead(&Context->FormHistoryList);
5380 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
5381 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
5382 RemoveEntryList (&MenuList->Link);
5383
5384 InsertTailList(&Context->FormHistoryList, &MenuList->Link);
5385 }
5386
5387 //
5388 // Insert to FormBrowser context list
5389 //
5390 InsertHeadList (&gBrowserContextList, &Context->Link);
5391 }
5392
5393
5394 /**
5395 Restore globals used by previous call to SendForm().
5396
5397 **/
5398 VOID
5399 RestoreBrowserContext (
5400 VOID
5401 )
5402 {
5403 LIST_ENTRY *Link;
5404 BROWSER_CONTEXT *Context;
5405 FORM_ENTRY_INFO *MenuList;
5406
5407 ASSERT (gBrowserContextCount != 0);
5408 gBrowserContextCount--;
5409 if (gBrowserContextCount == 0) {
5410 //
5411 // This is not reentry of SendForm(), no context to restore
5412 //
5413 return;
5414 }
5415
5416 ASSERT (!IsListEmpty (&gBrowserContextList));
5417
5418 Link = GetFirstNode (&gBrowserContextList);
5419 Context = BROWSER_CONTEXT_FROM_LINK (Link);
5420
5421 //
5422 // Restore FormBrowser context
5423 //
5424 gCurrentSelection = Context->Selection;
5425 gResetRequired = Context->ResetRequired;
5426 gExitRequired = Context->ExitRequired;
5427 mCurrentHiiHandle = Context->HiiHandle;
5428 mCurrentFormId = Context->FormId;
5429 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
5430
5431 //
5432 // Restore the menu history data.
5433 //
5434 while (!IsListEmpty (&Context->FormHistoryList)) {
5435 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
5436 RemoveEntryList (&MenuList->Link);
5437
5438 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
5439 }
5440
5441 //
5442 // Remove from FormBrowser context list
5443 //
5444 RemoveEntryList (&Context->Link);
5445 gBS->FreePool (Context);
5446 }
5447
5448 /**
5449 Find the matched FormSet context in the backup maintain list based on HiiHandle.
5450
5451 @param Handle The Hii Handle.
5452
5453 @return the found FormSet context. If no found, NULL will return.
5454
5455 **/
5456 FORM_BROWSER_FORMSET *
5457 GetFormSetFromHiiHandle (
5458 EFI_HII_HANDLE Handle
5459 )
5460 {
5461 LIST_ENTRY *Link;
5462 FORM_BROWSER_FORMSET *FormSet;
5463
5464 Link = GetFirstNode (&gBrowserFormSetList);
5465 while (!IsNull (&gBrowserFormSetList, Link)) {
5466 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5467 Link = GetNextNode (&gBrowserFormSetList, Link);
5468 if (!ValidateFormSet(FormSet)) {
5469 continue;
5470 }
5471 if (FormSet->HiiHandle == Handle) {
5472 return FormSet;
5473 }
5474 }
5475
5476 return NULL;
5477 }
5478
5479 /**
5480 Check whether the input HII handle is the FormSet that is being used.
5481
5482 @param Handle The Hii Handle.
5483
5484 @retval TRUE HII handle is being used.
5485 @retval FALSE HII handle is not being used.
5486
5487 **/
5488 BOOLEAN
5489 IsHiiHandleInBrowserContext (
5490 EFI_HII_HANDLE Handle
5491 )
5492 {
5493 LIST_ENTRY *Link;
5494 BROWSER_CONTEXT *Context;
5495
5496 //
5497 // HiiHandle is Current FormSet.
5498 //
5499 if (mCurrentHiiHandle == Handle) {
5500 return TRUE;
5501 }
5502
5503 //
5504 // Check whether HiiHandle is in BrowserContext.
5505 //
5506 Link = GetFirstNode (&gBrowserContextList);
5507 while (!IsNull (&gBrowserContextList, Link)) {
5508 Context = BROWSER_CONTEXT_FROM_LINK (Link);
5509 if (Context->HiiHandle == Handle) {
5510 //
5511 // HiiHandle is in BrowserContext
5512 //
5513 return TRUE;
5514 }
5515 Link = GetNextNode (&gBrowserContextList, Link);
5516 }
5517
5518 return FALSE;
5519 }
5520
5521 /**
5522 Perform Password check.
5523 Passwork may be encrypted by driver that requires the specific check.
5524
5525 @param Form Form where Password Statement is in.
5526 @param Statement Password statement
5527 @param PasswordString Password string to be checked. It may be NULL.
5528 NULL means to restore password.
5529 "" string can be used to checked whether old password does exist.
5530
5531 @return Status Status of Password check.
5532 **/
5533 EFI_STATUS
5534 EFIAPI
5535 PasswordCheck (
5536 IN FORM_DISPLAY_ENGINE_FORM *Form,
5537 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
5538 IN EFI_STRING PasswordString OPTIONAL
5539 )
5540 {
5541 EFI_STATUS Status;
5542 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5543 EFI_BROWSER_ACTION_REQUEST ActionRequest;
5544 EFI_IFR_TYPE_VALUE IfrTypeValue;
5545 FORM_BROWSER_STATEMENT *Question;
5546
5547 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
5548 Question = GetBrowserStatement(Statement);
5549 ASSERT (Question != NULL);
5550
5551 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
5552 if (ConfigAccess == NULL) {
5553 return EFI_UNSUPPORTED;
5554 }
5555 } else {
5556 if (PasswordString == NULL) {
5557 return EFI_SUCCESS;
5558 }
5559
5560 //
5561 // Check whether has preexisted password.
5562 //
5563 if (PasswordString[0] == 0) {
5564 if (*((CHAR16 *) Question->BufferValue) == 0) {
5565 return EFI_SUCCESS;
5566 } else {
5567 return EFI_NOT_READY;
5568 }
5569 }
5570
5571 //
5572 // Check whether the input password is same as preexisted password.
5573 //
5574 if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {
5575 return EFI_SUCCESS;
5576 } else {
5577 return EFI_NOT_READY;
5578 }
5579 }
5580
5581 //
5582 // Prepare password string in HII database
5583 //
5584 if (PasswordString != NULL) {
5585 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
5586 } else {
5587 IfrTypeValue.string = 0;
5588 }
5589
5590 //
5591 // Send password to Configuration Driver for validation
5592 //
5593 Status = ConfigAccess->Callback (
5594 ConfigAccess,
5595 EFI_BROWSER_ACTION_CHANGING,
5596 Question->QuestionId,
5597 Question->HiiValue.Type,
5598 &IfrTypeValue,
5599 &ActionRequest
5600 );
5601
5602 //
5603 // Remove password string from HII database
5604 //
5605 if (PasswordString != NULL) {
5606 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
5607 }
5608
5609 return Status;
5610 }
5611
5612 /**
5613 Find the registered HotKey based on KeyData.
5614
5615 @param[in] KeyData A pointer to a buffer that describes the keystroke
5616 information for the hot key.
5617
5618 @return The registered HotKey context. If no found, NULL will return.
5619 **/
5620 BROWSER_HOT_KEY *
5621 GetHotKeyFromRegisterList (
5622 IN EFI_INPUT_KEY *KeyData
5623 )
5624 {
5625 LIST_ENTRY *Link;
5626 BROWSER_HOT_KEY *HotKey;
5627
5628 Link = GetFirstNode (&gBrowserHotKeyList);
5629 while (!IsNull (&gBrowserHotKeyList, Link)) {
5630 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
5631 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
5632 return HotKey;
5633 }
5634 Link = GetNextNode (&gBrowserHotKeyList, Link);
5635 }
5636
5637 return NULL;
5638 }
5639
5640 /**
5641 Configure what scope the hot key will impact.
5642 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
5643 If no scope is set, the default scope will be FormSet level.
5644 After all registered hot keys are removed, previous Scope can reset to another level.
5645
5646 @param[in] Scope Scope level to be set.
5647
5648 @retval EFI_SUCCESS Scope is set correctly.
5649 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
5650 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
5651
5652 **/
5653 EFI_STATUS
5654 EFIAPI
5655 SetScope (
5656 IN BROWSER_SETTING_SCOPE Scope
5657 )
5658 {
5659 if (Scope >= MaxLevel) {
5660 return EFI_INVALID_PARAMETER;
5661 }
5662
5663 //
5664 // When no hot key registered in system or on the first setting,
5665 // Scope can be set.
5666 //
5667 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
5668 gBrowserSettingScope = Scope;
5669 mBrowserScopeFirstSet = FALSE;
5670 } else if (Scope != gBrowserSettingScope) {
5671 return EFI_UNSUPPORTED;
5672 }
5673
5674 return EFI_SUCCESS;
5675 }
5676
5677 /**
5678 Register the hot key with its browser action, or unregistered the hot key.
5679 Only support hot key that is not printable character (control key, function key, etc.).
5680 If the action value is zero, the hot key will be unregistered if it has been registered.
5681 If the same hot key has been registered, the new action and help string will override the previous ones.
5682
5683 @param[in] KeyData A pointer to a buffer that describes the keystroke
5684 information for the hot key. Its type is EFI_INPUT_KEY to
5685 be supported by all ConsoleIn devices.
5686 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
5687 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
5688 @param[in] HelpString Help string that describes the hot key information.
5689 Its value may be NULL for the unregistered hot key.
5690
5691 @retval EFI_SUCCESS Hot key is registered or unregistered.
5692 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
5693 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
5694 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
5695 **/
5696 EFI_STATUS
5697 EFIAPI
5698 RegisterHotKey (
5699 IN EFI_INPUT_KEY *KeyData,
5700 IN UINT32 Action,
5701 IN UINT16 DefaultId,
5702 IN EFI_STRING HelpString OPTIONAL
5703 )
5704 {
5705 BROWSER_HOT_KEY *HotKey;
5706
5707 //
5708 // Check input parameters.
5709 //
5710 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
5711 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
5712 return EFI_INVALID_PARAMETER;
5713 }
5714
5715 //
5716 // Check whether the input KeyData is in BrowserHotKeyList.
5717 //
5718 HotKey = GetHotKeyFromRegisterList (KeyData);
5719
5720 //
5721 // Unregister HotKey
5722 //
5723 if (Action == BROWSER_ACTION_UNREGISTER) {
5724 if (HotKey != NULL) {
5725 //
5726 // The registered HotKey is found.
5727 // Remove it from List, and free its resource.
5728 //
5729 RemoveEntryList (&HotKey->Link);
5730 FreePool (HotKey->KeyData);
5731 FreePool (HotKey->HelpString);
5732 return EFI_SUCCESS;
5733 } else {
5734 //
5735 // The registered HotKey is not found.
5736 //
5737 return EFI_NOT_FOUND;
5738 }
5739 }
5740
5741 //
5742 // Register HotKey into List.
5743 //
5744 if (HotKey == NULL) {
5745 //
5746 // Create new Key, and add it into List.
5747 //
5748 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
5749 ASSERT (HotKey != NULL);
5750 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
5751 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
5752 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
5753 }
5754
5755 //
5756 // Fill HotKey information.
5757 //
5758 HotKey->Action = Action;
5759 HotKey->DefaultId = DefaultId;
5760 if (HotKey->HelpString != NULL) {
5761 FreePool (HotKey->HelpString);
5762 }
5763 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
5764
5765 return EFI_SUCCESS;
5766 }
5767
5768 /**
5769 Register Exit handler function.
5770 When more than one handler function is registered, the latter one will override the previous one.
5771 When NULL handler is specified, the previous Exit handler will be unregistered.
5772
5773 @param[in] Handler Pointer to handler function.
5774
5775 **/
5776 VOID
5777 EFIAPI
5778 RegiserExitHandler (
5779 IN EXIT_HANDLER Handler
5780 )
5781 {
5782 ExitHandlerFunction = Handler;
5783 return;
5784 }
5785
5786 /**
5787 Check whether the browser data has been modified.
5788
5789 @retval TRUE Browser data is modified.
5790 @retval FALSE No browser data is modified.
5791
5792 **/
5793 BOOLEAN
5794 EFIAPI
5795 IsBrowserDataModified (
5796 VOID
5797 )
5798 {
5799 LIST_ENTRY *Link;
5800 FORM_BROWSER_FORMSET *FormSet;
5801
5802 switch (gBrowserSettingScope) {
5803 case FormLevel:
5804 if (gCurrentSelection == NULL) {
5805 return FALSE;
5806 }
5807 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
5808
5809 case FormSetLevel:
5810 if (gCurrentSelection == NULL) {
5811 return FALSE;
5812 }
5813 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
5814
5815 case SystemLevel:
5816 Link = GetFirstNode (&gBrowserFormSetList);
5817 while (!IsNull (&gBrowserFormSetList, Link)) {
5818 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5819 if (!ValidateFormSet(FormSet)) {
5820 continue;
5821 }
5822
5823 if (IsNvUpdateRequiredForFormSet (FormSet)) {
5824 return TRUE;
5825 }
5826 Link = GetNextNode (&gBrowserFormSetList, Link);
5827 }
5828 return FALSE;
5829
5830 default:
5831 return FALSE;
5832 }
5833 }
5834
5835 /**
5836 Execute the action requested by the Action parameter.
5837
5838 @param[in] Action Execute the request action.
5839 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
5840
5841 @retval EFI_SUCCESS Execute the request action succss.
5842 @retval EFI_INVALID_PARAMETER The input action value is invalid.
5843
5844 **/
5845 EFI_STATUS
5846 EFIAPI
5847 ExecuteAction (
5848 IN UINT32 Action,
5849 IN UINT16 DefaultId
5850 )
5851 {
5852 EFI_STATUS Status;
5853 FORM_BROWSER_FORMSET *FormSet;
5854 FORM_BROWSER_FORM *Form;
5855
5856 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
5857 return EFI_NOT_READY;
5858 }
5859
5860 Status = EFI_SUCCESS;
5861 FormSet = NULL;
5862 Form = NULL;
5863 if (gBrowserSettingScope < SystemLevel) {
5864 FormSet = gCurrentSelection->FormSet;
5865 Form = gCurrentSelection->Form;
5866 }
5867
5868 //
5869 // Executet the discard action.
5870 //
5871 if ((Action & BROWSER_ACTION_DISCARD) != 0) {
5872 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
5873 if (EFI_ERROR (Status)) {
5874 return Status;
5875 }
5876 }
5877
5878 //
5879 // Executet the difault action.
5880 //
5881 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
5882 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
5883 if (EFI_ERROR (Status)) {
5884 return Status;
5885 }
5886 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
5887 }
5888
5889 //
5890 // Executet the submit action.
5891 //
5892 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
5893 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
5894 if (EFI_ERROR (Status)) {
5895 return Status;
5896 }
5897 }
5898
5899 //
5900 // Executet the reset action.
5901 //
5902 if ((Action & BROWSER_ACTION_RESET) != 0) {
5903 gResetRequired = TRUE;
5904 }
5905
5906 //
5907 // Executet the exit action.
5908 //
5909 if ((Action & BROWSER_ACTION_EXIT) != 0) {
5910 DiscardForm (FormSet, Form, gBrowserSettingScope);
5911 if (gBrowserSettingScope == SystemLevel) {
5912 if (ExitHandlerFunction != NULL) {
5913 ExitHandlerFunction ();
5914 }
5915 }
5916
5917 gExitRequired = TRUE;
5918 }
5919
5920 return Status;
5921 }
5922
5923 /**
5924 Create reminder to let user to choose save or discard the changed browser data.
5925 Caller can use it to actively check the changed browser data.
5926
5927 @retval BROWSER_NO_CHANGES No browser data is changed.
5928 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
5929 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
5930 @retval BROWSER_KEEP_CURRENT Browser keep current changes.
5931
5932 **/
5933 UINT32
5934 EFIAPI
5935 SaveReminder (
5936 VOID
5937 )
5938 {
5939 LIST_ENTRY *Link;
5940 FORM_BROWSER_FORMSET *FormSet;
5941 BOOLEAN IsDataChanged;
5942 UINT32 DataSavedAction;
5943 UINT32 ConfirmRet;
5944
5945 DataSavedAction = BROWSER_NO_CHANGES;
5946 IsDataChanged = FALSE;
5947 Link = GetFirstNode (&gBrowserFormSetList);
5948 while (!IsNull (&gBrowserFormSetList, Link)) {
5949 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5950 Link = GetNextNode (&gBrowserFormSetList, Link);
5951 if (!ValidateFormSet(FormSet)) {
5952 continue;
5953 }
5954 if (IsNvUpdateRequiredForFormSet (FormSet)) {
5955 IsDataChanged = TRUE;
5956 break;
5957 }
5958 }
5959
5960 //
5961 // No data is changed. No save is required.
5962 //
5963 if (!IsDataChanged) {
5964 return DataSavedAction;
5965 }
5966
5967 //
5968 // If data is changed, prompt user to save or discard it.
5969 //
5970 do {
5971 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
5972
5973 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
5974 SubmitForm (NULL, NULL, SystemLevel);
5975 DataSavedAction = BROWSER_SAVE_CHANGES;
5976 break;
5977 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
5978 DiscardForm (NULL, NULL, SystemLevel);
5979 DataSavedAction = BROWSER_DISCARD_CHANGES;
5980 break;
5981 } else if (ConfirmRet == BROWSER_ACTION_NONE) {
5982 DataSavedAction = BROWSER_KEEP_CURRENT;
5983 break;
5984 }
5985 } while (1);
5986
5987 return DataSavedAction;
5988 }
5989
5990 /**
5991 Check whether the Reset Required for the browser
5992
5993 @retval TRUE Browser required to reset after exit.
5994 @retval FALSE Browser not need to reset after exit.
5995
5996 **/
5997 BOOLEAN
5998 EFIAPI
5999 IsResetRequired (
6000 VOID
6001 )
6002 {
6003 return gResetRequired;
6004 }
6005