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