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