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