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