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