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