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