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