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