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