]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
MdeModulePkg:System hangs in setup menu
[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 if (Question->Operand == EFI_IFR_DATE_OP){
1599 QuestionValue->date.Year = 0xff;
1600 QuestionValue->date.Month = 0xff;
1601 QuestionValue->date.Day = 0xff;
1602 } else {
1603 QuestionValue->time.Hour = 0xff;
1604 QuestionValue->time.Minute = 0xff;
1605 QuestionValue->time.Second = 0xff;
1606 }
1607 return EFI_SUCCESS;
1608 }
1609
1610 if (Question->Operand == EFI_IFR_DATE_OP) {
1611 QuestionValue->date.Year = EfiTime.Year;
1612 QuestionValue->date.Month = EfiTime.Month;
1613 QuestionValue->date.Day = EfiTime.Day;
1614 } else {
1615 QuestionValue->time.Hour = EfiTime.Hour;
1616 QuestionValue->time.Minute = EfiTime.Minute;
1617 QuestionValue->time.Second = EfiTime.Second;
1618 }
1619 }
1620
1621 return EFI_SUCCESS;
1622 }
1623
1624 //
1625 // Question value is provided by EFI variable
1626 //
1627 StorageWidth = Question->StorageWidth;
1628 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1629 if (Question->BufferValue != NULL) {
1630 Dst = Question->BufferValue;
1631 } else {
1632 Dst = (UINT8 *) QuestionValue;
1633 }
1634
1635 Status = gRT->GetVariable (
1636 Question->VariableName,
1637 &Storage->Guid,
1638 NULL,
1639 &StorageWidth,
1640 Dst
1641 );
1642 //
1643 // Always return success, even this EFI variable doesn't exist
1644 //
1645 return EFI_SUCCESS;
1646 }
1647
1648 //
1649 // Question Value is provided by Buffer Storage or NameValue Storage
1650 //
1651 if (Question->BufferValue != NULL) {
1652 //
1653 // This Question is password or orderedlist
1654 //
1655 Dst = Question->BufferValue;
1656 } else {
1657 //
1658 // Other type of Questions
1659 //
1660 Dst = (UINT8 *) &Question->HiiValue.Value;
1661 }
1662
1663 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1664 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1665 IsBufferStorage = TRUE;
1666 } else {
1667 IsBufferStorage = FALSE;
1668 }
1669 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
1670 if (IsBufferStorage) {
1671 if (GetValueFrom == GetSetValueWithEditBuffer) {
1672 //
1673 // Copy from storage Edit buffer
1674 //
1675 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1676 } else {
1677 //
1678 // Copy from storage Edit buffer
1679 //
1680 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1681 }
1682 } else {
1683 Value = NULL;
1684 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
1685 if (EFI_ERROR (Status)) {
1686 return Status;
1687 }
1688
1689 ASSERT (Value != NULL);
1690 Status = BufferToValue (Question, Value);
1691 FreePool (Value);
1692 }
1693 } else {
1694 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
1695 ASSERT (FormsetStorage != NULL);
1696 //
1697 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
1698 // <ConfigHdr> + "&" + <VariableName>
1699 //
1700 if (IsBufferStorage) {
1701 Length = StrLen (FormsetStorage->ConfigHdr);
1702 Length += StrLen (Question->BlockName);
1703 } else {
1704 Length = StrLen (FormsetStorage->ConfigHdr);
1705 Length += StrLen (Question->VariableName) + 1;
1706 }
1707 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
1708 ASSERT (ConfigRequest != NULL);
1709
1710 StrCpy (ConfigRequest, FormsetStorage->ConfigHdr);
1711 if (IsBufferStorage) {
1712 StrCat (ConfigRequest, Question->BlockName);
1713 } else {
1714 StrCat (ConfigRequest, L"&");
1715 StrCat (ConfigRequest, Question->VariableName);
1716 }
1717
1718 //
1719 // Request current settings from Configuration Driver
1720 //
1721 Status = mHiiConfigRouting->ExtractConfig (
1722 mHiiConfigRouting,
1723 ConfigRequest,
1724 &Progress,
1725 &Result
1726 );
1727 FreePool (ConfigRequest);
1728 if (EFI_ERROR (Status)) {
1729 return Status;
1730 }
1731
1732 //
1733 // Skip <ConfigRequest>
1734 //
1735 if (IsBufferStorage) {
1736 Value = StrStr (Result, L"&VALUE");
1737 if (Value == NULL) {
1738 FreePool (Result);
1739 return EFI_NOT_FOUND;
1740 }
1741 //
1742 // Skip "&VALUE"
1743 //
1744 Value = Value + 6;
1745 } else {
1746 Value = Result + Length;
1747 }
1748 if (*Value != '=') {
1749 FreePool (Result);
1750 return EFI_NOT_FOUND;
1751 }
1752 //
1753 // Skip '=', point to value
1754 //
1755 Value = Value + 1;
1756
1757 Status = BufferToValue (Question, Value);
1758 if (EFI_ERROR (Status)) {
1759 FreePool (Result);
1760 return Status;
1761 }
1762
1763 //
1764 // Synchronize Edit Buffer
1765 //
1766 if (IsBufferStorage) {
1767 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
1768 } else {
1769 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
1770 }
1771
1772 if (Result != NULL) {
1773 FreePool (Result);
1774 }
1775 }
1776
1777 return Status;
1778 }
1779
1780
1781 /**
1782 Save Question Value to edit copy(cached) or Storage(uncached).
1783
1784 @param FormSet FormSet data structure.
1785 @param Form Form data structure.
1786 @param Question Pointer to the Question.
1787 @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
1788
1789 @retval EFI_SUCCESS The function completed successfully.
1790
1791 **/
1792 EFI_STATUS
1793 SetQuestionValue (
1794 IN FORM_BROWSER_FORMSET *FormSet,
1795 IN FORM_BROWSER_FORM *Form,
1796 IN OUT FORM_BROWSER_STATEMENT *Question,
1797 IN GET_SET_QUESTION_VALUE_WITH SetValueTo
1798 )
1799 {
1800 EFI_STATUS Status;
1801 BOOLEAN Enabled;
1802 BOOLEAN Pending;
1803 UINT8 *Src;
1804 EFI_TIME EfiTime;
1805 UINTN BufferLen;
1806 UINTN StorageWidth;
1807 BROWSER_STORAGE *Storage;
1808 FORMSET_STORAGE *FormsetStorage;
1809 EFI_IFR_TYPE_VALUE *QuestionValue;
1810 CHAR16 *ConfigResp;
1811 CHAR16 *Progress;
1812 CHAR16 *Value;
1813 UINTN Length;
1814 BOOLEAN IsBufferStorage;
1815 BOOLEAN IsString;
1816 UINT8 *TemBuffer;
1817 CHAR16 *TemName;
1818 CHAR16 *TemString;
1819 UINTN Index;
1820 NAME_VALUE_NODE *Node;
1821
1822 Status = EFI_SUCCESS;
1823 Node = NULL;
1824
1825 if (SetValueTo >= GetSetValueWithMax) {
1826 return EFI_INVALID_PARAMETER;
1827 }
1828
1829 //
1830 // If Question value is provided by an Expression, then it is read only
1831 //
1832 if (Question->ValueExpression != NULL) {
1833 return Status;
1834 }
1835
1836 //
1837 // Before set question value, evaluate its write expression.
1838 //
1839 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1840 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
1841 if (EFI_ERROR (Status)) {
1842 return Status;
1843 }
1844 }
1845
1846 //
1847 // Question value is provided by RTC
1848 //
1849 Storage = Question->Storage;
1850 QuestionValue = &Question->HiiValue.Value;
1851 if (Storage == NULL) {
1852 //
1853 // It's a Question without storage, or RTC date/time
1854 //
1855 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1856 //
1857 // Date and time define the same Flags bit
1858 //
1859 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1860 case QF_DATE_STORAGE_TIME:
1861 Status = gRT->GetTime (&EfiTime, NULL);
1862 break;
1863
1864 case QF_DATE_STORAGE_WAKEUP:
1865 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1866 break;
1867
1868 case QF_DATE_STORAGE_NORMAL:
1869 default:
1870 //
1871 // For date/time without storage
1872 //
1873 return EFI_SUCCESS;
1874 }
1875
1876 if (EFI_ERROR (Status)) {
1877 return Status;
1878 }
1879
1880 if (Question->Operand == EFI_IFR_DATE_OP) {
1881 EfiTime.Year = QuestionValue->date.Year;
1882 EfiTime.Month = QuestionValue->date.Month;
1883 EfiTime.Day = QuestionValue->date.Day;
1884 } else {
1885 EfiTime.Hour = QuestionValue->time.Hour;
1886 EfiTime.Minute = QuestionValue->time.Minute;
1887 EfiTime.Second = QuestionValue->time.Second;
1888 }
1889
1890 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
1891 Status = gRT->SetTime (&EfiTime);
1892 } else {
1893 Status = gRT->SetWakeupTime (TRUE, &EfiTime);
1894 }
1895 }
1896
1897 return Status;
1898 }
1899
1900 //
1901 // Question value is provided by EFI variable
1902 //
1903 StorageWidth = Question->StorageWidth;
1904 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1905 if (Question->BufferValue != NULL) {
1906 Src = Question->BufferValue;
1907 } else {
1908 Src = (UINT8 *) QuestionValue;
1909 }
1910
1911 Status = gRT->SetVariable (
1912 Question->VariableName,
1913 &Storage->Guid,
1914 Storage->Attributes,
1915 StorageWidth,
1916 Src
1917 );
1918 return Status;
1919 }
1920
1921 //
1922 // Question Value is provided by Buffer Storage or NameValue Storage
1923 //
1924 if (Question->BufferValue != NULL) {
1925 Src = Question->BufferValue;
1926 } else {
1927 Src = (UINT8 *) &Question->HiiValue.Value;
1928 }
1929
1930 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1931 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1932 IsBufferStorage = TRUE;
1933 } else {
1934 IsBufferStorage = FALSE;
1935 }
1936 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1937
1938 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
1939 if (IsBufferStorage) {
1940 if (SetValueTo == GetSetValueWithEditBuffer) {
1941 //
1942 // Copy to storage edit buffer
1943 //
1944 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1945 } else if (SetValueTo == GetSetValueWithBuffer) {
1946 //
1947 // Copy to storage edit buffer
1948 //
1949 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1950 }
1951 } else {
1952 if (IsString) {
1953 //
1954 // Allocate enough string buffer.
1955 //
1956 Value = NULL;
1957 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
1958 Value = AllocateZeroPool (BufferLen);
1959 ASSERT (Value != NULL);
1960 //
1961 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1962 //
1963 TemName = (CHAR16 *) Src;
1964 TemString = Value;
1965 for (; *TemName != L'\0'; TemName++) {
1966 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1967 }
1968 } else {
1969 BufferLen = StorageWidth * 2 + 1;
1970 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
1971 ASSERT (Value != NULL);
1972 //
1973 // Convert Buffer to Hex String
1974 //
1975 TemBuffer = Src + StorageWidth - 1;
1976 TemString = Value;
1977 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1978 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1979 }
1980 }
1981
1982 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
1983 FreePool (Value);
1984 if (EFI_ERROR (Status)) {
1985 return Status;
1986 }
1987 }
1988 } else if (SetValueTo == GetSetValueWithHiiDriver) {
1989 //
1990 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
1991 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
1992 //
1993 if (IsBufferStorage) {
1994 Length = StrLen (Question->BlockName) + 7;
1995 } else {
1996 Length = StrLen (Question->VariableName) + 2;
1997 }
1998 if (!IsBufferStorage && IsString) {
1999 Length += (StrLen ((CHAR16 *) Src) * 4);
2000 } else {
2001 Length += (StorageWidth * 2);
2002 }
2003 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
2004 ASSERT (FormsetStorage != NULL);
2005 ConfigResp = AllocateZeroPool ((StrLen (FormsetStorage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
2006 ASSERT (ConfigResp != NULL);
2007
2008 StrCpy (ConfigResp, FormsetStorage->ConfigHdr);
2009 if (IsBufferStorage) {
2010 StrCat (ConfigResp, Question->BlockName);
2011 StrCat (ConfigResp, L"&VALUE=");
2012 } else {
2013 StrCat (ConfigResp, L"&");
2014 StrCat (ConfigResp, Question->VariableName);
2015 StrCat (ConfigResp, L"=");
2016 }
2017
2018 Value = ConfigResp + StrLen (ConfigResp);
2019
2020 if (!IsBufferStorage && IsString) {
2021 //
2022 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
2023 //
2024 TemName = (CHAR16 *) Src;
2025 TemString = Value;
2026 for (; *TemName != L'\0'; TemName++) {
2027 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
2028 }
2029 } else {
2030 //
2031 // Convert Buffer to Hex String
2032 //
2033 TemBuffer = Src + StorageWidth - 1;
2034 TemString = Value;
2035 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
2036 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
2037 }
2038 }
2039
2040 //
2041 // Convert to lower char.
2042 //
2043 for (TemString = Value; *Value != L'\0'; Value++) {
2044 if (*Value >= L'A' && *Value <= L'Z') {
2045 *Value = (CHAR16) (*Value - L'A' + L'a');
2046 }
2047 }
2048
2049 //
2050 // Submit Question Value to Configuration Driver
2051 //
2052 Status = mHiiConfigRouting->RouteConfig (
2053 mHiiConfigRouting,
2054 ConfigResp,
2055 &Progress
2056 );
2057 if (EFI_ERROR (Status)) {
2058 FreePool (ConfigResp);
2059 return Status;
2060 }
2061 FreePool (ConfigResp);
2062
2063 //
2064 // Sync storage, from editbuffer to buffer.
2065 //
2066 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
2067 }
2068
2069 return Status;
2070 }
2071
2072
2073 /**
2074 Perform nosubmitif check for a Form.
2075
2076 @param FormSet FormSet data structure.
2077 @param Form Form data structure.
2078 @param Question The Question to be validated.
2079 @param Type Validation type: NoSubmit
2080
2081 @retval EFI_SUCCESS Form validation pass.
2082 @retval other Form validation failed.
2083
2084 **/
2085 EFI_STATUS
2086 ValidateQuestion (
2087 IN FORM_BROWSER_FORMSET *FormSet,
2088 IN FORM_BROWSER_FORM *Form,
2089 IN FORM_BROWSER_STATEMENT *Question,
2090 IN UINTN Type
2091 )
2092 {
2093 EFI_STATUS Status;
2094 LIST_ENTRY *Link;
2095 LIST_ENTRY *ListHead;
2096 FORM_EXPRESSION *Expression;
2097 UINT32 BrowserStatus;
2098 CHAR16 *ErrorStr;
2099
2100 BrowserStatus = BROWSER_SUCCESS;
2101 ErrorStr = NULL;
2102
2103 switch (Type) {
2104 case EFI_HII_EXPRESSION_INCONSISTENT_IF:
2105 ListHead = &Question->InconsistentListHead;
2106 break;
2107
2108 case EFI_HII_EXPRESSION_WARNING_IF:
2109 ListHead = &Question->WarningListHead;
2110 break;
2111
2112 case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
2113 ListHead = &Question->NoSubmitListHead;
2114 break;
2115
2116 default:
2117 ASSERT (FALSE);
2118 return EFI_UNSUPPORTED;
2119 }
2120
2121 Link = GetFirstNode (ListHead);
2122 while (!IsNull (ListHead, Link)) {
2123 Expression = FORM_EXPRESSION_FROM_LINK (Link);
2124
2125 //
2126 // Evaluate the expression
2127 //
2128 Status = EvaluateExpression (FormSet, Form, Expression);
2129 if (EFI_ERROR (Status)) {
2130 return Status;
2131 }
2132
2133 if (IsTrue (&Expression->Result)) {
2134 switch (Type) {
2135 case EFI_HII_EXPRESSION_INCONSISTENT_IF:
2136 BrowserStatus = BROWSER_INCONSISTENT_IF;
2137 break;
2138
2139 case EFI_HII_EXPRESSION_WARNING_IF:
2140 BrowserStatus = BROWSER_WARNING_IF;
2141 break;
2142
2143 case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
2144 BrowserStatus = BROWSER_NO_SUBMIT_IF;
2145 //
2146 // This code only used to compatible with old display engine,
2147 // New display engine will not use this field.
2148 //
2149 if (Expression->Error != 0) {
2150 ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);
2151 }
2152 break;
2153
2154 default:
2155 ASSERT (FALSE);
2156 break;
2157 }
2158
2159 if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {
2160 //
2161 // If in system submit process and for no_submit_if check, not popup this error message.
2162 // Will process this fail again later in not system submit process.
2163 //
2164 PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);
2165 }
2166
2167 if (ErrorStr != NULL) {
2168 FreePool (ErrorStr);
2169 }
2170
2171 if (Type == EFI_HII_EXPRESSION_WARNING_IF) {
2172 return EFI_SUCCESS;
2173 } else {
2174 return EFI_NOT_READY;
2175 }
2176 }
2177
2178 Link = GetNextNode (ListHead, Link);
2179 }
2180
2181 return EFI_SUCCESS;
2182 }
2183
2184 /**
2185 Perform question check.
2186
2187 If one question has more than one check, process form high priority to low.
2188 Only one error info will be popup.
2189
2190 @param FormSet FormSet data structure.
2191 @param Form Form data structure.
2192 @param Question The Question to be validated.
2193
2194 @retval EFI_SUCCESS Form validation pass.
2195 @retval other Form validation failed.
2196
2197 **/
2198 EFI_STATUS
2199 ValueChangedValidation (
2200 IN FORM_BROWSER_FORMSET *FormSet,
2201 IN FORM_BROWSER_FORM *Form,
2202 IN FORM_BROWSER_STATEMENT *Question
2203 )
2204 {
2205 EFI_STATUS Status;
2206
2207 Status = EFI_SUCCESS;
2208
2209 //
2210 // Do the inconsistentif check.
2211 //
2212 if (!IsListEmpty (&Question->InconsistentListHead)) {
2213 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
2214 if (EFI_ERROR (Status)) {
2215 return Status;
2216 }
2217 }
2218
2219 //
2220 // Do the warningif check.
2221 //
2222 if (!IsListEmpty (&Question->WarningListHead)) {
2223 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);
2224 }
2225
2226 return Status;
2227 }
2228
2229 /**
2230 Perform NoSubmit check for each Form in FormSet.
2231
2232 @param FormSet FormSet data structure.
2233 @param CurrentForm Current input form data structure.
2234 @param Statement The statement for this check.
2235
2236 @retval EFI_SUCCESS Form validation pass.
2237 @retval other Form validation failed.
2238
2239 **/
2240 EFI_STATUS
2241 NoSubmitCheck (
2242 IN FORM_BROWSER_FORMSET *FormSet,
2243 IN OUT FORM_BROWSER_FORM **CurrentForm,
2244 OUT FORM_BROWSER_STATEMENT **Statement
2245 )
2246 {
2247 EFI_STATUS Status;
2248 LIST_ENTRY *Link;
2249 FORM_BROWSER_STATEMENT *Question;
2250 FORM_BROWSER_FORM *Form;
2251 LIST_ENTRY *LinkForm;
2252
2253 LinkForm = GetFirstNode (&FormSet->FormListHead);
2254 while (!IsNull (&FormSet->FormListHead, LinkForm)) {
2255 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
2256 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
2257
2258 if (*CurrentForm != NULL && *CurrentForm != Form) {
2259 continue;
2260 }
2261
2262 Link = GetFirstNode (&Form->StatementListHead);
2263 while (!IsNull (&Form->StatementListHead, Link)) {
2264 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2265 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
2266 if (EFI_ERROR (Status)) {
2267 if (*CurrentForm == NULL) {
2268 *CurrentForm = Form;
2269 }
2270 if (Statement != NULL) {
2271 *Statement = Question;
2272 }
2273 return Status;
2274 }
2275
2276 Link = GetNextNode (&Form->StatementListHead, Link);
2277 }
2278 }
2279
2280 return EFI_SUCCESS;
2281 }
2282
2283 /**
2284 Fill storage's edit copy with settings requested from Configuration Driver.
2285
2286 @param Storage The storage which need to sync.
2287 @param ConfigRequest The config request string which used to sync storage.
2288 @param SyncOrRestore Sync the buffer to editbuffer or Restore the
2289 editbuffer to buffer
2290 if TRUE, copy the editbuffer to the buffer.
2291 if FALSE, copy the buffer to the editbuffer.
2292
2293 @retval EFI_SUCCESS The function completed successfully.
2294
2295 **/
2296 EFI_STATUS
2297 SynchronizeStorage (
2298 OUT BROWSER_STORAGE *Storage,
2299 IN CHAR16 *ConfigRequest,
2300 IN BOOLEAN SyncOrRestore
2301 )
2302 {
2303 EFI_STATUS Status;
2304 EFI_STRING Progress;
2305 EFI_STRING Result;
2306 UINTN BufferSize;
2307 LIST_ENTRY *Link;
2308 NAME_VALUE_NODE *Node;
2309 UINT8 *Src;
2310 UINT8 *Dst;
2311
2312 Status = EFI_SUCCESS;
2313 Result = NULL;
2314
2315 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2316 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2317 BufferSize = Storage->Size;
2318
2319 if (SyncOrRestore) {
2320 Src = Storage->EditBuffer;
2321 Dst = Storage->Buffer;
2322 } else {
2323 Src = Storage->Buffer;
2324 Dst = Storage->EditBuffer;
2325 }
2326
2327 if (ConfigRequest != NULL) {
2328 Status = mHiiConfigRouting->BlockToConfig(
2329 mHiiConfigRouting,
2330 ConfigRequest,
2331 Src,
2332 BufferSize,
2333 &Result,
2334 &Progress
2335 );
2336 if (EFI_ERROR (Status)) {
2337 return Status;
2338 }
2339
2340 Status = mHiiConfigRouting->ConfigToBlock (
2341 mHiiConfigRouting,
2342 Result,
2343 Dst,
2344 &BufferSize,
2345 &Progress
2346 );
2347 if (Result != NULL) {
2348 FreePool (Result);
2349 }
2350 } else {
2351 CopyMem (Dst, Src, BufferSize);
2352 }
2353 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2354 Link = GetFirstNode (&Storage->NameValueListHead);
2355 while (!IsNull (&Storage->NameValueListHead, Link)) {
2356 Node = NAME_VALUE_NODE_FROM_LINK (Link);
2357
2358 if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
2359 (ConfigRequest == NULL)) {
2360 if (SyncOrRestore) {
2361 NewStringCpy (&Node->Value, Node->EditValue);
2362 } else {
2363 NewStringCpy (&Node->EditValue, Node->Value);
2364 }
2365 }
2366
2367 Link = GetNextNode (&Storage->NameValueListHead, Link);
2368 }
2369 }
2370
2371 return Status;
2372 }
2373
2374 /**
2375 When discard the question value, call the callback function with Changed type
2376 to inform the hii driver.
2377
2378 @param FormSet FormSet data structure.
2379 @param Form Form data structure.
2380
2381 **/
2382 VOID
2383 SendDiscardInfoToDriver (
2384 IN FORM_BROWSER_FORMSET *FormSet,
2385 IN FORM_BROWSER_FORM *Form
2386 )
2387 {
2388 LIST_ENTRY *Link;
2389 FORM_BROWSER_STATEMENT *Question;
2390 EFI_IFR_TYPE_VALUE *TypeValue;
2391 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2392
2393 if (FormSet->ConfigAccess == NULL) {
2394 return;
2395 }
2396
2397 Link = GetFirstNode (&Form->StatementListHead);
2398 while (!IsNull (&Form->StatementListHead, Link)) {
2399 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2400 Link = GetNextNode (&Form->StatementListHead, Link);
2401
2402 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2403 continue;
2404 }
2405
2406 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2407 continue;
2408 }
2409
2410 if (Question->Operand == EFI_IFR_PASSWORD_OP) {
2411 continue;
2412 }
2413
2414 if (!Question->ValueChanged) {
2415 continue;
2416 }
2417
2418 //
2419 // Restore the question value before call the CHANGED callback type.
2420 //
2421 GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
2422
2423 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
2424 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
2425 } else {
2426 TypeValue = &Question->HiiValue.Value;
2427 }
2428
2429 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2430 FormSet->ConfigAccess->Callback (
2431 FormSet->ConfigAccess,
2432 EFI_BROWSER_ACTION_CHANGED,
2433 Question->QuestionId,
2434 Question->HiiValue.Type,
2435 TypeValue,
2436 &ActionRequest
2437 );
2438 }
2439 }
2440
2441 /**
2442 Validate the HiiHandle.
2443
2444 @param HiiHandle The input HiiHandle which need to validate.
2445
2446 @retval TRUE The handle is validate.
2447 @retval FALSE The handle is invalidate.
2448
2449 **/
2450 BOOLEAN
2451 ValidateHiiHandle (
2452 EFI_HII_HANDLE HiiHandle
2453 )
2454 {
2455 EFI_HII_HANDLE *HiiHandles;
2456 UINTN Index;
2457 BOOLEAN Find;
2458
2459 if (HiiHandle == NULL) {
2460 return FALSE;
2461 }
2462
2463 Find = FALSE;
2464
2465 HiiHandles = HiiGetHiiHandles (NULL);
2466 ASSERT (HiiHandles != NULL);
2467
2468 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
2469 if (HiiHandles[Index] == HiiHandle) {
2470 Find = TRUE;
2471 break;
2472 }
2473 }
2474
2475 FreePool (HiiHandles);
2476
2477 return Find;
2478 }
2479
2480 /**
2481 Validate the FormSet. If the formset is not validate, remove it from the list.
2482
2483 @param FormSet The input FormSet which need to validate.
2484
2485 @retval TRUE The handle is validate.
2486 @retval FALSE The handle is invalidate.
2487
2488 **/
2489 BOOLEAN
2490 ValidateFormSet (
2491 FORM_BROWSER_FORMSET *FormSet
2492 )
2493 {
2494 BOOLEAN Find;
2495
2496 ASSERT (FormSet != NULL);
2497
2498 Find = ValidateHiiHandle(FormSet->HiiHandle);
2499 //
2500 // Should not remove the formset which is being used.
2501 //
2502 if (!Find && (FormSet != gCurrentSelection->FormSet)) {
2503 CleanBrowserStorage(FormSet);
2504 RemoveEntryList (&FormSet->Link);
2505 DestroyFormSet (FormSet);
2506 }
2507
2508 return Find;
2509 }
2510 /**
2511 Check whether need to enable the reset flag in form level.
2512 Also clean all ValueChanged flag in question.
2513
2514 @param SetFlag Whether need to set the Reset Flag.
2515 @param FormSet FormSet data structure.
2516 @param Form Form data structure.
2517
2518 **/
2519 VOID
2520 UpdateFlagForForm (
2521 IN BOOLEAN SetFlag,
2522 IN FORM_BROWSER_FORMSET *FormSet,
2523 IN FORM_BROWSER_FORM *Form
2524 )
2525 {
2526 LIST_ENTRY *Link;
2527 FORM_BROWSER_STATEMENT *Question;
2528 BOOLEAN OldValue;
2529
2530 Link = GetFirstNode (&Form->StatementListHead);
2531 while (!IsNull (&Form->StatementListHead, Link)) {
2532 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2533 Link = GetNextNode (&Form->StatementListHead, Link);
2534
2535 if (!Question->ValueChanged) {
2536 continue;
2537 }
2538
2539 OldValue = Question->ValueChanged;
2540
2541 //
2542 // Compare the buffer and editbuffer data to see whether the data has been saved.
2543 //
2544 Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);
2545
2546 //
2547 // Only the changed data has been saved, then need to set the reset flag.
2548 //
2549 if (SetFlag && OldValue && !Question->ValueChanged) {
2550 if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
2551 gResetRequired = TRUE;
2552 }
2553
2554 if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
2555 gFlagReconnect = TRUE;
2556 }
2557 }
2558 }
2559 }
2560
2561 /**
2562 Check whether need to enable the reset flag.
2563 Also clean ValueChanged flag for all statements.
2564
2565 Form level or formset level, only one.
2566
2567 @param SetFlag Whether need to set the Reset Flag.
2568 @param FormSet FormSet data structure.
2569 @param Form Form data structure.
2570
2571 **/
2572 VOID
2573 ValueChangeResetFlagUpdate (
2574 IN BOOLEAN SetFlag,
2575 IN FORM_BROWSER_FORMSET *FormSet,
2576 IN FORM_BROWSER_FORM *Form
2577 )
2578 {
2579 FORM_BROWSER_FORM *CurrentForm;
2580 LIST_ENTRY *Link;
2581
2582 if (Form != NULL) {
2583 UpdateFlagForForm(SetFlag, FormSet, Form);
2584 return;
2585 }
2586
2587 Link = GetFirstNode (&FormSet->FormListHead);
2588 while (!IsNull (&FormSet->FormListHead, Link)) {
2589 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
2590 Link = GetNextNode (&FormSet->FormListHead, Link);
2591
2592 UpdateFlagForForm(SetFlag, FormSet, CurrentForm);
2593 }
2594 }
2595
2596 /**
2597 Base on the return Progress string to find the form.
2598
2599 Base on the first return Offset/Width (Name) string to find the form
2600 which keep this string.
2601
2602 @param FormSet FormSet data structure.
2603 @param Storage Storage which has this Progress string.
2604 @param Progress The Progress string which has the first fail string.
2605 @param RetForm The return form for this progress string.
2606 @param RetQuestion The return question for the error progress string.
2607
2608 @retval TRUE Find the error form and statement for this error progress string.
2609 @retval FALSE Not find the error form.
2610
2611 **/
2612 BOOLEAN
2613 FindQuestionFromProgress (
2614 IN FORM_BROWSER_FORMSET *FormSet,
2615 IN BROWSER_STORAGE *Storage,
2616 IN EFI_STRING Progress,
2617 OUT FORM_BROWSER_FORM **RetForm,
2618 OUT FORM_BROWSER_STATEMENT **RetQuestion
2619 )
2620 {
2621 LIST_ENTRY *Link;
2622 LIST_ENTRY *LinkStorage;
2623 LIST_ENTRY *LinkStatement;
2624 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2625 FORM_BROWSER_FORM *Form;
2626 EFI_STRING EndStr;
2627 FORM_BROWSER_STATEMENT *Statement;
2628
2629 ASSERT ((*Progress == '&') || (*Progress == 'G'));
2630
2631 ConfigInfo = NULL;
2632 *RetForm = NULL;
2633 *RetQuestion = NULL;
2634
2635 //
2636 // Skip the first "&" or the ConfigHdr part.
2637 //
2638 if (*Progress == '&') {
2639 Progress++;
2640 } else {
2641 //
2642 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2643 //
2644 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2645 //
2646 // For Name/Value type, Skip the ConfigHdr part.
2647 //
2648 EndStr = StrStr (Progress, L"PATH=");
2649 ASSERT (EndStr != NULL);
2650 while (*EndStr != '&') {
2651 EndStr++;
2652 }
2653
2654 *EndStr = '\0';
2655 } else {
2656 //
2657 // For Buffer type, Skip the ConfigHdr part.
2658 //
2659 EndStr = StrStr (Progress, L"&OFFSET=");
2660 ASSERT (EndStr != NULL);
2661 *EndStr = '\0';
2662 }
2663
2664 Progress = EndStr + 1;
2665 }
2666
2667 //
2668 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2669 //
2670 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2671 //
2672 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
2673 // here, just keep the "Fred" string.
2674 //
2675 EndStr = StrStr (Progress, L"=");
2676 ASSERT (EndStr != NULL);
2677 *EndStr = '\0';
2678 } else {
2679 //
2680 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
2681 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
2682 //
2683 EndStr = StrStr (Progress, L"&VALUE=");
2684 ASSERT (EndStr != NULL);
2685 *EndStr = '\0';
2686 }
2687
2688 //
2689 // Search in the form list.
2690 //
2691 Link = GetFirstNode (&FormSet->FormListHead);
2692 while (!IsNull (&FormSet->FormListHead, Link)) {
2693 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2694 Link = GetNextNode (&FormSet->FormListHead, Link);
2695
2696 //
2697 // Search in the ConfigReqeust list in this form.
2698 //
2699 LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
2700 while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
2701 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
2702 LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
2703
2704 if (Storage != ConfigInfo->Storage) {
2705 continue;
2706 }
2707
2708 if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
2709 //
2710 // Find the OffsetWidth string in this form.
2711 //
2712 *RetForm = Form;
2713 break;
2714 }
2715 }
2716
2717 if (*RetForm != NULL) {
2718 LinkStatement = GetFirstNode (&Form->StatementListHead);
2719 while (!IsNull (&Form->StatementListHead, LinkStatement)) {
2720 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
2721 LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
2722
2723 if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {
2724 *RetQuestion = Statement;
2725 break;
2726 }
2727
2728 if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) {
2729 *RetQuestion = Statement;
2730 break;
2731 }
2732 }
2733 }
2734
2735 if (*RetForm != NULL) {
2736 break;
2737 }
2738 }
2739
2740 //
2741 // restore the OffsetWidth string to the original format.
2742 //
2743 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2744 *EndStr = '=';
2745 } else {
2746 *EndStr = '&';
2747 }
2748
2749 return (BOOLEAN) (*RetForm != NULL);
2750 }
2751
2752 /**
2753 Popup an save error info and get user input.
2754
2755 @param TitleId The form title id.
2756 @param HiiHandle The hii handle for this package.
2757
2758 @retval UINT32 The user select option for the save fail.
2759 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
2760 **/
2761 UINT32
2762 ConfirmSaveFail (
2763 IN EFI_STRING_ID TitleId,
2764 IN EFI_HII_HANDLE HiiHandle
2765 )
2766 {
2767 CHAR16 *FormTitle;
2768 CHAR16 *StringBuffer;
2769 UINT32 RetVal;
2770
2771 FormTitle = GetToken (TitleId, HiiHandle);
2772
2773 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
2774 ASSERT (StringBuffer != NULL);
2775
2776 UnicodeSPrint (
2777 StringBuffer,
2778 24 * sizeof (CHAR16) + StrSize (FormTitle),
2779 L"Submit Fail For Form: %s.",
2780 FormTitle
2781 );
2782
2783 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
2784
2785 FreePool (StringBuffer);
2786 FreePool (FormTitle);
2787
2788 return RetVal;
2789 }
2790
2791 /**
2792 Popup an NO_SUBMIT_IF error info and get user input.
2793
2794 @param TitleId The form title id.
2795 @param HiiHandle The hii handle for this package.
2796
2797 @retval UINT32 The user select option for the save fail.
2798 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
2799 **/
2800 UINT32
2801 ConfirmNoSubmitFail (
2802 IN EFI_STRING_ID TitleId,
2803 IN EFI_HII_HANDLE HiiHandle
2804 )
2805 {
2806 CHAR16 *FormTitle;
2807 CHAR16 *StringBuffer;
2808 UINT32 RetVal;
2809
2810 FormTitle = GetToken (TitleId, HiiHandle);
2811
2812 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
2813 ASSERT (StringBuffer != NULL);
2814
2815 UnicodeSPrint (
2816 StringBuffer,
2817 24 * sizeof (CHAR16) + StrSize (FormTitle),
2818 L"NO_SUBMIT_IF error For Form: %s.",
2819 FormTitle
2820 );
2821
2822 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
2823
2824 FreePool (StringBuffer);
2825 FreePool (FormTitle);
2826
2827 return RetVal;
2828 }
2829
2830 /**
2831 Discard data based on the input setting scope (Form, FormSet or System).
2832
2833 @param FormSet FormSet data structure.
2834 @param Form Form data structure.
2835 @param SettingScope Setting Scope for Discard action.
2836
2837 @retval EFI_SUCCESS The function completed successfully.
2838 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2839
2840 **/
2841 EFI_STATUS
2842 DiscardForm (
2843 IN FORM_BROWSER_FORMSET *FormSet,
2844 IN FORM_BROWSER_FORM *Form,
2845 IN BROWSER_SETTING_SCOPE SettingScope
2846 )
2847 {
2848 LIST_ENTRY *Link;
2849 FORMSET_STORAGE *Storage;
2850 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2851 FORM_BROWSER_FORMSET *LocalFormSet;
2852 FORM_BROWSER_FORMSET *OldFormSet;
2853
2854 //
2855 // Check the supported setting level.
2856 //
2857 if (SettingScope >= MaxLevel) {
2858 return EFI_UNSUPPORTED;
2859 }
2860
2861 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
2862 ConfigInfo = NULL;
2863 Link = GetFirstNode (&Form->ConfigRequestHead);
2864 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2865 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2866 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2867
2868 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2869 continue;
2870 }
2871
2872 //
2873 // Skip if there is no RequestElement
2874 //
2875 if (ConfigInfo->ElementCount == 0) {
2876 continue;
2877 }
2878
2879 //
2880 // Prepare <ConfigResp>
2881 //
2882 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
2883
2884 //
2885 // Call callback with Changed type to inform the driver.
2886 //
2887 SendDiscardInfoToDriver (FormSet, Form);
2888 }
2889
2890 ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
2891 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
2892
2893 //
2894 // Discard Buffer storage or Name/Value storage
2895 //
2896 Link = GetFirstNode (&FormSet->StorageListHead);
2897 while (!IsNull (&FormSet->StorageListHead, Link)) {
2898 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2899 Link = GetNextNode (&FormSet->StorageListHead, Link);
2900
2901 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2902 continue;
2903 }
2904
2905 //
2906 // Skip if there is no RequestElement
2907 //
2908 if (Storage->ElementCount == 0) {
2909 continue;
2910 }
2911
2912 SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
2913 }
2914
2915 Link = GetFirstNode (&FormSet->FormListHead);
2916 while (!IsNull (&FormSet->FormListHead, Link)) {
2917 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2918 Link = GetNextNode (&FormSet->FormListHead, Link);
2919
2920 //
2921 // Call callback with Changed type to inform the driver.
2922 //
2923 SendDiscardInfoToDriver (FormSet, Form);
2924 }
2925
2926 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
2927 } else if (SettingScope == SystemLevel) {
2928 //
2929 // System Level Discard.
2930 //
2931 OldFormSet = mSystemLevelFormSet;
2932
2933 //
2934 // Discard changed value for each FormSet in the maintain list.
2935 //
2936 Link = GetFirstNode (&gBrowserFormSetList);
2937 while (!IsNull (&gBrowserFormSetList, Link)) {
2938 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2939 Link = GetNextNode (&gBrowserFormSetList, Link);
2940 if (!ValidateFormSet(LocalFormSet)) {
2941 continue;
2942 }
2943
2944 mSystemLevelFormSet = LocalFormSet;
2945
2946 DiscardForm (LocalFormSet, NULL, FormSetLevel);
2947 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2948 //
2949 // Remove maintain backup list after discard except for the current using FormSet.
2950 //
2951 CleanBrowserStorage(LocalFormSet);
2952 RemoveEntryList (&LocalFormSet->Link);
2953 DestroyFormSet (LocalFormSet);
2954 }
2955 }
2956
2957 mSystemLevelFormSet = OldFormSet;
2958 }
2959
2960 return EFI_SUCCESS;
2961 }
2962
2963 /**
2964 Submit data for a form.
2965
2966 @param FormSet FormSet data structure.
2967 @param Form Form data structure.
2968
2969 @retval EFI_SUCCESS The function completed successfully.
2970 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2971
2972 **/
2973 EFI_STATUS
2974 SubmitForForm (
2975 IN FORM_BROWSER_FORMSET *FormSet,
2976 IN FORM_BROWSER_FORM *Form
2977 )
2978 {
2979 EFI_STATUS Status;
2980 LIST_ENTRY *Link;
2981 EFI_STRING ConfigResp;
2982 EFI_STRING Progress;
2983 BROWSER_STORAGE *Storage;
2984 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2985
2986 if (!IsNvUpdateRequiredForForm (Form)) {
2987 return EFI_SUCCESS;
2988 }
2989
2990 Status = NoSubmitCheck (FormSet, &Form, NULL);
2991 if (EFI_ERROR (Status)) {
2992 return Status;
2993 }
2994
2995 Link = GetFirstNode (&Form->ConfigRequestHead);
2996 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2997 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2998 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2999
3000 Storage = ConfigInfo->Storage;
3001 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3002 continue;
3003 }
3004
3005 //
3006 // Skip if there is no RequestElement
3007 //
3008 if (ConfigInfo->ElementCount == 0) {
3009 continue;
3010 }
3011
3012 //
3013 // 1. Prepare <ConfigResp>
3014 //
3015 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
3016 if (EFI_ERROR (Status)) {
3017 return Status;
3018 }
3019
3020 //
3021 // 2. Set value to hii config routine protocol.
3022 //
3023 Status = mHiiConfigRouting->RouteConfig (
3024 mHiiConfigRouting,
3025 ConfigResp,
3026 &Progress
3027 );
3028 FreePool (ConfigResp);
3029
3030 if (EFI_ERROR (Status)) {
3031 InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
3032 continue;
3033 }
3034
3035 //
3036 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
3037 //
3038 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
3039 }
3040
3041 //
3042 // 4. Process the save failed storage.
3043 //
3044 if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3045 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
3046 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3047 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
3048 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
3049 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
3050
3051 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
3052
3053 Status = EFI_SUCCESS;
3054 }
3055 } else {
3056 Status = EFI_UNSUPPORTED;
3057 }
3058
3059 //
3060 // Free Form save fail list.
3061 //
3062 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3063 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3064 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
3065 RemoveEntryList (&ConfigInfo->SaveFailLink);
3066 }
3067 }
3068
3069 //
3070 // 5. Update the NV flag.
3071 //
3072 ValueChangeResetFlagUpdate(TRUE, FormSet, Form);
3073
3074 return Status;
3075 }
3076
3077 /**
3078 Submit data for a formset.
3079
3080 @param FormSet FormSet data structure.
3081 @param SkipProcessFail Whether skip to process the save failed storage.
3082 If submit formset is called when do system level save,
3083 set this value to true and process the failed formset
3084 together.
3085 if submit formset is called when do formset level save,
3086 set the value to false and process the failed storage
3087 right after process all storages for this formset.
3088
3089 @retval EFI_SUCCESS The function completed successfully.
3090 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3091
3092 **/
3093 EFI_STATUS
3094 SubmitForFormSet (
3095 IN FORM_BROWSER_FORMSET *FormSet,
3096 IN BOOLEAN SkipProcessFail
3097 )
3098 {
3099 EFI_STATUS Status;
3100 LIST_ENTRY *Link;
3101 EFI_STRING ConfigResp;
3102 EFI_STRING Progress;
3103 BROWSER_STORAGE *Storage;
3104 FORMSET_STORAGE *FormSetStorage;
3105 FORM_BROWSER_FORM *Form;
3106 BOOLEAN HasInserted;
3107 FORM_BROWSER_STATEMENT *Question;
3108
3109 HasInserted = FALSE;
3110
3111 if (!IsNvUpdateRequiredForFormSet (FormSet)) {
3112 return EFI_SUCCESS;
3113 }
3114
3115 Form = NULL;
3116 Status = NoSubmitCheck (FormSet, &Form, &Question);
3117 if (EFI_ERROR (Status)) {
3118 if (SkipProcessFail) {
3119 //
3120 // Process NO_SUBMIT check first, so insert it at head.
3121 //
3122 FormSet->SaveFailForm = Form;
3123 FormSet->SaveFailStatement = Question;
3124 InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
3125 }
3126
3127 return Status;
3128 }
3129
3130 Form = NULL;
3131 Question = NULL;
3132 //
3133 // Submit Buffer storage or Name/Value storage
3134 //
3135 Link = GetFirstNode (&FormSet->StorageListHead);
3136 while (!IsNull (&FormSet->StorageListHead, Link)) {
3137 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
3138 Storage = FormSetStorage->BrowserStorage;
3139 Link = GetNextNode (&FormSet->StorageListHead, Link);
3140
3141 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3142 continue;
3143 }
3144
3145 //
3146 // Skip if there is no RequestElement
3147 //
3148 if (FormSetStorage->ElementCount == 0) {
3149 continue;
3150 }
3151
3152 //
3153 // 1. Prepare <ConfigResp>
3154 //
3155 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
3156 if (EFI_ERROR (Status)) {
3157 return Status;
3158 }
3159
3160 //
3161 // 2. Send <ConfigResp> to Routine config Protocol.
3162 //
3163 Status = mHiiConfigRouting->RouteConfig (
3164 mHiiConfigRouting,
3165 ConfigResp,
3166 &Progress
3167 );
3168 if (EFI_ERROR (Status)) {
3169 InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
3170 if (!HasInserted) {
3171 //
3172 // Call submit formset for system level, save the formset info
3173 // and process later.
3174 //
3175 FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);
3176 ASSERT (Form != NULL && Question != NULL);
3177 FormSet->SaveFailForm = Form;
3178 FormSet->SaveFailStatement = Question;
3179 if (SkipProcessFail) {
3180 InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
3181 }
3182 HasInserted = TRUE;
3183 }
3184
3185 FreePool (ConfigResp);
3186 continue;
3187 }
3188
3189 FreePool (ConfigResp);
3190 //
3191 // 3. Config success, update storage shadow Buffer
3192 //
3193 SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
3194 }
3195
3196 //
3197 // 4. Has save fail storage need to handle.
3198 //
3199 if (Form != NULL) {
3200 if (!SkipProcessFail) {
3201 //
3202 // If not in system level, just handl the save failed storage here.
3203 //
3204 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
3205 Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
3206 while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
3207 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
3208 Storage = FormSetStorage->BrowserStorage;
3209 Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
3210
3211 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3212
3213 Status = EFI_SUCCESS;
3214 }
3215 } else {
3216 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
3217
3218 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
3219 gCurrentSelection->Handle = FormSet->HiiHandle;
3220 CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
3221 gCurrentSelection->FormId = Form->FormId;
3222 gCurrentSelection->QuestionId = Question->QuestionId;
3223
3224 Status = EFI_UNSUPPORTED;
3225 }
3226
3227 //
3228 // Free FormSet save fail list.
3229 //
3230 while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
3231 Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
3232 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
3233 RemoveEntryList (&FormSetStorage->SaveFailLink);
3234 }
3235 } else {
3236 //
3237 // If in system level, just return error and handle the failed formset later.
3238 //
3239 Status = EFI_UNSUPPORTED;
3240 }
3241 }
3242
3243 //
3244 // 5. Update the NV flag.
3245 //
3246 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
3247
3248 return Status;
3249 }
3250
3251 /**
3252 Submit data for all formsets.
3253
3254 @retval EFI_SUCCESS The function completed successfully.
3255 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3256
3257 **/
3258 EFI_STATUS
3259 SubmitForSystem (
3260 VOID
3261 )
3262 {
3263 EFI_STATUS Status;
3264 LIST_ENTRY *Link;
3265 LIST_ENTRY *StorageLink;
3266 FORMSET_STORAGE *FormSetStorage;
3267 FORM_BROWSER_FORM *Form;
3268 FORM_BROWSER_FORMSET *LocalFormSet;
3269 UINT32 UserSelection;
3270 FORM_BROWSER_STATEMENT *Question;
3271
3272 mSystemSubmit = TRUE;
3273 Link = GetFirstNode (&gBrowserFormSetList);
3274 while (!IsNull (&gBrowserFormSetList, Link)) {
3275 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3276 Link = GetNextNode (&gBrowserFormSetList, Link);
3277 if (!ValidateFormSet(LocalFormSet)) {
3278 continue;
3279 }
3280
3281 Status = SubmitForFormSet (LocalFormSet, TRUE);
3282 if (EFI_ERROR (Status)) {
3283 continue;
3284 }
3285
3286 //
3287 // Remove maintain backup list after save except for the current using FormSet.
3288 //
3289 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3290 CleanBrowserStorage(LocalFormSet);
3291 RemoveEntryList (&LocalFormSet->Link);
3292 DestroyFormSet (LocalFormSet);
3293 }
3294 }
3295 mSystemSubmit = FALSE;
3296
3297 Status = EFI_SUCCESS;
3298
3299 //
3300 // Process the save failed formsets.
3301 //
3302 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3303 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
3304 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
3305 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
3306
3307 if (!ValidateFormSet(LocalFormSet)) {
3308 continue;
3309 }
3310
3311 Form = LocalFormSet->SaveFailForm;
3312 Question= LocalFormSet->SaveFailStatement;
3313
3314 //
3315 // Confirm with user, get user input.
3316 //
3317 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3318 //
3319 // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
3320 //
3321 UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
3322 } else {
3323 UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
3324 }
3325
3326 if (UserSelection == BROWSER_ACTION_DISCARD) {
3327 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3328 StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
3329 while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
3330 FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
3331 StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
3332
3333 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3334 }
3335 } else {
3336 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
3337 while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
3338 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
3339 StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
3340
3341 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3342 }
3343 }
3344
3345 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3346 CleanBrowserStorage(LocalFormSet);
3347 RemoveEntryList (&LocalFormSet->Link);
3348 RemoveEntryList (&LocalFormSet->SaveFailLink);
3349 DestroyFormSet (LocalFormSet);
3350 } else {
3351 ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);
3352 }
3353 } else {
3354 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3355 NoSubmitCheck (LocalFormSet, &Form, &Question);
3356 }
3357
3358 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
3359
3360 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
3361 gCurrentSelection->Handle = LocalFormSet->HiiHandle;
3362 CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
3363 gCurrentSelection->FormId = Form->FormId;
3364 gCurrentSelection->QuestionId = Question->QuestionId;
3365
3366 Status = EFI_UNSUPPORTED;
3367 break;
3368 }
3369 }
3370
3371 //
3372 // Clean the list which will not process.
3373 //
3374 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3375 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3376 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
3377 RemoveEntryList (&LocalFormSet->SaveFailLink);
3378
3379 while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3380 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
3381 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
3382 RemoveEntryList (&FormSetStorage->SaveFailLink);
3383 }
3384 }
3385
3386 return Status;
3387 }
3388
3389 /**
3390 Submit data based on the input Setting level (Form, FormSet or System).
3391
3392 @param FormSet FormSet data structure.
3393 @param Form Form data structure.
3394 @param SettingScope Setting Scope for Submit action.
3395
3396 @retval EFI_SUCCESS The function completed successfully.
3397 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3398
3399 **/
3400 EFI_STATUS
3401 SubmitForm (
3402 IN FORM_BROWSER_FORMSET *FormSet,
3403 IN FORM_BROWSER_FORM *Form,
3404 IN BROWSER_SETTING_SCOPE SettingScope
3405 )
3406 {
3407 EFI_STATUS Status;
3408
3409 switch (SettingScope) {
3410 case FormLevel:
3411 Status = SubmitForForm(FormSet, Form);
3412 break;
3413
3414 case FormSetLevel:
3415 Status = SubmitForFormSet (FormSet, FALSE);
3416 break;
3417
3418 case SystemLevel:
3419 Status = SubmitForSystem ();
3420 break;
3421
3422 default:
3423 Status = EFI_UNSUPPORTED;
3424 break;
3425 }
3426
3427 return Status;
3428 }
3429
3430 /**
3431 Converts the unicode character of the string from uppercase to lowercase.
3432 This is a internal function.
3433
3434 @param ConfigString String to be converted
3435
3436 **/
3437 VOID
3438 EFIAPI
3439 HiiToLower (
3440 IN EFI_STRING ConfigString
3441 )
3442 {
3443 EFI_STRING String;
3444 BOOLEAN Lower;
3445
3446 ASSERT (ConfigString != NULL);
3447
3448 //
3449 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
3450 //
3451 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
3452 if (*String == L'=') {
3453 Lower = TRUE;
3454 } else if (*String == L'&') {
3455 Lower = FALSE;
3456 } else if (Lower && *String >= L'A' && *String <= L'F') {
3457 *String = (CHAR16) (*String - L'A' + L'a');
3458 }
3459 }
3460 }
3461
3462 /**
3463 Find the point in the ConfigResp string for this question.
3464
3465 @param Question The question.
3466 @param ConfigResp Get ConfigResp string.
3467
3468 @retval point to the offset where is for this question.
3469
3470 **/
3471 CHAR16 *
3472 GetOffsetFromConfigResp (
3473 IN FORM_BROWSER_STATEMENT *Question,
3474 IN CHAR16 *ConfigResp
3475 )
3476 {
3477 CHAR16 *RequestElement;
3478 CHAR16 *BlockData;
3479
3480 //
3481 // Type is EFI_HII_VARSTORE_NAME_VALUE.
3482 //
3483 if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3484 RequestElement = StrStr (ConfigResp, Question->VariableName);
3485 if (RequestElement != NULL) {
3486 //
3487 // Skip the "VariableName=" field.
3488 //
3489 RequestElement += StrLen (Question->VariableName) + 1;
3490 }
3491
3492 return RequestElement;
3493 }
3494
3495 //
3496 // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
3497 //
3498
3499 //
3500 // 1. Directly use Question->BlockName to find.
3501 //
3502 RequestElement = StrStr (ConfigResp, Question->BlockName);
3503 if (RequestElement != NULL) {
3504 //
3505 // Skip the "Question->BlockName&VALUE=" field.
3506 //
3507 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
3508 return RequestElement;
3509 }
3510
3511 //
3512 // 2. Change all hex digits in Question->BlockName to lower and compare again.
3513 //
3514 BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName);
3515 ASSERT (BlockData != NULL);
3516 HiiToLower (BlockData);
3517 RequestElement = StrStr (ConfigResp, BlockData);
3518 FreePool (BlockData);
3519
3520 if (RequestElement != NULL) {
3521 //
3522 // Skip the "Question->BlockName&VALUE=" field.
3523 //
3524 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
3525 }
3526
3527 return RequestElement;
3528 }
3529
3530 /**
3531 Get Question default value from AltCfg string.
3532
3533 @param FormSet The form set.
3534 @param Form The form
3535 @param Question The question.
3536
3537 @retval EFI_SUCCESS Question is reset to default value.
3538
3539 **/
3540 EFI_STATUS
3541 GetDefaultValueFromAltCfg (
3542 IN FORM_BROWSER_FORMSET *FormSet,
3543 IN FORM_BROWSER_FORM *Form,
3544 IN OUT FORM_BROWSER_STATEMENT *Question
3545 )
3546 {
3547 BROWSER_STORAGE *Storage;
3548 FORMSET_STORAGE *FormSetStorage;
3549 CHAR16 *ConfigResp;
3550 CHAR16 *Value;
3551 LIST_ENTRY *Link;
3552 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
3553
3554 Storage = Question->Storage;
3555 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
3556 return EFI_NOT_FOUND;
3557 }
3558
3559 //
3560 // Try to get AltCfg string from form. If not found it, then
3561 // try to get it from formset.
3562 //
3563 ConfigResp = NULL;
3564 Link = GetFirstNode (&Form->ConfigRequestHead);
3565 while (!IsNull (&Form->ConfigRequestHead, Link)) {
3566 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
3567 Link = GetNextNode (&Form->ConfigRequestHead, Link);
3568
3569 if (Storage == ConfigInfo->Storage) {
3570 ConfigResp = ConfigInfo->ConfigAltResp;
3571 break;
3572 }
3573 }
3574
3575 if (ConfigResp == NULL) {
3576 Link = GetFirstNode (&FormSet->StorageListHead);
3577 while (!IsNull (&FormSet->StorageListHead, Link)) {
3578 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
3579 Link = GetNextNode (&FormSet->StorageListHead, Link);
3580
3581 if (Storage == FormSetStorage->BrowserStorage) {
3582 ConfigResp = FormSetStorage->ConfigAltResp;
3583 break;
3584 }
3585 }
3586 }
3587
3588 if (ConfigResp == NULL) {
3589 return EFI_NOT_FOUND;
3590 }
3591
3592 Value = GetOffsetFromConfigResp (Question, ConfigResp);
3593 if (Value == NULL) {
3594 return EFI_NOT_FOUND;
3595 }
3596
3597 return BufferToValue (Question, Value);
3598 }
3599
3600 /**
3601 Get default Id value used for browser.
3602
3603 @param DefaultId The default id value used by hii.
3604
3605 @retval Browser used default value.
3606
3607 **/
3608 INTN
3609 GetDefaultIdForCallBack (
3610 UINTN DefaultId
3611 )
3612 {
3613 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
3614 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
3615 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3616 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
3617 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
3618 return EFI_BROWSER_ACTION_DEFAULT_SAFE;
3619 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
3620 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
3621 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
3622 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
3623 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
3624 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
3625 } else {
3626 return -1;
3627 }
3628 }
3629
3630
3631
3632 /**
3633 Return data element in an Array by its Index.
3634
3635 @param Array The data array.
3636 @param Type Type of the data in this array.
3637 @param Index Zero based index for data in this array.
3638
3639 @retval Value The data to be returned
3640
3641 **/
3642 UINT64
3643 GetArrayData (
3644 IN VOID *Array,
3645 IN UINT8 Type,
3646 IN UINTN Index
3647 )
3648 {
3649 UINT64 Data;
3650
3651 ASSERT (Array != NULL);
3652
3653 Data = 0;
3654 switch (Type) {
3655 case EFI_IFR_TYPE_NUM_SIZE_8:
3656 Data = (UINT64) *(((UINT8 *) Array) + Index);
3657 break;
3658
3659 case EFI_IFR_TYPE_NUM_SIZE_16:
3660 Data = (UINT64) *(((UINT16 *) Array) + Index);
3661 break;
3662
3663 case EFI_IFR_TYPE_NUM_SIZE_32:
3664 Data = (UINT64) *(((UINT32 *) Array) + Index);
3665 break;
3666
3667 case EFI_IFR_TYPE_NUM_SIZE_64:
3668 Data = (UINT64) *(((UINT64 *) Array) + Index);
3669 break;
3670
3671 default:
3672 break;
3673 }
3674
3675 return Data;
3676 }
3677
3678
3679 /**
3680 Set value of a data element in an Array by its Index.
3681
3682 @param Array The data array.
3683 @param Type Type of the data in this array.
3684 @param Index Zero based index for data in this array.
3685 @param Value The value to be set.
3686
3687 **/
3688 VOID
3689 SetArrayData (
3690 IN VOID *Array,
3691 IN UINT8 Type,
3692 IN UINTN Index,
3693 IN UINT64 Value
3694 )
3695 {
3696
3697 ASSERT (Array != NULL);
3698
3699 switch (Type) {
3700 case EFI_IFR_TYPE_NUM_SIZE_8:
3701 *(((UINT8 *) Array) + Index) = (UINT8) Value;
3702 break;
3703
3704 case EFI_IFR_TYPE_NUM_SIZE_16:
3705 *(((UINT16 *) Array) + Index) = (UINT16) Value;
3706 break;
3707
3708 case EFI_IFR_TYPE_NUM_SIZE_32:
3709 *(((UINT32 *) Array) + Index) = (UINT32) Value;
3710 break;
3711
3712 case EFI_IFR_TYPE_NUM_SIZE_64:
3713 *(((UINT64 *) Array) + Index) = (UINT64) Value;
3714 break;
3715
3716 default:
3717 break;
3718 }
3719 }
3720
3721 /**
3722 Search an Option of a Question by its value.
3723
3724 @param Question The Question
3725 @param OptionValue Value for Option to be searched.
3726
3727 @retval Pointer Pointer to the found Option.
3728 @retval NULL Option not found.
3729
3730 **/
3731 QUESTION_OPTION *
3732 ValueToOption (
3733 IN FORM_BROWSER_STATEMENT *Question,
3734 IN EFI_HII_VALUE *OptionValue
3735 )
3736 {
3737 LIST_ENTRY *Link;
3738 QUESTION_OPTION *Option;
3739 INTN Result;
3740
3741 Link = GetFirstNode (&Question->OptionListHead);
3742 while (!IsNull (&Question->OptionListHead, Link)) {
3743 Option = QUESTION_OPTION_FROM_LINK (Link);
3744
3745 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
3746 //
3747 // Check the suppressif condition, only a valid option can be return.
3748 //
3749 if ((Option->SuppressExpression == NULL) ||
3750 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
3751 return Option;
3752 }
3753 }
3754
3755 Link = GetNextNode (&Question->OptionListHead, Link);
3756 }
3757
3758 return NULL;
3759 }
3760
3761
3762 /**
3763 Reset Question to its default value.
3764
3765 @param FormSet The form set.
3766 @param Form The form.
3767 @param Question The question.
3768 @param DefaultId The Class of the default.
3769
3770 @retval EFI_SUCCESS Question is reset to default value.
3771
3772 **/
3773 EFI_STATUS
3774 GetQuestionDefault (
3775 IN FORM_BROWSER_FORMSET *FormSet,
3776 IN FORM_BROWSER_FORM *Form,
3777 IN FORM_BROWSER_STATEMENT *Question,
3778 IN UINT16 DefaultId
3779 )
3780 {
3781 EFI_STATUS Status;
3782 LIST_ENTRY *Link;
3783 QUESTION_DEFAULT *Default;
3784 QUESTION_OPTION *Option;
3785 EFI_HII_VALUE *HiiValue;
3786 UINT8 Index;
3787 EFI_STRING StrValue;
3788 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
3789 EFI_BROWSER_ACTION_REQUEST ActionRequest;
3790 INTN Action;
3791 CHAR16 *NewString;
3792
3793 Status = EFI_NOT_FOUND;
3794 StrValue = NULL;
3795
3796 //
3797 // Statement don't have storage, skip them
3798 //
3799 if (Question->QuestionId == 0) {
3800 return Status;
3801 }
3802
3803 //
3804 // There are Five ways to specify default value for a Question:
3805 // 1, use call back function (highest priority)
3806 // 2, use ExtractConfig function
3807 // 3, use nested EFI_IFR_DEFAULT
3808 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
3809 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
3810 //
3811 HiiValue = &Question->HiiValue;
3812
3813 //
3814 // Get Question defaut value from call back function.
3815 //
3816 ConfigAccess = FormSet->ConfigAccess;
3817 Action = GetDefaultIdForCallBack (DefaultId);
3818 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
3819 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
3820 Status = ConfigAccess->Callback (
3821 ConfigAccess,
3822 Action,
3823 Question->QuestionId,
3824 HiiValue->Type,
3825 &HiiValue->Value,
3826 &ActionRequest
3827 );
3828 if (!EFI_ERROR (Status)) {
3829 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3830 NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
3831 ASSERT (NewString != NULL);
3832
3833 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
3834 if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
3835 CopyMem (Question->BufferValue, NewString, StrSize (NewString));
3836 } else {
3837 CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
3838 }
3839
3840 FreePool (NewString);
3841 }
3842 return Status;
3843 }
3844 }
3845
3846 //
3847 // Get default value from altcfg string.
3848 //
3849 if (ConfigAccess != NULL) {
3850 Status = GetDefaultValueFromAltCfg(FormSet, Form, Question);
3851 if (!EFI_ERROR (Status)) {
3852 return Status;
3853 }
3854 }
3855
3856 //
3857 // EFI_IFR_DEFAULT has highest priority
3858 //
3859 if (!IsListEmpty (&Question->DefaultListHead)) {
3860 Link = GetFirstNode (&Question->DefaultListHead);
3861 while (!IsNull (&Question->DefaultListHead, Link)) {
3862 Default = QUESTION_DEFAULT_FROM_LINK (Link);
3863
3864 if (Default->DefaultId == DefaultId) {
3865 if (Default->ValueExpression != NULL) {
3866 //
3867 // Default is provided by an Expression, evaluate it
3868 //
3869 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
3870 if (EFI_ERROR (Status)) {
3871 return Status;
3872 }
3873
3874 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
3875 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
3876 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
3877 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
3878 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
3879 } else {
3880 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
3881 Question->HiiValue.BufferLen = Question->StorageWidth;
3882 }
3883 FreePool (Default->ValueExpression->Result.Buffer);
3884 }
3885 HiiValue->Type = Default->ValueExpression->Result.Type;
3886 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
3887 } else {
3888 //
3889 // Default value is embedded in EFI_IFR_DEFAULT
3890 //
3891 if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
3892 ASSERT (HiiValue->Buffer != NULL);
3893 CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
3894 } else {
3895 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
3896 }
3897 }
3898
3899 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3900 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
3901 if (StrValue == NULL) {
3902 return EFI_NOT_FOUND;
3903 }
3904 if (Question->StorageWidth > StrSize (StrValue)) {
3905 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
3906 } else {
3907 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
3908 }
3909 }
3910
3911 return EFI_SUCCESS;
3912 }
3913
3914 Link = GetNextNode (&Question->DefaultListHead, Link);
3915 }
3916 }
3917
3918 //
3919 // EFI_ONE_OF_OPTION
3920 //
3921 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
3922 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3923 //
3924 // OneOfOption could only provide Standard and Manufacturing default
3925 //
3926 Link = GetFirstNode (&Question->OptionListHead);
3927 while (!IsNull (&Question->OptionListHead, Link)) {
3928 Option = QUESTION_OPTION_FROM_LINK (Link);
3929 Link = GetNextNode (&Question->OptionListHead, Link);
3930
3931 if ((Option->SuppressExpression != NULL) &&
3932 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3933 continue;
3934 }
3935
3936 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
3937 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
3938 ) {
3939 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3940
3941 return EFI_SUCCESS;
3942 }
3943 }
3944 }
3945 }
3946
3947 //
3948 // EFI_IFR_CHECKBOX - lowest priority
3949 //
3950 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
3951 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3952 //
3953 // Checkbox could only provide Standard and Manufacturing default
3954 //
3955 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
3956 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
3957 ) {
3958 HiiValue->Value.b = TRUE;
3959 } else {
3960 HiiValue->Value.b = FALSE;
3961 }
3962
3963 return EFI_SUCCESS;
3964 }
3965 }
3966
3967 //
3968 // For Questions without default
3969 //
3970 Status = EFI_NOT_FOUND;
3971 switch (Question->Operand) {
3972 case EFI_IFR_NUMERIC_OP:
3973 //
3974 // Take minimum value as numeric default value
3975 //
3976 if ((Question->Flags & EFI_IFR_DISPLAY) == 0) {
3977 //
3978 // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
3979 //
3980 switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) {
3981 case EFI_IFR_NUMERIC_SIZE_1:
3982 if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) {
3983 HiiValue->Value.u8 = (UINT8) Question->Minimum;
3984 Status = EFI_SUCCESS;
3985 }
3986 break;
3987 case EFI_IFR_NUMERIC_SIZE_2:
3988 if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) {
3989 HiiValue->Value.u16 = (UINT16) Question->Minimum;
3990 Status = EFI_SUCCESS;
3991 }
3992 break;
3993 case EFI_IFR_NUMERIC_SIZE_4:
3994 if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) {
3995 HiiValue->Value.u32 = (UINT32) Question->Minimum;
3996 Status = EFI_SUCCESS;
3997 }
3998 break;
3999 case EFI_IFR_NUMERIC_SIZE_8:
4000 if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) {
4001 HiiValue->Value.u64 = Question->Minimum;
4002 Status = EFI_SUCCESS;
4003 }
4004 break;
4005 default:
4006 break;
4007 }
4008 } else {
4009 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
4010 HiiValue->Value.u64 = Question->Minimum;
4011 Status = EFI_SUCCESS;
4012 }
4013 }
4014 break;
4015
4016 case EFI_IFR_ONE_OF_OP:
4017 //
4018 // Take first oneof option as oneof's default value
4019 //
4020 if (ValueToOption (Question, HiiValue) == NULL) {
4021 Link = GetFirstNode (&Question->OptionListHead);
4022 while (!IsNull (&Question->OptionListHead, Link)) {
4023 Option = QUESTION_OPTION_FROM_LINK (Link);
4024 Link = GetNextNode (&Question->OptionListHead, Link);
4025
4026 if ((Option->SuppressExpression != NULL) &&
4027 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
4028 continue;
4029 }
4030
4031 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
4032 Status = EFI_SUCCESS;
4033 break;
4034 }
4035 }
4036 break;
4037
4038 case EFI_IFR_ORDERED_LIST_OP:
4039 //
4040 // Take option sequence in IFR as ordered list's default value
4041 //
4042 Index = 0;
4043 Link = GetFirstNode (&Question->OptionListHead);
4044 while (!IsNull (&Question->OptionListHead, Link)) {
4045 Status = EFI_SUCCESS;
4046 Option = QUESTION_OPTION_FROM_LINK (Link);
4047 Link = GetNextNode (&Question->OptionListHead, Link);
4048
4049 if ((Option->SuppressExpression != NULL) &&
4050 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
4051 continue;
4052 }
4053
4054 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
4055
4056 Index++;
4057 if (Index >= Question->MaxContainers) {
4058 break;
4059 }
4060 }
4061 break;
4062
4063 default:
4064 break;
4065 }
4066
4067 return Status;
4068 }
4069
4070 /**
4071 Get AltCfg string for current form.
4072
4073 @param FormSet Form data structure.
4074 @param Form Form data structure.
4075 @param DefaultId The Class of the default.
4076 @param BrowserStorage The input request storage for the questions.
4077
4078 **/
4079 VOID
4080 ExtractAltCfgForForm (
4081 IN FORM_BROWSER_FORMSET *FormSet,
4082 IN FORM_BROWSER_FORM *Form,
4083 IN UINT16 DefaultId,
4084 IN BROWSER_STORAGE *BrowserStorage
4085 )
4086 {
4087 EFI_STATUS Status;
4088 LIST_ENTRY *Link;
4089 CHAR16 *ConfigResp;
4090 CHAR16 *Progress;
4091 CHAR16 *Result;
4092 BROWSER_STORAGE *Storage;
4093 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
4094 FORMSET_STORAGE *FormSetStorage;
4095
4096 //
4097 // Check whether has get AltCfg string for this formset.
4098 // If yes, no need to get AltCfg for form.
4099 //
4100 Link = GetFirstNode (&FormSet->StorageListHead);
4101 while (!IsNull (&FormSet->StorageListHead, Link)) {
4102 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
4103 Storage = FormSetStorage->BrowserStorage;
4104 Link = GetNextNode (&FormSet->StorageListHead, Link);
4105 if (BrowserStorage != NULL && BrowserStorage != Storage) {
4106 continue;
4107 }
4108
4109 if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE &&
4110 FormSetStorage->ElementCount != 0 &&
4111 FormSetStorage->HasCallAltCfg) {
4112 return;
4113 }
4114 }
4115
4116 //
4117 // Get AltCfg string for each form.
4118 //
4119 Link = GetFirstNode (&Form->ConfigRequestHead);
4120 while (!IsNull (&Form->ConfigRequestHead, Link)) {
4121 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
4122 Link = GetNextNode (&Form->ConfigRequestHead, Link);
4123
4124 Storage = ConfigInfo->Storage;
4125 if (BrowserStorage != NULL && BrowserStorage != Storage) {
4126 continue;
4127 }
4128
4129 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
4130 continue;
4131 }
4132
4133 //
4134 // 1. Skip if there is no RequestElement
4135 //
4136 if (ConfigInfo->ElementCount == 0) {
4137 continue;
4138 }
4139
4140 //
4141 // 2. Get value through hii config routine protocol.
4142 //
4143 Status = mHiiConfigRouting->ExtractConfig (
4144 mHiiConfigRouting,
4145 ConfigInfo->ConfigRequest,
4146 &Progress,
4147 &Result
4148 );
4149 if (EFI_ERROR (Status)) {
4150 continue;
4151 }
4152
4153 //
4154 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
4155 // Get the default configuration string according to the default ID.
4156 //
4157 Status = mHiiConfigRouting->GetAltConfig (
4158 mHiiConfigRouting,
4159 Result,
4160 &Storage->Guid,
4161 Storage->Name,
4162 NULL,
4163 &DefaultId, // it can be NULL to get the current setting.
4164 &ConfigResp
4165 );
4166 FreePool (Result);
4167 if (EFI_ERROR (Status)) {
4168 continue;
4169 }
4170
4171 ConfigInfo->ConfigAltResp = ConfigResp;
4172 }
4173 }
4174
4175 /**
4176 Clean AltCfg string for current form.
4177
4178 @param Form Form data structure.
4179
4180 **/
4181 VOID
4182 CleanAltCfgForForm (
4183 IN FORM_BROWSER_FORM *Form
4184 )
4185 {
4186 LIST_ENTRY *Link;
4187 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
4188
4189 Link = GetFirstNode (&Form->ConfigRequestHead);
4190 while (!IsNull (&Form->ConfigRequestHead, Link)) {
4191 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
4192 Link = GetNextNode (&Form->ConfigRequestHead, Link);
4193
4194 if (ConfigInfo->ConfigAltResp != NULL) {
4195 FreePool (ConfigInfo->ConfigAltResp);
4196 ConfigInfo->ConfigAltResp = NULL;
4197 }
4198 }
4199 }
4200
4201 /**
4202 Get AltCfg string for current formset.
4203
4204 @param FormSet Form data structure.
4205 @param DefaultId The Class of the default.
4206 @param BrowserStorage The input request storage for the questions.
4207
4208 **/
4209 VOID
4210 ExtractAltCfgForFormSet (
4211 IN FORM_BROWSER_FORMSET *FormSet,
4212 IN UINT16 DefaultId,
4213 IN BROWSER_STORAGE *BrowserStorage
4214 )
4215 {
4216 EFI_STATUS Status;
4217 LIST_ENTRY *Link;
4218 CHAR16 *ConfigResp;
4219 CHAR16 *Progress;
4220 CHAR16 *Result;
4221 BROWSER_STORAGE *Storage;
4222 FORMSET_STORAGE *FormSetStorage;
4223
4224 Link = GetFirstNode (&FormSet->StorageListHead);
4225 while (!IsNull (&FormSet->StorageListHead, Link)) {
4226 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
4227 Storage = FormSetStorage->BrowserStorage;
4228 Link = GetNextNode (&FormSet->StorageListHead, Link);
4229
4230 if (BrowserStorage != NULL && BrowserStorage != Storage) {
4231 continue;
4232 }
4233
4234 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
4235 continue;
4236 }
4237
4238 //
4239 // 1. Skip if there is no RequestElement
4240 //
4241 if (FormSetStorage->ElementCount == 0) {
4242 continue;
4243 }
4244
4245 FormSetStorage->HasCallAltCfg = TRUE;
4246
4247 //
4248 // 2. Get value through hii config routine protocol.
4249 //
4250 Status = mHiiConfigRouting->ExtractConfig (
4251 mHiiConfigRouting,
4252 FormSetStorage->ConfigRequest,
4253 &Progress,
4254 &Result
4255 );
4256 if (EFI_ERROR (Status)) {
4257 continue;
4258 }
4259
4260 //
4261 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
4262 // Get the default configuration string according to the default ID.
4263 //
4264 Status = mHiiConfigRouting->GetAltConfig (
4265 mHiiConfigRouting,
4266 Result,
4267 &Storage->Guid,
4268 Storage->Name,
4269 NULL,
4270 &DefaultId, // it can be NULL to get the current setting.
4271 &ConfigResp
4272 );
4273
4274 FreePool (Result);
4275 if (EFI_ERROR (Status)) {
4276 continue;
4277 }
4278
4279 FormSetStorage->ConfigAltResp = ConfigResp;
4280 }
4281
4282 }
4283
4284 /**
4285 Clean AltCfg string for current formset.
4286
4287 @param FormSet Form data structure.
4288
4289 **/
4290 VOID
4291 CleanAltCfgForFormSet (
4292 IN FORM_BROWSER_FORMSET *FormSet
4293 )
4294 {
4295 LIST_ENTRY *Link;
4296 FORMSET_STORAGE *FormSetStorage;
4297
4298 Link = GetFirstNode (&FormSet->StorageListHead);
4299 while (!IsNull (&FormSet->StorageListHead, Link)) {
4300 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
4301 Link = GetNextNode (&FormSet->StorageListHead, Link);
4302
4303 if (FormSetStorage->ConfigAltResp != NULL) {
4304 FreePool (FormSetStorage->ConfigAltResp);
4305 FormSetStorage->ConfigAltResp = NULL;
4306 }
4307
4308 FormSetStorage->HasCallAltCfg = FALSE;
4309 }
4310 }
4311
4312 /**
4313 Reset Questions to their initial value or default value in a Form, Formset or System.
4314
4315 GetDefaultValueScope parameter decides which questions will reset
4316 to its default value.
4317
4318 @param FormSet FormSet data structure.
4319 @param Form Form data structure.
4320 @param DefaultId The Class of the default.
4321 @param SettingScope Setting Scope for Default action.
4322 @param GetDefaultValueScope Get default value scope.
4323 @param Storage Get default value only for this storage.
4324 @param RetrieveValueFirst Whether call the retrieve call back to
4325 get the initial value before get default
4326 value.
4327 @param SkipGetAltCfg Whether skip the get altcfg string process.
4328
4329 @retval EFI_SUCCESS The function completed successfully.
4330 @retval EFI_UNSUPPORTED Unsupport SettingScope.
4331
4332 **/
4333 EFI_STATUS
4334 ExtractDefault (
4335 IN FORM_BROWSER_FORMSET *FormSet,
4336 IN FORM_BROWSER_FORM *Form,
4337 IN UINT16 DefaultId,
4338 IN BROWSER_SETTING_SCOPE SettingScope,
4339 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
4340 IN BROWSER_STORAGE *Storage OPTIONAL,
4341 IN BOOLEAN RetrieveValueFirst,
4342 IN BOOLEAN SkipGetAltCfg
4343 )
4344 {
4345 EFI_STATUS Status;
4346 LIST_ENTRY *FormLink;
4347 LIST_ENTRY *Link;
4348 FORM_BROWSER_STATEMENT *Question;
4349 FORM_BROWSER_FORMSET *LocalFormSet;
4350 FORM_BROWSER_FORMSET *OldFormSet;
4351
4352 Status = EFI_SUCCESS;
4353
4354 //
4355 // Check the supported setting level.
4356 //
4357 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
4358 return EFI_UNSUPPORTED;
4359 }
4360
4361 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
4362 return EFI_UNSUPPORTED;
4363 }
4364
4365 if (SettingScope == FormLevel) {
4366 //
4367 // Prepare the AltCfg String for form.
4368 //
4369 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4370 ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);
4371 }
4372
4373 //
4374 // Extract Form default
4375 //
4376 Link = GetFirstNode (&Form->StatementListHead);
4377 while (!IsNull (&Form->StatementListHead, Link)) {
4378 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
4379 Link = GetNextNode (&Form->StatementListHead, Link);
4380
4381 //
4382 // If get default value only for this storage, check the storage first.
4383 //
4384 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
4385 continue;
4386 }
4387
4388 //
4389 // If get default value only for no storage question, just skip the question which has storage.
4390 //
4391 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
4392 continue;
4393 }
4394
4395 //
4396 // If Question is disabled, don't reset it to default
4397 //
4398 if (Question->Expression != NULL) {
4399 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
4400 continue;
4401 }
4402 }
4403
4404 if (RetrieveValueFirst) {
4405 //
4406 // Call the Retrieve call back to get the initial question value.
4407 //
4408 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
4409 }
4410
4411 //
4412 // If not request to get the initial value or get initial value fail, then get default value.
4413 //
4414 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
4415 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
4416 if (EFI_ERROR (Status)) {
4417 continue;
4418 }
4419 }
4420
4421 //
4422 // Synchronize Buffer storage's Edit buffer
4423 //
4424 if ((Question->Storage != NULL) &&
4425 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
4426 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4427 }
4428 }
4429
4430 //
4431 // Clean the AltCfg String.
4432 //
4433 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4434 CleanAltCfgForForm(Form);
4435 }
4436 } else if (SettingScope == FormSetLevel) {
4437 //
4438 // Prepare the AltCfg String for formset.
4439 //
4440 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4441 ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);
4442 }
4443
4444 FormLink = GetFirstNode (&FormSet->FormListHead);
4445 while (!IsNull (&FormSet->FormListHead, FormLink)) {
4446 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
4447 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
4448 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
4449 }
4450
4451 //
4452 // Clean the AltCfg String.
4453 //
4454 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4455 CleanAltCfgForFormSet (FormSet);
4456 }
4457 } else if (SettingScope == SystemLevel) {
4458 //
4459 // Preload all Hii formset.
4460 //
4461 LoadAllHiiFormset();
4462
4463 OldFormSet = mSystemLevelFormSet;
4464
4465 //
4466 // Set Default Value for each FormSet in the maintain list.
4467 //
4468 Link = GetFirstNode (&gBrowserFormSetList);
4469 while (!IsNull (&gBrowserFormSetList, Link)) {
4470 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4471 Link = GetNextNode (&gBrowserFormSetList, Link);
4472 if (!ValidateFormSet(LocalFormSet)) {
4473 continue;
4474 }
4475
4476 mSystemLevelFormSet = LocalFormSet;
4477
4478 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
4479 }
4480
4481 mSystemLevelFormSet = OldFormSet;
4482 }
4483
4484 return EFI_SUCCESS;
4485 }
4486
4487
4488 /**
4489 Validate whether this question's value has changed.
4490
4491 @param FormSet FormSet data structure.
4492 @param Form Form data structure.
4493 @param Question Question to be initialized.
4494 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
4495
4496 @retval TRUE Question's value has changed.
4497 @retval FALSE Question's value has not changed
4498
4499 **/
4500 BOOLEAN
4501 IsQuestionValueChanged (
4502 IN FORM_BROWSER_FORMSET *FormSet,
4503 IN FORM_BROWSER_FORM *Form,
4504 IN OUT FORM_BROWSER_STATEMENT *Question,
4505 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
4506 )
4507 {
4508 EFI_HII_VALUE BackUpValue;
4509 CHAR8 *BackUpBuffer;
4510 EFI_HII_VALUE BackUpValue2;
4511 CHAR8 *BackUpBuffer2;
4512 EFI_STATUS Status;
4513 BOOLEAN ValueChanged;
4514 UINTN BufferWidth;
4515
4516 //
4517 // For quetion without storage, always mark it as data not changed.
4518 //
4519 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
4520 return FALSE;
4521 }
4522
4523 BackUpBuffer = NULL;
4524 BackUpBuffer2 = NULL;
4525 ValueChanged = FALSE;
4526
4527 switch (Question->Operand) {
4528 case EFI_IFR_ORDERED_LIST_OP:
4529 BufferWidth = Question->StorageWidth;
4530 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
4531 ASSERT (BackUpBuffer != NULL);
4532 break;
4533
4534 case EFI_IFR_STRING_OP:
4535 case EFI_IFR_PASSWORD_OP:
4536 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
4537 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
4538 ASSERT (BackUpBuffer != NULL);
4539 break;
4540
4541 default:
4542 BufferWidth = 0;
4543 break;
4544 }
4545 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
4546
4547 if (GetValueFrom == GetSetValueWithBothBuffer) {
4548 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4549 ASSERT_EFI_ERROR(Status);
4550
4551 switch (Question->Operand) {
4552 case EFI_IFR_ORDERED_LIST_OP:
4553 BufferWidth = Question->StorageWidth;
4554 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
4555 ASSERT (BackUpBuffer2 != NULL);
4556 break;
4557
4558 case EFI_IFR_STRING_OP:
4559 case EFI_IFR_PASSWORD_OP:
4560 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
4561 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
4562 ASSERT (BackUpBuffer2 != NULL);
4563 break;
4564
4565 default:
4566 BufferWidth = 0;
4567 break;
4568 }
4569 CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
4570
4571 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
4572 ASSERT_EFI_ERROR(Status);
4573
4574 if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
4575 CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {
4576 ValueChanged = TRUE;
4577 }
4578 } else {
4579 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
4580 ASSERT_EFI_ERROR(Status);
4581
4582 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
4583 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
4584 ValueChanged = TRUE;
4585 }
4586 }
4587
4588 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
4589 if (BackUpBuffer != NULL) {
4590 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
4591 FreePool (BackUpBuffer);
4592 }
4593
4594 if (BackUpBuffer2 != NULL) {
4595 FreePool (BackUpBuffer2);
4596 }
4597
4598 Question->ValueChanged = ValueChanged;
4599
4600 return ValueChanged;
4601 }
4602
4603 /**
4604 Initialize Question's Edit copy from Storage.
4605
4606 @param Selection Selection contains the information about
4607 the Selection, form and formset to be displayed.
4608 Selection action may be updated in retrieve callback.
4609 If Selection is NULL, only initialize Question value.
4610 @param FormSet FormSet data structure.
4611 @param Form Form data structure.
4612
4613 @retval EFI_SUCCESS The function completed successfully.
4614
4615 **/
4616 EFI_STATUS
4617 LoadFormConfig (
4618 IN OUT UI_MENU_SELECTION *Selection,
4619 IN FORM_BROWSER_FORMSET *FormSet,
4620 IN FORM_BROWSER_FORM *Form
4621 )
4622 {
4623 EFI_STATUS Status;
4624 LIST_ENTRY *Link;
4625 FORM_BROWSER_STATEMENT *Question;
4626
4627 Link = GetFirstNode (&Form->StatementListHead);
4628 while (!IsNull (&Form->StatementListHead, Link)) {
4629 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
4630
4631 //
4632 // Initialize local copy of Value for each Question
4633 //
4634 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
4635 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
4636 } else {
4637 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4638 }
4639 if (EFI_ERROR (Status)) {
4640 return Status;
4641 }
4642
4643 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
4644 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
4645 }
4646
4647 Link = GetNextNode (&Form->StatementListHead, Link);
4648 }
4649
4650 return EFI_SUCCESS;
4651 }
4652
4653 /**
4654 Initialize Question's Edit copy from Storage for the whole Formset.
4655
4656 @param Selection Selection contains the information about
4657 the Selection, form and formset to be displayed.
4658 Selection action may be updated in retrieve callback.
4659 If Selection is NULL, only initialize Question value.
4660 @param FormSet FormSet data structure.
4661
4662 @retval EFI_SUCCESS The function completed successfully.
4663
4664 **/
4665 EFI_STATUS
4666 LoadFormSetConfig (
4667 IN OUT UI_MENU_SELECTION *Selection,
4668 IN FORM_BROWSER_FORMSET *FormSet
4669 )
4670 {
4671 EFI_STATUS Status;
4672 LIST_ENTRY *Link;
4673 FORM_BROWSER_FORM *Form;
4674
4675 Link = GetFirstNode (&FormSet->FormListHead);
4676 while (!IsNull (&FormSet->FormListHead, Link)) {
4677 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4678
4679 //
4680 // Initialize local copy of Value for each Form
4681 //
4682 Status = LoadFormConfig (Selection, FormSet, Form);
4683 if (EFI_ERROR (Status)) {
4684 return Status;
4685 }
4686
4687 Link = GetNextNode (&FormSet->FormListHead, Link);
4688 }
4689
4690 //
4691 // Finished question initialization.
4692 //
4693 FormSet->QuestionInited = TRUE;
4694
4695 return EFI_SUCCESS;
4696 }
4697
4698 /**
4699 Remove the Request element from the Config Request.
4700
4701 @param Storage Pointer to the browser storage.
4702 @param RequestElement The pointer to the Request element.
4703
4704 **/
4705 VOID
4706 RemoveElement (
4707 IN OUT BROWSER_STORAGE *Storage,
4708 IN CHAR16 *RequestElement
4709 )
4710 {
4711 CHAR16 *NewStr;
4712 CHAR16 *DestStr;
4713
4714 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
4715
4716 NewStr = StrStr (Storage->ConfigRequest, RequestElement);
4717
4718 if (NewStr == NULL) {
4719 return;
4720 }
4721
4722 //
4723 // Remove this element from this ConfigRequest.
4724 //
4725 DestStr = NewStr;
4726 NewStr += StrLen (RequestElement);
4727 CopyMem (DestStr, NewStr, StrSize (NewStr));
4728
4729 Storage->SpareStrLen += StrLen (RequestElement);
4730 }
4731
4732 /**
4733 Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
4734
4735 @param Storage Pointer to the formset storage.
4736 @param ConfigRequest The pointer to the Request element.
4737
4738 **/
4739 VOID
4740 RemoveConfigRequest (
4741 FORMSET_STORAGE *Storage,
4742 CHAR16 *ConfigRequest
4743 )
4744 {
4745 CHAR16 *RequestElement;
4746 CHAR16 *NextRequestElement;
4747 CHAR16 *SearchKey;
4748
4749 //
4750 // No request element in it, just return.
4751 //
4752 if (ConfigRequest == NULL) {
4753 return;
4754 }
4755
4756 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4757 //
4758 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
4759 //
4760 SearchKey = L"&";
4761 } else {
4762 //
4763 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
4764 //
4765 SearchKey = L"&OFFSET";
4766 }
4767
4768 //
4769 // Find SearchKey storage
4770 //
4771 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4772 RequestElement = StrStr (ConfigRequest, L"PATH");
4773 ASSERT (RequestElement != NULL);
4774 RequestElement = StrStr (RequestElement, SearchKey);
4775 } else {
4776 RequestElement = StrStr (ConfigRequest, SearchKey);
4777 }
4778
4779 while (RequestElement != NULL) {
4780 //
4781 // +1 to avoid find header itself.
4782 //
4783 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
4784
4785 //
4786 // The last Request element in configRequest string.
4787 //
4788 if (NextRequestElement != NULL) {
4789 //
4790 // Replace "&" with '\0'.
4791 //
4792 *NextRequestElement = L'\0';
4793 }
4794
4795 RemoveElement (Storage->BrowserStorage, RequestElement);
4796
4797 if (NextRequestElement != NULL) {
4798 //
4799 // Restore '&' with '\0' for later used.
4800 //
4801 *NextRequestElement = L'&';
4802 }
4803
4804 RequestElement = NextRequestElement;
4805 }
4806
4807 //
4808 // If no request element remain, just remove the ConfigRequest string.
4809 //
4810 if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {
4811 FreePool (Storage->BrowserStorage->ConfigRequest);
4812 Storage->BrowserStorage->ConfigRequest = NULL;
4813 Storage->BrowserStorage->SpareStrLen = 0;
4814 }
4815 }
4816
4817 /**
4818 Base on the current formset info, clean the ConfigRequest string in browser storage.
4819
4820 @param FormSet Pointer of the FormSet
4821
4822 **/
4823 VOID
4824 CleanBrowserStorage (
4825 IN OUT FORM_BROWSER_FORMSET *FormSet
4826 )
4827 {
4828 LIST_ENTRY *Link;
4829 FORMSET_STORAGE *Storage;
4830
4831 Link = GetFirstNode (&FormSet->StorageListHead);
4832 while (!IsNull (&FormSet->StorageListHead, Link)) {
4833 Storage = FORMSET_STORAGE_FROM_LINK (Link);
4834 Link = GetNextNode (&FormSet->StorageListHead, Link);
4835
4836 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
4837 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
4838 continue;
4839 }
4840
4841 RemoveConfigRequest (Storage, Storage->ConfigRequest);
4842 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
4843 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4844 if (Storage->BrowserStorage->ConfigRequest != NULL) {
4845 FreePool (Storage->BrowserStorage->ConfigRequest);
4846 Storage->BrowserStorage->ConfigRequest = NULL;
4847 }
4848 Storage->BrowserStorage->Initialized = FALSE;
4849 }
4850 }
4851 }
4852
4853 /**
4854 Check whether current element in the ConfigReqeust string.
4855
4856 @param BrowserStorage Storage which includes ConfigReqeust.
4857 @param RequestElement New element need to check.
4858
4859 @retval TRUE The Element is in the ConfigReqeust string.
4860 @retval FALSE The Element not in the configReqeust String.
4861
4862 **/
4863 BOOLEAN
4864 ElementValidation (
4865 BROWSER_STORAGE *BrowserStorage,
4866 CHAR16 *RequestElement
4867 )
4868 {
4869 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
4870 }
4871
4872 /**
4873 Append the Request element to the Config Request.
4874
4875 @param ConfigRequest Current ConfigRequest info.
4876 @param SpareStrLen Current remain free buffer for config reqeust.
4877 @param RequestElement New Request element.
4878
4879 **/
4880 VOID
4881 AppendConfigRequest (
4882 IN OUT CHAR16 **ConfigRequest,
4883 IN OUT UINTN *SpareStrLen,
4884 IN CHAR16 *RequestElement
4885 )
4886 {
4887 CHAR16 *NewStr;
4888 UINTN StringSize;
4889 UINTN StrLength;
4890
4891 StrLength = StrLen (RequestElement);
4892
4893 //
4894 // Append <RequestElement> to <ConfigRequest>
4895 //
4896 if (StrLength > *SpareStrLen) {
4897 //
4898 // Old String buffer is not sufficient for RequestElement, allocate a new one
4899 //
4900 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
4901 NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));
4902 ASSERT (NewStr != NULL);
4903
4904 if (*ConfigRequest != NULL) {
4905 CopyMem (NewStr, *ConfigRequest, StringSize);
4906 FreePool (*ConfigRequest);
4907 }
4908 *ConfigRequest = NewStr;
4909 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
4910 }
4911
4912 StrCat (*ConfigRequest, RequestElement);
4913 *SpareStrLen -= StrLength;
4914 }
4915
4916 /**
4917 Adjust the config request info, remove the request elements which already in AllConfigRequest string.
4918
4919 @param Storage Form set Storage.
4920 @param Request The input request string.
4921 @param RespString Whether the input is ConfigRequest or ConfigResp format.
4922
4923 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
4924 @retval FALSE All elements covered by current used elements.
4925
4926 **/
4927 BOOLEAN
4928 ConfigRequestAdjust (
4929 IN BROWSER_STORAGE *Storage,
4930 IN CHAR16 *Request,
4931 IN BOOLEAN RespString
4932 )
4933 {
4934 CHAR16 *RequestElement;
4935 CHAR16 *NextRequestElement;
4936 CHAR16 *NextElementBakup;
4937 CHAR16 *SearchKey;
4938 CHAR16 *ValueKey;
4939 BOOLEAN RetVal;
4940 CHAR16 *ConfigRequest;
4941
4942 RetVal = FALSE;
4943 NextElementBakup = NULL;
4944 ValueKey = NULL;
4945
4946 if (Request != NULL) {
4947 ConfigRequest = Request;
4948 } else {
4949 ConfigRequest = Storage->ConfigRequest;
4950 }
4951
4952 if (Storage->ConfigRequest == NULL) {
4953 Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
4954 return TRUE;
4955 }
4956
4957 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4958 //
4959 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
4960 //
4961 SearchKey = L"&";
4962 } else {
4963 //
4964 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
4965 //
4966 SearchKey = L"&OFFSET";
4967 ValueKey = L"&VALUE";
4968 }
4969
4970 //
4971 // Find SearchKey storage
4972 //
4973 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4974 RequestElement = StrStr (ConfigRequest, L"PATH");
4975 ASSERT (RequestElement != NULL);
4976 RequestElement = StrStr (RequestElement, SearchKey);
4977 } else {
4978 RequestElement = StrStr (ConfigRequest, SearchKey);
4979 }
4980
4981 while (RequestElement != NULL) {
4982
4983 //
4984 // +1 to avoid find header itself.
4985 //
4986 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
4987
4988 //
4989 // The last Request element in configRequest string.
4990 //
4991 if (NextRequestElement != NULL) {
4992 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4993 NextElementBakup = NextRequestElement;
4994 NextRequestElement = StrStr (RequestElement, ValueKey);
4995 ASSERT (NextRequestElement != NULL);
4996 }
4997 //
4998 // Replace "&" with '\0'.
4999 //
5000 *NextRequestElement = L'\0';
5001 } else {
5002 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
5003 NextElementBakup = NextRequestElement;
5004 NextRequestElement = StrStr (RequestElement, ValueKey);
5005 ASSERT (NextRequestElement != NULL);
5006 //
5007 // Replace "&" with '\0'.
5008 //
5009 *NextRequestElement = L'\0';
5010 }
5011 }
5012
5013 if (!ElementValidation (Storage, RequestElement)) {
5014 //
5015 // Add this element to the Storage->BrowserStorage->AllRequestElement.
5016 //
5017 AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
5018 RetVal = TRUE;
5019 }
5020
5021 if (NextRequestElement != NULL) {
5022 //
5023 // Restore '&' with '\0' for later used.
5024 //
5025 *NextRequestElement = L'&';
5026 }
5027
5028 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
5029 RequestElement = NextElementBakup;
5030 } else {
5031 RequestElement = NextRequestElement;
5032 }
5033 }
5034
5035 return RetVal;
5036 }
5037
5038 /**
5039 Fill storage's edit copy with settings requested from Configuration Driver.
5040
5041 @param FormSet FormSet data structure.
5042 @param Storage Buffer Storage.
5043
5044 **/
5045 VOID
5046 LoadStorage (
5047 IN FORM_BROWSER_FORMSET *FormSet,
5048 IN FORMSET_STORAGE *Storage
5049 )
5050 {
5051 EFI_STATUS Status;
5052 EFI_STRING Progress;
5053 EFI_STRING Result;
5054 CHAR16 *StrPtr;
5055 EFI_STRING ConfigRequest;
5056 UINTN StrLen;
5057
5058 ConfigRequest = NULL;
5059
5060 switch (Storage->BrowserStorage->Type) {
5061 case EFI_HII_VARSTORE_EFI_VARIABLE:
5062 return;
5063
5064 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
5065 if (Storage->BrowserStorage->ConfigRequest != NULL) {
5066 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
5067 return;
5068 }
5069 break;
5070
5071 case EFI_HII_VARSTORE_BUFFER:
5072 case EFI_HII_VARSTORE_NAME_VALUE:
5073 //
5074 // Skip if there is no RequestElement.
5075 //
5076 if (Storage->ElementCount == 0) {
5077 return;
5078 }
5079
5080 //
5081 // Just update the ConfigRequest, if storage already initialized.
5082 //
5083 if (Storage->BrowserStorage->Initialized) {
5084 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
5085 return;
5086 }
5087
5088 Storage->BrowserStorage->Initialized = TRUE;
5089 break;
5090
5091 default:
5092 return;
5093 }
5094
5095 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
5096 //
5097 // Create the config request string to get all fields for this storage.
5098 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
5099 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
5100 //
5101 StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);
5102 ConfigRequest = AllocateZeroPool (StrLen);
5103 ASSERT (ConfigRequest != NULL);
5104 UnicodeSPrint (
5105 ConfigRequest,
5106 StrLen,
5107 L"%s&OFFSET=0&WIDTH=%04x",
5108 Storage->ConfigHdr,
5109 Storage->BrowserStorage->Size);
5110 } else {
5111 ConfigRequest = Storage->ConfigRequest;
5112 }
5113
5114 //
5115 // Request current settings from Configuration Driver
5116 //
5117 Status = mHiiConfigRouting->ExtractConfig (
5118 mHiiConfigRouting,
5119 ConfigRequest,
5120 &Progress,
5121 &Result
5122 );
5123
5124 //
5125 // If get value fail, extract default from IFR binary
5126 //
5127 if (EFI_ERROR (Status)) {
5128 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
5129 } else {
5130 //
5131 // Convert Result from <ConfigAltResp> to <ConfigResp>
5132 //
5133 StrPtr = StrStr (Result, L"&GUID=");
5134 if (StrPtr != NULL) {
5135 *StrPtr = L'\0';
5136 }
5137
5138 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
5139 FreePool (Result);
5140 }
5141
5142 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
5143
5144 //
5145 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
5146 //
5147 SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);
5148
5149 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
5150 if (ConfigRequest != NULL) {
5151 FreePool (ConfigRequest);
5152 }
5153 }
5154 }
5155
5156 /**
5157 Get Value changed status from old question.
5158
5159 @param NewFormSet FormSet data structure.
5160 @param OldQuestion Old question which has value changed.
5161
5162 **/
5163 VOID
5164 SyncStatusForQuestion (
5165 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5166 IN FORM_BROWSER_STATEMENT *OldQuestion
5167 )
5168 {
5169 LIST_ENTRY *Link;
5170 LIST_ENTRY *QuestionLink;
5171 FORM_BROWSER_FORM *Form;
5172 FORM_BROWSER_STATEMENT *Question;
5173
5174 //
5175 // For each form in one formset.
5176 //
5177 Link = GetFirstNode (&NewFormSet->FormListHead);
5178 while (!IsNull (&NewFormSet->FormListHead, Link)) {
5179 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5180 Link = GetNextNode (&NewFormSet->FormListHead, Link);
5181
5182 //
5183 // for each question in one form.
5184 //
5185 QuestionLink = GetFirstNode (&Form->StatementListHead);
5186 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5187 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5188 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5189
5190 if (Question->QuestionId == OldQuestion->QuestionId) {
5191 Question->ValueChanged = TRUE;
5192 return;
5193 }
5194 }
5195 }
5196 }
5197
5198 /**
5199 Get Value changed status from old formset.
5200
5201 @param NewFormSet FormSet data structure.
5202 @param OldFormSet FormSet data structure.
5203
5204 **/
5205 VOID
5206 SyncStatusForFormSet (
5207 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5208 IN FORM_BROWSER_FORMSET *OldFormSet
5209 )
5210 {
5211 LIST_ENTRY *Link;
5212 LIST_ENTRY *QuestionLink;
5213 FORM_BROWSER_FORM *Form;
5214 FORM_BROWSER_STATEMENT *Question;
5215
5216 //
5217 // For each form in one formset.
5218 //
5219 Link = GetFirstNode (&OldFormSet->FormListHead);
5220 while (!IsNull (&OldFormSet->FormListHead, Link)) {
5221 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5222 Link = GetNextNode (&OldFormSet->FormListHead, Link);
5223
5224 //
5225 // for each question in one form.
5226 //
5227 QuestionLink = GetFirstNode (&Form->StatementListHead);
5228 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5229 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5230 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5231
5232 if (!Question->ValueChanged) {
5233 continue;
5234 }
5235
5236 //
5237 // Find the same question in new formset and update the value changed flag.
5238 //
5239 SyncStatusForQuestion (NewFormSet, Question);
5240 }
5241 }
5242 }
5243
5244 /**
5245 Get current setting of Questions.
5246
5247 @param FormSet FormSet data structure.
5248
5249 **/
5250 VOID
5251 InitializeCurrentSetting (
5252 IN OUT FORM_BROWSER_FORMSET *FormSet
5253 )
5254 {
5255 LIST_ENTRY *Link;
5256 FORMSET_STORAGE *Storage;
5257 FORM_BROWSER_FORMSET *OldFormSet;
5258
5259 //
5260 // Try to find pre FormSet in the maintain backup list.
5261 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
5262 //
5263 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
5264 if (OldFormSet != NULL) {
5265 SyncStatusForFormSet (FormSet, OldFormSet);
5266 RemoveEntryList (&OldFormSet->Link);
5267 DestroyFormSet (OldFormSet);
5268 }
5269 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
5270
5271 //
5272 // Extract default from IFR binary for no storage questions.
5273 //
5274 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
5275
5276 //
5277 // Request current settings from Configuration Driver
5278 //
5279 Link = GetFirstNode (&FormSet->StorageListHead);
5280 while (!IsNull (&FormSet->StorageListHead, Link)) {
5281 Storage = FORMSET_STORAGE_FROM_LINK (Link);
5282
5283 LoadStorage (FormSet, Storage);
5284
5285 Link = GetNextNode (&FormSet->StorageListHead, Link);
5286 }
5287 }
5288
5289
5290 /**
5291 Fetch the Ifr binary data of a FormSet.
5292
5293 @param Handle PackageList Handle
5294 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5295 specified (NULL or zero GUID), take the first
5296 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5297 found in package list.
5298 On output, GUID of the formset found(if not NULL).
5299 @param BinaryLength The length of the FormSet IFR binary.
5300 @param BinaryData The buffer designed to receive the FormSet.
5301
5302 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
5303 BufferLength was updated.
5304 @retval EFI_INVALID_PARAMETER The handle is unknown.
5305 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
5306 be found with the requested FormId.
5307
5308 **/
5309 EFI_STATUS
5310 GetIfrBinaryData (
5311 IN EFI_HII_HANDLE Handle,
5312 IN OUT EFI_GUID *FormSetGuid,
5313 OUT UINTN *BinaryLength,
5314 OUT UINT8 **BinaryData
5315 )
5316 {
5317 EFI_STATUS Status;
5318 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
5319 UINTN BufferSize;
5320 UINT8 *Package;
5321 UINT8 *OpCodeData;
5322 UINT32 Offset;
5323 UINT32 Offset2;
5324 UINT32 PackageListLength;
5325 EFI_HII_PACKAGE_HEADER PackageHeader;
5326 UINT8 Index;
5327 UINT8 NumberOfClassGuid;
5328 BOOLEAN ClassGuidMatch;
5329 EFI_GUID *ClassGuid;
5330 EFI_GUID *ComparingGuid;
5331
5332 OpCodeData = NULL;
5333 Package = NULL;
5334 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
5335
5336 //
5337 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
5338 //
5339 if (FormSetGuid == NULL) {
5340 ComparingGuid = &gZeroGuid;
5341 } else {
5342 ComparingGuid = FormSetGuid;
5343 }
5344
5345 //
5346 // Get HII PackageList
5347 //
5348 BufferSize = 0;
5349 HiiPackageList = NULL;
5350 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5351 if (Status == EFI_BUFFER_TOO_SMALL) {
5352 HiiPackageList = AllocatePool (BufferSize);
5353 ASSERT (HiiPackageList != NULL);
5354
5355 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5356 }
5357 if (EFI_ERROR (Status)) {
5358 return Status;
5359 }
5360 ASSERT (HiiPackageList != NULL);
5361
5362 //
5363 // Get Form package from this HII package List
5364 //
5365 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
5366 Offset2 = 0;
5367 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
5368
5369 ClassGuidMatch = FALSE;
5370 while (Offset < PackageListLength) {
5371 Package = ((UINT8 *) HiiPackageList) + Offset;
5372 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
5373
5374 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
5375 //
5376 // Search FormSet in this Form Package
5377 //
5378 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
5379 while (Offset2 < PackageHeader.Length) {
5380 OpCodeData = Package + Offset2;
5381
5382 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
5383 //
5384 // Try to compare against formset GUID
5385 //
5386 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
5387 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
5388 break;
5389 }
5390
5391 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
5392 //
5393 // Try to compare against formset class GUID
5394 //
5395 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
5396 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
5397 for (Index = 0; Index < NumberOfClassGuid; Index++) {
5398 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
5399 ClassGuidMatch = TRUE;
5400 break;
5401 }
5402 }
5403 if (ClassGuidMatch) {
5404 break;
5405 }
5406 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
5407 ClassGuidMatch = TRUE;
5408 break;
5409 }
5410 }
5411
5412 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
5413 }
5414
5415 if (Offset2 < PackageHeader.Length) {
5416 //
5417 // Target formset found
5418 //
5419 break;
5420 }
5421 }
5422
5423 Offset += PackageHeader.Length;
5424 }
5425
5426 if (Offset >= PackageListLength) {
5427 //
5428 // Form package not found in this Package List
5429 //
5430 FreePool (HiiPackageList);
5431 return EFI_NOT_FOUND;
5432 }
5433
5434 if (FormSetGuid != NULL) {
5435 //
5436 // Return the FormSet GUID
5437 //
5438 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
5439 }
5440
5441 //
5442 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
5443 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
5444 // of the Form Package.
5445 //
5446 *BinaryLength = PackageHeader.Length - Offset2;
5447 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
5448
5449 FreePool (HiiPackageList);
5450
5451 if (*BinaryData == NULL) {
5452 return EFI_OUT_OF_RESOURCES;
5453 }
5454
5455 return EFI_SUCCESS;
5456 }
5457
5458
5459 /**
5460 Initialize the internal data structure of a FormSet.
5461
5462 @param Handle PackageList Handle
5463 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5464 specified (NULL or zero GUID), take the first
5465 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5466 found in package list.
5467 On output, GUID of the formset found(if not NULL).
5468 @param FormSet FormSet data structure.
5469
5470 @retval EFI_SUCCESS The function completed successfully.
5471 @retval EFI_NOT_FOUND The specified FormSet could not be found.
5472
5473 **/
5474 EFI_STATUS
5475 InitializeFormSet (
5476 IN EFI_HII_HANDLE Handle,
5477 IN OUT EFI_GUID *FormSetGuid,
5478 OUT FORM_BROWSER_FORMSET *FormSet
5479 )
5480 {
5481 EFI_STATUS Status;
5482 EFI_HANDLE DriverHandle;
5483
5484 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
5485 if (EFI_ERROR (Status)) {
5486 return Status;
5487 }
5488
5489 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
5490 FormSet->HiiHandle = Handle;
5491 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
5492 FormSet->QuestionInited = FALSE;
5493
5494 //
5495 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
5496 //
5497 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
5498 if (EFI_ERROR (Status)) {
5499 return Status;
5500 }
5501 FormSet->DriverHandle = DriverHandle;
5502 Status = gBS->HandleProtocol (
5503 DriverHandle,
5504 &gEfiHiiConfigAccessProtocolGuid,
5505 (VOID **) &FormSet->ConfigAccess
5506 );
5507 if (EFI_ERROR (Status)) {
5508 //
5509 // Configuration Driver don't attach ConfigAccess protocol to its HII package
5510 // list, then there will be no configuration action required
5511 //
5512 FormSet->ConfigAccess = NULL;
5513 }
5514
5515 //
5516 // Parse the IFR binary OpCodes
5517 //
5518 Status = ParseOpCodes (FormSet);
5519
5520 return Status;
5521 }
5522
5523
5524 /**
5525 Save globals used by previous call to SendForm(). SendForm() may be called from
5526 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
5527 So, save globals of previous call to SendForm() and restore them upon exit.
5528
5529 **/
5530 VOID
5531 SaveBrowserContext (
5532 VOID
5533 )
5534 {
5535 BROWSER_CONTEXT *Context;
5536 FORM_ENTRY_INFO *MenuList;
5537
5538 gBrowserContextCount++;
5539 if (gBrowserContextCount == 1) {
5540 //
5541 // This is not reentry of SendForm(), no context to save
5542 //
5543 return;
5544 }
5545
5546 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
5547 ASSERT (Context != NULL);
5548
5549 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
5550
5551 //
5552 // Save FormBrowser context
5553 //
5554 Context->Selection = gCurrentSelection;
5555 Context->ResetRequired = gResetRequired;
5556 Context->FlagReconnect = gFlagReconnect;
5557 Context->CallbackReconnect = gCallbackReconnect;
5558 Context->ExitRequired = gExitRequired;
5559 Context->HiiHandle = mCurrentHiiHandle;
5560 Context->FormId = mCurrentFormId;
5561 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
5562
5563 //
5564 // Save the menu history data.
5565 //
5566 InitializeListHead(&Context->FormHistoryList);
5567 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
5568 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
5569 RemoveEntryList (&MenuList->Link);
5570
5571 InsertTailList(&Context->FormHistoryList, &MenuList->Link);
5572 }
5573
5574 //
5575 // Insert to FormBrowser context list
5576 //
5577 InsertHeadList (&gBrowserContextList, &Context->Link);
5578 }
5579
5580
5581 /**
5582 Restore globals used by previous call to SendForm().
5583
5584 **/
5585 VOID
5586 RestoreBrowserContext (
5587 VOID
5588 )
5589 {
5590 LIST_ENTRY *Link;
5591 BROWSER_CONTEXT *Context;
5592 FORM_ENTRY_INFO *MenuList;
5593
5594 ASSERT (gBrowserContextCount != 0);
5595 gBrowserContextCount--;
5596 if (gBrowserContextCount == 0) {
5597 //
5598 // This is not reentry of SendForm(), no context to restore
5599 //
5600 return;
5601 }
5602
5603 ASSERT (!IsListEmpty (&gBrowserContextList));
5604
5605 Link = GetFirstNode (&gBrowserContextList);
5606 Context = BROWSER_CONTEXT_FROM_LINK (Link);
5607
5608 //
5609 // Restore FormBrowser context
5610 //
5611 gCurrentSelection = Context->Selection;
5612 gResetRequired = Context->ResetRequired;
5613 gFlagReconnect = Context->FlagReconnect;
5614 gCallbackReconnect = Context->CallbackReconnect;
5615 gExitRequired = Context->ExitRequired;
5616 mCurrentHiiHandle = Context->HiiHandle;
5617 mCurrentFormId = Context->FormId;
5618 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
5619
5620 //
5621 // Restore the menu history data.
5622 //
5623 while (!IsListEmpty (&Context->FormHistoryList)) {
5624 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
5625 RemoveEntryList (&MenuList->Link);
5626
5627 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
5628 }
5629
5630 //
5631 // Remove from FormBrowser context list
5632 //
5633 RemoveEntryList (&Context->Link);
5634 gBS->FreePool (Context);
5635 }
5636
5637 /**
5638 Find the matched FormSet context in the backup maintain list based on HiiHandle.
5639
5640 @param Handle The Hii Handle.
5641
5642 @return the found FormSet context. If no found, NULL will return.
5643
5644 **/
5645 FORM_BROWSER_FORMSET *
5646 GetFormSetFromHiiHandle (
5647 EFI_HII_HANDLE Handle
5648 )
5649 {
5650 LIST_ENTRY *Link;
5651 FORM_BROWSER_FORMSET *FormSet;
5652
5653 Link = GetFirstNode (&gBrowserFormSetList);
5654 while (!IsNull (&gBrowserFormSetList, Link)) {
5655 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5656 Link = GetNextNode (&gBrowserFormSetList, Link);
5657 if (!ValidateFormSet(FormSet)) {
5658 continue;
5659 }
5660 if (FormSet->HiiHandle == Handle) {
5661 return FormSet;
5662 }
5663 }
5664
5665 return NULL;
5666 }
5667
5668 /**
5669 Check whether the input HII handle is the FormSet that is being used.
5670
5671 @param Handle The Hii Handle.
5672
5673 @retval TRUE HII handle is being used.
5674 @retval FALSE HII handle is not being used.
5675
5676 **/
5677 BOOLEAN
5678 IsHiiHandleInBrowserContext (
5679 EFI_HII_HANDLE Handle
5680 )
5681 {
5682 LIST_ENTRY *Link;
5683 BROWSER_CONTEXT *Context;
5684
5685 //
5686 // HiiHandle is Current FormSet.
5687 //
5688 if (mCurrentHiiHandle == Handle) {
5689 return TRUE;
5690 }
5691
5692 //
5693 // Check whether HiiHandle is in BrowserContext.
5694 //
5695 Link = GetFirstNode (&gBrowserContextList);
5696 while (!IsNull (&gBrowserContextList, Link)) {
5697 Context = BROWSER_CONTEXT_FROM_LINK (Link);
5698 if (Context->HiiHandle == Handle) {
5699 //
5700 // HiiHandle is in BrowserContext
5701 //
5702 return TRUE;
5703 }
5704 Link = GetNextNode (&gBrowserContextList, Link);
5705 }
5706
5707 return FALSE;
5708 }
5709
5710 /**
5711 Perform Password check.
5712 Passwork may be encrypted by driver that requires the specific check.
5713
5714 @param Form Form where Password Statement is in.
5715 @param Statement Password statement
5716 @param PasswordString Password string to be checked. It may be NULL.
5717 NULL means to restore password.
5718 "" string can be used to checked whether old password does exist.
5719
5720 @return Status Status of Password check.
5721 **/
5722 EFI_STATUS
5723 EFIAPI
5724 PasswordCheck (
5725 IN FORM_DISPLAY_ENGINE_FORM *Form,
5726 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
5727 IN EFI_STRING PasswordString OPTIONAL
5728 )
5729 {
5730 EFI_STATUS Status;
5731 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5732 EFI_BROWSER_ACTION_REQUEST ActionRequest;
5733 EFI_IFR_TYPE_VALUE IfrTypeValue;
5734 FORM_BROWSER_STATEMENT *Question;
5735
5736 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
5737 Question = GetBrowserStatement(Statement);
5738 ASSERT (Question != NULL);
5739
5740 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
5741 if (ConfigAccess == NULL) {
5742 return EFI_UNSUPPORTED;
5743 }
5744 } else {
5745 if (PasswordString == NULL) {
5746 return EFI_SUCCESS;
5747 }
5748
5749 //
5750 // Check whether has preexisted password.
5751 //
5752 if (PasswordString[0] == 0) {
5753 if (*((CHAR16 *) Question->BufferValue) == 0) {
5754 return EFI_SUCCESS;
5755 } else {
5756 return EFI_NOT_READY;
5757 }
5758 }
5759
5760 //
5761 // Check whether the input password is same as preexisted password.
5762 //
5763 if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {
5764 return EFI_SUCCESS;
5765 } else {
5766 return EFI_NOT_READY;
5767 }
5768 }
5769
5770 //
5771 // Prepare password string in HII database
5772 //
5773 if (PasswordString != NULL) {
5774 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
5775 } else {
5776 IfrTypeValue.string = 0;
5777 }
5778
5779 //
5780 // Send password to Configuration Driver for validation
5781 //
5782 Status = ConfigAccess->Callback (
5783 ConfigAccess,
5784 EFI_BROWSER_ACTION_CHANGING,
5785 Question->QuestionId,
5786 Question->HiiValue.Type,
5787 &IfrTypeValue,
5788 &ActionRequest
5789 );
5790
5791 //
5792 // Remove password string from HII database
5793 //
5794 if (PasswordString != NULL) {
5795 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
5796 }
5797
5798 return Status;
5799 }
5800
5801 /**
5802 Find the registered HotKey based on KeyData.
5803
5804 @param[in] KeyData A pointer to a buffer that describes the keystroke
5805 information for the hot key.
5806
5807 @return The registered HotKey context. If no found, NULL will return.
5808 **/
5809 BROWSER_HOT_KEY *
5810 GetHotKeyFromRegisterList (
5811 IN EFI_INPUT_KEY *KeyData
5812 )
5813 {
5814 LIST_ENTRY *Link;
5815 BROWSER_HOT_KEY *HotKey;
5816
5817 Link = GetFirstNode (&gBrowserHotKeyList);
5818 while (!IsNull (&gBrowserHotKeyList, Link)) {
5819 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
5820 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
5821 return HotKey;
5822 }
5823 Link = GetNextNode (&gBrowserHotKeyList, Link);
5824 }
5825
5826 return NULL;
5827 }
5828
5829 /**
5830 Configure what scope the hot key will impact.
5831 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
5832 If no scope is set, the default scope will be FormSet level.
5833 After all registered hot keys are removed, previous Scope can reset to another level.
5834
5835 @param[in] Scope Scope level to be set.
5836
5837 @retval EFI_SUCCESS Scope is set correctly.
5838 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
5839 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
5840
5841 **/
5842 EFI_STATUS
5843 EFIAPI
5844 SetScope (
5845 IN BROWSER_SETTING_SCOPE Scope
5846 )
5847 {
5848 if (Scope >= MaxLevel) {
5849 return EFI_INVALID_PARAMETER;
5850 }
5851
5852 //
5853 // When no hot key registered in system or on the first setting,
5854 // Scope can be set.
5855 //
5856 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
5857 gBrowserSettingScope = Scope;
5858 mBrowserScopeFirstSet = FALSE;
5859 } else if (Scope != gBrowserSettingScope) {
5860 return EFI_UNSUPPORTED;
5861 }
5862
5863 return EFI_SUCCESS;
5864 }
5865
5866 /**
5867 Register the hot key with its browser action, or unregistered the hot key.
5868 Only support hot key that is not printable character (control key, function key, etc.).
5869 If the action value is zero, the hot key will be unregistered if it has been registered.
5870 If the same hot key has been registered, the new action and help string will override the previous ones.
5871
5872 @param[in] KeyData A pointer to a buffer that describes the keystroke
5873 information for the hot key. Its type is EFI_INPUT_KEY to
5874 be supported by all ConsoleIn devices.
5875 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
5876 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
5877 @param[in] HelpString Help string that describes the hot key information.
5878 Its value may be NULL for the unregistered hot key.
5879
5880 @retval EFI_SUCCESS Hot key is registered or unregistered.
5881 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
5882 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
5883 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
5884 **/
5885 EFI_STATUS
5886 EFIAPI
5887 RegisterHotKey (
5888 IN EFI_INPUT_KEY *KeyData,
5889 IN UINT32 Action,
5890 IN UINT16 DefaultId,
5891 IN EFI_STRING HelpString OPTIONAL
5892 )
5893 {
5894 BROWSER_HOT_KEY *HotKey;
5895
5896 //
5897 // Check input parameters.
5898 //
5899 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
5900 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
5901 return EFI_INVALID_PARAMETER;
5902 }
5903
5904 //
5905 // Check whether the input KeyData is in BrowserHotKeyList.
5906 //
5907 HotKey = GetHotKeyFromRegisterList (KeyData);
5908
5909 //
5910 // Unregister HotKey
5911 //
5912 if (Action == BROWSER_ACTION_UNREGISTER) {
5913 if (HotKey != NULL) {
5914 //
5915 // The registered HotKey is found.
5916 // Remove it from List, and free its resource.
5917 //
5918 RemoveEntryList (&HotKey->Link);
5919 FreePool (HotKey->KeyData);
5920 FreePool (HotKey->HelpString);
5921 return EFI_SUCCESS;
5922 } else {
5923 //
5924 // The registered HotKey is not found.
5925 //
5926 return EFI_NOT_FOUND;
5927 }
5928 }
5929
5930 //
5931 // Register HotKey into List.
5932 //
5933 if (HotKey == NULL) {
5934 //
5935 // Create new Key, and add it into List.
5936 //
5937 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
5938 ASSERT (HotKey != NULL);
5939 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
5940 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
5941 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
5942 }
5943
5944 //
5945 // Fill HotKey information.
5946 //
5947 HotKey->Action = Action;
5948 HotKey->DefaultId = DefaultId;
5949 if (HotKey->HelpString != NULL) {
5950 FreePool (HotKey->HelpString);
5951 }
5952 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
5953
5954 return EFI_SUCCESS;
5955 }
5956
5957 /**
5958 Register Exit handler function.
5959 When more than one handler function is registered, the latter one will override the previous one.
5960 When NULL handler is specified, the previous Exit handler will be unregistered.
5961
5962 @param[in] Handler Pointer to handler function.
5963
5964 **/
5965 VOID
5966 EFIAPI
5967 RegiserExitHandler (
5968 IN EXIT_HANDLER Handler
5969 )
5970 {
5971 ExitHandlerFunction = Handler;
5972 return;
5973 }
5974
5975 /**
5976 Check whether the browser data has been modified.
5977
5978 @retval TRUE Browser data is modified.
5979 @retval FALSE No browser data is modified.
5980
5981 **/
5982 BOOLEAN
5983 EFIAPI
5984 IsBrowserDataModified (
5985 VOID
5986 )
5987 {
5988 LIST_ENTRY *Link;
5989 FORM_BROWSER_FORMSET *FormSet;
5990
5991 switch (gBrowserSettingScope) {
5992 case FormLevel:
5993 if (gCurrentSelection == NULL) {
5994 return FALSE;
5995 }
5996 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
5997
5998 case FormSetLevel:
5999 if (gCurrentSelection == NULL) {
6000 return FALSE;
6001 }
6002 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
6003
6004 case SystemLevel:
6005 Link = GetFirstNode (&gBrowserFormSetList);
6006 while (!IsNull (&gBrowserFormSetList, Link)) {
6007 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6008 if (!ValidateFormSet(FormSet)) {
6009 continue;
6010 }
6011
6012 if (IsNvUpdateRequiredForFormSet (FormSet)) {
6013 return TRUE;
6014 }
6015 Link = GetNextNode (&gBrowserFormSetList, Link);
6016 }
6017 return FALSE;
6018
6019 default:
6020 return FALSE;
6021 }
6022 }
6023
6024 /**
6025 Execute the action requested by the Action parameter.
6026
6027 @param[in] Action Execute the request action.
6028 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
6029
6030 @retval EFI_SUCCESS Execute the request action succss.
6031 @retval EFI_INVALID_PARAMETER The input action value is invalid.
6032
6033 **/
6034 EFI_STATUS
6035 EFIAPI
6036 ExecuteAction (
6037 IN UINT32 Action,
6038 IN UINT16 DefaultId
6039 )
6040 {
6041 EFI_STATUS Status;
6042 FORM_BROWSER_FORMSET *FormSet;
6043 FORM_BROWSER_FORM *Form;
6044
6045 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
6046 return EFI_NOT_READY;
6047 }
6048
6049 Status = EFI_SUCCESS;
6050 FormSet = NULL;
6051 Form = NULL;
6052 if (gBrowserSettingScope < SystemLevel) {
6053 FormSet = gCurrentSelection->FormSet;
6054 Form = gCurrentSelection->Form;
6055 }
6056
6057 //
6058 // Executet the discard action.
6059 //
6060 if ((Action & BROWSER_ACTION_DISCARD) != 0) {
6061 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
6062 if (EFI_ERROR (Status)) {
6063 return Status;
6064 }
6065 }
6066
6067 //
6068 // Executet the difault action.
6069 //
6070 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
6071 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
6072 if (EFI_ERROR (Status)) {
6073 return Status;
6074 }
6075 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
6076 }
6077
6078 //
6079 // Executet the submit action.
6080 //
6081 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
6082 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
6083 if (EFI_ERROR (Status)) {
6084 return Status;
6085 }
6086 }
6087
6088 //
6089 // Executet the reset action.
6090 //
6091 if ((Action & BROWSER_ACTION_RESET) != 0) {
6092 gResetRequired = TRUE;
6093 }
6094
6095 //
6096 // Executet the exit action.
6097 //
6098 if ((Action & BROWSER_ACTION_EXIT) != 0) {
6099 DiscardForm (FormSet, Form, gBrowserSettingScope);
6100 if (gBrowserSettingScope == SystemLevel) {
6101 if (ExitHandlerFunction != NULL) {
6102 ExitHandlerFunction ();
6103 }
6104 }
6105
6106 gExitRequired = TRUE;
6107 }
6108
6109 return Status;
6110 }
6111
6112 /**
6113 Create reminder to let user to choose save or discard the changed browser data.
6114 Caller can use it to actively check the changed browser data.
6115
6116 @retval BROWSER_NO_CHANGES No browser data is changed.
6117 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
6118 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
6119 @retval BROWSER_KEEP_CURRENT Browser keep current changes.
6120
6121 **/
6122 UINT32
6123 EFIAPI
6124 SaveReminder (
6125 VOID
6126 )
6127 {
6128 LIST_ENTRY *Link;
6129 FORM_BROWSER_FORMSET *FormSet;
6130 BOOLEAN IsDataChanged;
6131 UINT32 DataSavedAction;
6132 UINT32 ConfirmRet;
6133
6134 DataSavedAction = BROWSER_NO_CHANGES;
6135 IsDataChanged = FALSE;
6136 Link = GetFirstNode (&gBrowserFormSetList);
6137 while (!IsNull (&gBrowserFormSetList, Link)) {
6138 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6139 Link = GetNextNode (&gBrowserFormSetList, Link);
6140 if (!ValidateFormSet(FormSet)) {
6141 continue;
6142 }
6143 if (IsNvUpdateRequiredForFormSet (FormSet)) {
6144 IsDataChanged = TRUE;
6145 break;
6146 }
6147 }
6148
6149 //
6150 // No data is changed. No save is required.
6151 //
6152 if (!IsDataChanged) {
6153 return DataSavedAction;
6154 }
6155
6156 //
6157 // If data is changed, prompt user to save or discard it.
6158 //
6159 do {
6160 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
6161
6162 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
6163 SubmitForm (NULL, NULL, SystemLevel);
6164 DataSavedAction = BROWSER_SAVE_CHANGES;
6165 break;
6166 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
6167 DiscardForm (NULL, NULL, SystemLevel);
6168 DataSavedAction = BROWSER_DISCARD_CHANGES;
6169 break;
6170 } else if (ConfirmRet == BROWSER_ACTION_NONE) {
6171 DataSavedAction = BROWSER_KEEP_CURRENT;
6172 break;
6173 }
6174 } while (1);
6175
6176 return DataSavedAction;
6177 }
6178
6179 /**
6180 Check whether the Reset Required for the browser
6181
6182 @retval TRUE Browser required to reset after exit.
6183 @retval FALSE Browser not need to reset after exit.
6184
6185 **/
6186 BOOLEAN
6187 EFIAPI
6188 IsResetRequired (
6189 VOID
6190 )
6191 {
6192 return gResetRequired;
6193 }
6194