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