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