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