]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
Refine code to make it more safely.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Setup.c
1 /** @file
2 Entry and initialization module for the browser.
3
4 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Setup.h"
16
17 SETUP_DRIVER_PRIVATE_DATA mPrivateData = {
18 SETUP_DRIVER_SIGNATURE,
19 NULL,
20 {
21 SendForm,
22 BrowserCallback
23 },
24 {
25 SetScope,
26 RegisterHotKey,
27 RegiserExitHandler,
28 SaveReminder
29 },
30 {
31 BROWSER_EXTENSION2_VERSION_1_1,
32 SetScope,
33 RegisterHotKey,
34 RegiserExitHandler,
35 IsBrowserDataModified,
36 ExecuteAction,
37 {NULL,NULL},
38 {NULL,NULL},
39 IsResetRequired
40 }
41 };
42
43 EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
44 EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
45 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
46 EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
47
48 UINTN gBrowserContextCount = 0;
49 LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
50 LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
51 LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
52 LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
53
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 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
2266 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
2267 } else {
2268 TypeValue = &Question->HiiValue.Value;
2269 }
2270
2271 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2272 FormSet->ConfigAccess->Callback (
2273 FormSet->ConfigAccess,
2274 EFI_BROWSER_ACTION_CHANGED,
2275 Question->QuestionId,
2276 Question->HiiValue.Type,
2277 TypeValue,
2278 &ActionRequest
2279 );
2280 }
2281 }
2282
2283 /**
2284 Validate the FormSet. If the formset is not validate, remove it from the list.
2285
2286 @param FormSet The input FormSet which need to validate.
2287
2288 @retval TRUE The handle is validate.
2289 @retval FALSE The handle is invalidate.
2290
2291 **/
2292 BOOLEAN
2293 ValidateFormSet (
2294 FORM_BROWSER_FORMSET *FormSet
2295 )
2296 {
2297 EFI_HII_HANDLE *HiiHandles;
2298 UINTN Index;
2299 BOOLEAN Find;
2300
2301 ASSERT (FormSet != NULL);
2302 Find = FALSE;
2303 //
2304 // Get all the Hii handles
2305 //
2306 HiiHandles = HiiGetHiiHandles (NULL);
2307 ASSERT (HiiHandles != NULL);
2308
2309 //
2310 // Search for formset of each class type
2311 //
2312 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
2313 if (HiiHandles[Index] == FormSet->HiiHandle) {
2314 Find = TRUE;
2315 break;
2316 }
2317 }
2318
2319 if (!Find) {
2320 CleanBrowserStorage(FormSet);
2321 RemoveEntryList (&FormSet->Link);
2322 DestroyFormSet (FormSet);
2323 }
2324
2325 FreePool (HiiHandles);
2326
2327 return Find;
2328 }
2329 /**
2330 Check whether need to enable the reset flag in form level.
2331 Also clean all ValueChanged flag in question.
2332
2333 @param SetFlag Whether need to set the Reset Flag.
2334 @param Form Form data structure.
2335
2336 **/
2337 VOID
2338 UpdateFlagForForm (
2339 IN BOOLEAN SetFlag,
2340 IN FORM_BROWSER_FORM *Form
2341 )
2342 {
2343 LIST_ENTRY *Link;
2344 FORM_BROWSER_STATEMENT *Question;
2345 BOOLEAN FindOne;
2346
2347 FindOne = FALSE;
2348 Link = GetFirstNode (&Form->StatementListHead);
2349 while (!IsNull (&Form->StatementListHead, Link)) {
2350 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2351
2352 if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {
2353 gResetRequired = TRUE;
2354 }
2355
2356 if (Question->ValueChanged) {
2357 Question->ValueChanged = FALSE;
2358 }
2359
2360 Link = GetNextNode (&Form->StatementListHead, Link);
2361 }
2362 }
2363
2364 /**
2365 Check whether need to enable the reset flag.
2366 Also clean ValueChanged flag for all statements.
2367
2368 Form level or formset level, only one.
2369
2370 @param SetFlag Whether need to set the Reset Flag.
2371 @param FormSet FormSet data structure.
2372 @param Form Form data structure.
2373
2374 **/
2375 VOID
2376 ValueChangeResetFlagUpdate (
2377 IN BOOLEAN SetFlag,
2378 IN FORM_BROWSER_FORMSET *FormSet,
2379 IN FORM_BROWSER_FORM *Form
2380 )
2381 {
2382 FORM_BROWSER_FORM *CurrentForm;
2383 LIST_ENTRY *Link;
2384
2385 //
2386 // Form != NULL means only check form level.
2387 //
2388 if (Form != NULL) {
2389 UpdateFlagForForm(SetFlag, Form);
2390 return;
2391 }
2392
2393 Link = GetFirstNode (&FormSet->FormListHead);
2394 while (!IsNull (&FormSet->FormListHead, Link)) {
2395 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
2396 Link = GetNextNode (&FormSet->FormListHead, Link);
2397
2398 UpdateFlagForForm(SetFlag, CurrentForm);
2399 }
2400 }
2401
2402 /**
2403 Discard data based on the input setting scope (Form, FormSet or System).
2404
2405 @param FormSet FormSet data structure.
2406 @param Form Form data structure.
2407 @param SettingScope Setting Scope for Discard action.
2408
2409 @retval EFI_SUCCESS The function completed successfully.
2410 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2411
2412 **/
2413 EFI_STATUS
2414 DiscardForm (
2415 IN FORM_BROWSER_FORMSET *FormSet,
2416 IN FORM_BROWSER_FORM *Form,
2417 IN BROWSER_SETTING_SCOPE SettingScope
2418 )
2419 {
2420 LIST_ENTRY *Link;
2421 FORMSET_STORAGE *Storage;
2422 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2423 FORM_BROWSER_FORMSET *LocalFormSet;
2424 FORM_BROWSER_FORMSET *OldFormSet;
2425
2426 //
2427 // Check the supported setting level.
2428 //
2429 if (SettingScope >= MaxLevel) {
2430 return EFI_UNSUPPORTED;
2431 }
2432
2433 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
2434 ConfigInfo = NULL;
2435 Link = GetFirstNode (&Form->ConfigRequestHead);
2436 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2437 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2438 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2439
2440 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2441 continue;
2442 }
2443
2444 //
2445 // Skip if there is no RequestElement
2446 //
2447 if (ConfigInfo->ElementCount == 0) {
2448 continue;
2449 }
2450
2451 //
2452 // Prepare <ConfigResp>
2453 //
2454 SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
2455
2456 //
2457 // Call callback with Changed type to inform the driver.
2458 //
2459 SendDiscardInfoToDriver (FormSet, Form);
2460 }
2461
2462 ValueChangeResetFlagUpdate (FALSE, NULL, Form);
2463 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
2464
2465 //
2466 // Discard Buffer storage or Name/Value storage
2467 //
2468 Link = GetFirstNode (&FormSet->StorageListHead);
2469 while (!IsNull (&FormSet->StorageListHead, Link)) {
2470 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2471 Link = GetNextNode (&FormSet->StorageListHead, Link);
2472
2473 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2474 continue;
2475 }
2476
2477 //
2478 // Skip if there is no RequestElement
2479 //
2480 if (Storage->ElementCount == 0) {
2481 continue;
2482 }
2483
2484 SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
2485 }
2486
2487 Link = GetFirstNode (&FormSet->FormListHead);
2488 while (!IsNull (&FormSet->FormListHead, Link)) {
2489 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2490 Link = GetNextNode (&FormSet->FormListHead, Link);
2491
2492 //
2493 // Call callback with Changed type to inform the driver.
2494 //
2495 SendDiscardInfoToDriver (FormSet, Form);
2496 }
2497
2498 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
2499 } else if (SettingScope == SystemLevel) {
2500 //
2501 // System Level Discard.
2502 //
2503 OldFormSet = mSystemLevelFormSet;
2504
2505 //
2506 // Discard changed value for each FormSet in the maintain list.
2507 //
2508 Link = GetFirstNode (&gBrowserFormSetList);
2509 while (!IsNull (&gBrowserFormSetList, Link)) {
2510 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2511 Link = GetNextNode (&gBrowserFormSetList, Link);
2512 if (!ValidateFormSet(LocalFormSet)) {
2513 continue;
2514 }
2515
2516 mSystemLevelFormSet = LocalFormSet;
2517
2518 DiscardForm (LocalFormSet, NULL, FormSetLevel);
2519 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2520 //
2521 // Remove maintain backup list after discard except for the current using FormSet.
2522 //
2523 CleanBrowserStorage(LocalFormSet);
2524 RemoveEntryList (&LocalFormSet->Link);
2525 DestroyFormSet (LocalFormSet);
2526 }
2527 }
2528
2529 mSystemLevelFormSet = OldFormSet;
2530 }
2531
2532 return EFI_SUCCESS;
2533 }
2534
2535 /**
2536 Submit data based on the input Setting level (Form, FormSet or System).
2537
2538 @param FormSet FormSet data structure.
2539 @param Form Form data structure.
2540 @param SettingScope Setting Scope for Submit action.
2541
2542 @retval EFI_SUCCESS The function completed successfully.
2543 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2544
2545 **/
2546 EFI_STATUS
2547 SubmitForm (
2548 IN FORM_BROWSER_FORMSET *FormSet,
2549 IN FORM_BROWSER_FORM *Form,
2550 IN BROWSER_SETTING_SCOPE SettingScope
2551 )
2552 {
2553 EFI_STATUS Status;
2554 LIST_ENTRY *Link;
2555 EFI_STRING ConfigResp;
2556 EFI_STRING Progress;
2557 BROWSER_STORAGE *Storage;
2558 FORMSET_STORAGE *FormSetStorage;
2559 FORM_BROWSER_FORMSET *LocalFormSet;
2560 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2561
2562 //
2563 // Check the supported setting level.
2564 //
2565 if (SettingScope >= MaxLevel) {
2566 return EFI_UNSUPPORTED;
2567 }
2568
2569 //
2570 // Validate the Form by NoSubmit check
2571 //
2572 Status = EFI_SUCCESS;
2573 if (SettingScope == FormLevel) {
2574 Status = NoSubmitCheck (FormSet, Form);
2575 } else if (SettingScope == FormSetLevel) {
2576 Status = NoSubmitCheck (FormSet, NULL);
2577 }
2578 if (EFI_ERROR (Status)) {
2579 return Status;
2580 }
2581
2582 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
2583 ConfigInfo = NULL;
2584 Link = GetFirstNode (&Form->ConfigRequestHead);
2585 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2586 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2587 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2588
2589 Storage = ConfigInfo->Storage;
2590 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2591 continue;
2592 }
2593
2594 //
2595 // Skip if there is no RequestElement
2596 //
2597 if (ConfigInfo->ElementCount == 0) {
2598 continue;
2599 }
2600
2601 //
2602 // 1. Prepare <ConfigResp>
2603 //
2604 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
2605 if (EFI_ERROR (Status)) {
2606 return Status;
2607 }
2608
2609 //
2610 // 2. Set value to hii config routine protocol.
2611 //
2612 Status = mHiiConfigRouting->RouteConfig (
2613 mHiiConfigRouting,
2614 ConfigResp,
2615 &Progress
2616 );
2617 if (EFI_ERROR (Status)) {
2618 FreePool (ConfigResp);
2619 return Status;
2620 }
2621
2622 FreePool (ConfigResp);
2623 //
2624 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
2625 //
2626 SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
2627 }
2628
2629 //
2630 // 4. Update the NV flag.
2631 //
2632 ValueChangeResetFlagUpdate(TRUE, NULL, Form);
2633 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
2634 //
2635 // Submit Buffer storage or Name/Value storage
2636 //
2637 Link = GetFirstNode (&FormSet->StorageListHead);
2638 while (!IsNull (&FormSet->StorageListHead, Link)) {
2639 FormSetStorage = (FORMSET_STORAGE_FROM_LINK (Link));
2640 Storage = FormSetStorage->BrowserStorage;
2641 Link = GetNextNode (&FormSet->StorageListHead, Link);
2642
2643 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2644 continue;
2645 }
2646
2647 //
2648 // Skip if there is no RequestElement
2649 //
2650 if (FormSetStorage->ElementCount == 0) {
2651 continue;
2652 }
2653
2654 //
2655 // 1. Prepare <ConfigResp>
2656 //
2657 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
2658 if (EFI_ERROR (Status)) {
2659 return Status;
2660 }
2661
2662 //
2663 // 2. Send <ConfigResp> to Routine config Protocol.
2664 //
2665 Status = mHiiConfigRouting->RouteConfig (
2666 mHiiConfigRouting,
2667 ConfigResp,
2668 &Progress
2669 );
2670 if (EFI_ERROR (Status)) {
2671 FreePool (ConfigResp);
2672 return Status;
2673 }
2674
2675 FreePool (ConfigResp);
2676 //
2677 // 3. Config success, update storage shadow Buffer
2678 //
2679 SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE);
2680 }
2681
2682 //
2683 // 4. Update the NV flag.
2684 //
2685 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
2686 } else if (SettingScope == SystemLevel) {
2687 //
2688 // System Level Save.
2689 //
2690
2691 //
2692 // Save changed value for each FormSet in the maintain list.
2693 //
2694 Link = GetFirstNode (&gBrowserFormSetList);
2695 while (!IsNull (&gBrowserFormSetList, Link)) {
2696 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2697 Link = GetNextNode (&gBrowserFormSetList, Link);
2698 if (!ValidateFormSet(LocalFormSet)) {
2699 continue;
2700 }
2701 SubmitForm (LocalFormSet, NULL, FormSetLevel);
2702 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2703 //
2704 // Remove maintain backup list after save except for the current using FormSet.
2705 //
2706 CleanBrowserStorage(LocalFormSet);
2707 RemoveEntryList (&LocalFormSet->Link);
2708 DestroyFormSet (LocalFormSet);
2709 }
2710 }
2711 }
2712
2713 return EFI_SUCCESS;
2714 }
2715
2716 /**
2717 Get Question default value from AltCfg string.
2718
2719 @param FormSet The form set.
2720 @param Question The question.
2721 @param DefaultId The default Id.
2722
2723 @retval EFI_SUCCESS Question is reset to default value.
2724
2725 **/
2726 EFI_STATUS
2727 GetDefaultValueFromAltCfg (
2728 IN FORM_BROWSER_FORMSET *FormSet,
2729 IN OUT FORM_BROWSER_STATEMENT *Question,
2730 IN UINT16 DefaultId
2731 )
2732 {
2733 BOOLEAN IsBufferStorage;
2734 BOOLEAN IsString;
2735 UINTN Length;
2736 BROWSER_STORAGE *Storage;
2737 CHAR16 *ConfigRequest;
2738 CHAR16 *Progress;
2739 CHAR16 *Result;
2740 CHAR16 *ConfigResp;
2741 CHAR16 *Value;
2742 CHAR16 *StringPtr;
2743 UINTN LengthStr;
2744 UINT8 *Dst;
2745 CHAR16 TemStr[5];
2746 UINTN Index;
2747 UINT8 DigitUint8;
2748 EFI_STATUS Status;
2749
2750 Status = EFI_NOT_FOUND;
2751 Length = 0;
2752 Dst = NULL;
2753 ConfigRequest = NULL;
2754 Result = NULL;
2755 ConfigResp = NULL;
2756 Value = NULL;
2757 Storage = Question->Storage;
2758
2759 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
2760 return Status;
2761 }
2762
2763 //
2764 // Question Value is provided by Buffer Storage or NameValue Storage
2765 //
2766 if (Question->BufferValue != NULL) {
2767 //
2768 // This Question is password or orderedlist
2769 //
2770 Dst = Question->BufferValue;
2771 } else {
2772 //
2773 // Other type of Questions
2774 //
2775 Dst = (UINT8 *) &Question->HiiValue.Value;
2776 }
2777
2778 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
2779 IsBufferStorage = TRUE;
2780 } else {
2781 IsBufferStorage = FALSE;
2782 }
2783 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
2784
2785 //
2786 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
2787 // <ConfigHdr> + "&" + <VariableName>
2788 //
2789 if (IsBufferStorage) {
2790 Length = StrLen (Storage->ConfigHdr);
2791 Length += StrLen (Question->BlockName);
2792 } else {
2793 Length = StrLen (Storage->ConfigHdr);
2794 Length += StrLen (Question->VariableName) + 1;
2795 }
2796 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
2797 ASSERT (ConfigRequest != NULL);
2798
2799 StrCpy (ConfigRequest, Storage->ConfigHdr);
2800 if (IsBufferStorage) {
2801 StrCat (ConfigRequest, Question->BlockName);
2802 } else {
2803 StrCat (ConfigRequest, L"&");
2804 StrCat (ConfigRequest, Question->VariableName);
2805 }
2806
2807 Status = mHiiConfigRouting->ExtractConfig (
2808 mHiiConfigRouting,
2809 ConfigRequest,
2810 &Progress,
2811 &Result
2812 );
2813 if (EFI_ERROR (Status)) {
2814 goto Done;
2815 }
2816
2817 //
2818 // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
2819 // Get the default configuration string according to the default ID.
2820 //
2821 Status = mHiiConfigRouting->GetAltConfig (
2822 mHiiConfigRouting,
2823 Result,
2824 &Storage->Guid,
2825 Storage->Name,
2826 NULL,
2827 &DefaultId, // it can be NULL to get the current setting.
2828 &ConfigResp
2829 );
2830
2831 //
2832 // The required setting can't be found. So, it is not required to be validated and set.
2833 //
2834 if (EFI_ERROR (Status)) {
2835 goto Done;
2836 }
2837
2838 if (ConfigResp == NULL) {
2839 Status = EFI_NOT_FOUND;
2840 goto Done;
2841 }
2842
2843 //
2844 // Skip <ConfigRequest>
2845 //
2846 if (IsBufferStorage) {
2847 Value = StrStr (ConfigResp, L"&VALUE");
2848 ASSERT (Value != NULL);
2849 //
2850 // Skip "&VALUE"
2851 //
2852 Value = Value + 6;
2853 } else {
2854 Value = StrStr (ConfigResp, Question->VariableName);
2855 ASSERT (Value != NULL);
2856
2857 Value = Value + StrLen (Question->VariableName);
2858 }
2859 if (*Value != '=') {
2860 Status = EFI_NOT_FOUND;
2861 goto Done;
2862 }
2863 //
2864 // Skip '=', point to value
2865 //
2866 Value = Value + 1;
2867
2868 //
2869 // Suppress <AltResp> if any
2870 //
2871 StringPtr = Value;
2872 while (*StringPtr != L'\0' && *StringPtr != L'&') {
2873 StringPtr++;
2874 }
2875 *StringPtr = L'\0';
2876
2877 LengthStr = StrLen (Value);
2878 if (!IsBufferStorage && IsString) {
2879 StringPtr = (CHAR16 *) Dst;
2880 ZeroMem (TemStr, sizeof (TemStr));
2881 for (Index = 0; Index < LengthStr; Index += 4) {
2882 StrnCpy (TemStr, Value + Index, 4);
2883 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
2884 }
2885 //
2886 // Add tailing L'\0' character
2887 //
2888 StringPtr[Index/4] = L'\0';
2889 } else {
2890 ZeroMem (TemStr, sizeof (TemStr));
2891 for (Index = 0; Index < LengthStr; Index ++) {
2892 TemStr[0] = Value[LengthStr - Index - 1];
2893 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
2894 if ((Index & 1) == 0) {
2895 Dst [Index/2] = DigitUint8;
2896 } else {
2897 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
2898 }
2899 }
2900 }
2901
2902 Done:
2903 if (ConfigRequest != NULL){
2904 FreePool (ConfigRequest);
2905 }
2906
2907 if (ConfigResp != NULL) {
2908 FreePool (ConfigResp);
2909 }
2910
2911 if (Result != NULL) {
2912 FreePool (Result);
2913 }
2914
2915 return Status;
2916 }
2917
2918 /**
2919 Get default Id value used for browser.
2920
2921 @param DefaultId The default id value used by hii.
2922
2923 @retval Browser used default value.
2924
2925 **/
2926 INTN
2927 GetDefaultIdForCallBack (
2928 UINTN DefaultId
2929 )
2930 {
2931 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
2932 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
2933 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2934 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
2935 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
2936 return EFI_BROWSER_ACTION_DEFAULT_SAFE;
2937 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
2938 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
2939 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
2940 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
2941 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
2942 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
2943 } else {
2944 return -1;
2945 }
2946 }
2947
2948
2949
2950 /**
2951 Return data element in an Array by its Index.
2952
2953 @param Array The data array.
2954 @param Type Type of the data in this array.
2955 @param Index Zero based index for data in this array.
2956
2957 @retval Value The data to be returned
2958
2959 **/
2960 UINT64
2961 GetArrayData (
2962 IN VOID *Array,
2963 IN UINT8 Type,
2964 IN UINTN Index
2965 )
2966 {
2967 UINT64 Data;
2968
2969 ASSERT (Array != NULL);
2970
2971 Data = 0;
2972 switch (Type) {
2973 case EFI_IFR_TYPE_NUM_SIZE_8:
2974 Data = (UINT64) *(((UINT8 *) Array) + Index);
2975 break;
2976
2977 case EFI_IFR_TYPE_NUM_SIZE_16:
2978 Data = (UINT64) *(((UINT16 *) Array) + Index);
2979 break;
2980
2981 case EFI_IFR_TYPE_NUM_SIZE_32:
2982 Data = (UINT64) *(((UINT32 *) Array) + Index);
2983 break;
2984
2985 case EFI_IFR_TYPE_NUM_SIZE_64:
2986 Data = (UINT64) *(((UINT64 *) Array) + Index);
2987 break;
2988
2989 default:
2990 break;
2991 }
2992
2993 return Data;
2994 }
2995
2996
2997 /**
2998 Set value of a data element in an Array by its Index.
2999
3000 @param Array The data array.
3001 @param Type Type of the data in this array.
3002 @param Index Zero based index for data in this array.
3003 @param Value The value to be set.
3004
3005 **/
3006 VOID
3007 SetArrayData (
3008 IN VOID *Array,
3009 IN UINT8 Type,
3010 IN UINTN Index,
3011 IN UINT64 Value
3012 )
3013 {
3014
3015 ASSERT (Array != NULL);
3016
3017 switch (Type) {
3018 case EFI_IFR_TYPE_NUM_SIZE_8:
3019 *(((UINT8 *) Array) + Index) = (UINT8) Value;
3020 break;
3021
3022 case EFI_IFR_TYPE_NUM_SIZE_16:
3023 *(((UINT16 *) Array) + Index) = (UINT16) Value;
3024 break;
3025
3026 case EFI_IFR_TYPE_NUM_SIZE_32:
3027 *(((UINT32 *) Array) + Index) = (UINT32) Value;
3028 break;
3029
3030 case EFI_IFR_TYPE_NUM_SIZE_64:
3031 *(((UINT64 *) Array) + Index) = (UINT64) Value;
3032 break;
3033
3034 default:
3035 break;
3036 }
3037 }
3038
3039 /**
3040 Search an Option of a Question by its value.
3041
3042 @param Question The Question
3043 @param OptionValue Value for Option to be searched.
3044
3045 @retval Pointer Pointer to the found Option.
3046 @retval NULL Option not found.
3047
3048 **/
3049 QUESTION_OPTION *
3050 ValueToOption (
3051 IN FORM_BROWSER_STATEMENT *Question,
3052 IN EFI_HII_VALUE *OptionValue
3053 )
3054 {
3055 LIST_ENTRY *Link;
3056 QUESTION_OPTION *Option;
3057 INTN Result;
3058
3059 Link = GetFirstNode (&Question->OptionListHead);
3060 while (!IsNull (&Question->OptionListHead, Link)) {
3061 Option = QUESTION_OPTION_FROM_LINK (Link);
3062
3063 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
3064 //
3065 // Check the suppressif condition, only a valid option can be return.
3066 //
3067 if ((Option->SuppressExpression == NULL) ||
3068 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
3069 return Option;
3070 }
3071 }
3072
3073 Link = GetNextNode (&Question->OptionListHead, Link);
3074 }
3075
3076 return NULL;
3077 }
3078
3079
3080 /**
3081 Reset Question to its default value.
3082
3083 @param FormSet The form set.
3084 @param Form The form.
3085 @param Question The question.
3086 @param DefaultId The Class of the default.
3087
3088 @retval EFI_SUCCESS Question is reset to default value.
3089
3090 **/
3091 EFI_STATUS
3092 GetQuestionDefault (
3093 IN FORM_BROWSER_FORMSET *FormSet,
3094 IN FORM_BROWSER_FORM *Form,
3095 IN FORM_BROWSER_STATEMENT *Question,
3096 IN UINT16 DefaultId
3097 )
3098 {
3099 EFI_STATUS Status;
3100 LIST_ENTRY *Link;
3101 QUESTION_DEFAULT *Default;
3102 QUESTION_OPTION *Option;
3103 EFI_HII_VALUE *HiiValue;
3104 UINT8 Index;
3105 EFI_STRING StrValue;
3106 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
3107 EFI_BROWSER_ACTION_REQUEST ActionRequest;
3108 INTN Action;
3109 CHAR16 *NewString;
3110
3111 Status = EFI_NOT_FOUND;
3112 StrValue = NULL;
3113
3114 //
3115 // Statement don't have storage, skip them
3116 //
3117 if (Question->QuestionId == 0) {
3118 return Status;
3119 }
3120
3121 //
3122 // There are Five ways to specify default value for a Question:
3123 // 1, use call back function (highest priority)
3124 // 2, use ExtractConfig function
3125 // 3, use nested EFI_IFR_DEFAULT
3126 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
3127 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
3128 //
3129 HiiValue = &Question->HiiValue;
3130
3131 //
3132 // Get Question defaut value from call back function.
3133 //
3134 ConfigAccess = FormSet->ConfigAccess;
3135 Action = GetDefaultIdForCallBack (DefaultId);
3136 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
3137 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
3138 Status = ConfigAccess->Callback (
3139 ConfigAccess,
3140 Action,
3141 Question->QuestionId,
3142 HiiValue->Type,
3143 &HiiValue->Value,
3144 &ActionRequest
3145 );
3146 if (!EFI_ERROR (Status)) {
3147 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3148 NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
3149 ASSERT (NewString != NULL);
3150
3151 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
3152 if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
3153 CopyMem (Question->BufferValue, NewString, StrSize (NewString));
3154 } else {
3155 CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
3156 }
3157
3158 FreePool (NewString);
3159 }
3160 return Status;
3161 }
3162 }
3163
3164 //
3165 // Get default value from altcfg string.
3166 //
3167 if (ConfigAccess != NULL) {
3168 Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);
3169 if (!EFI_ERROR (Status)) {
3170 return Status;
3171 }
3172 }
3173
3174 //
3175 // EFI_IFR_DEFAULT has highest priority
3176 //
3177 if (!IsListEmpty (&Question->DefaultListHead)) {
3178 Link = GetFirstNode (&Question->DefaultListHead);
3179 while (!IsNull (&Question->DefaultListHead, Link)) {
3180 Default = QUESTION_DEFAULT_FROM_LINK (Link);
3181
3182 if (Default->DefaultId == DefaultId) {
3183 if (Default->ValueExpression != NULL) {
3184 //
3185 // Default is provided by an Expression, evaluate it
3186 //
3187 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
3188 if (EFI_ERROR (Status)) {
3189 return Status;
3190 }
3191
3192 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
3193 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
3194 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
3195 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
3196 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
3197 } else {
3198 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
3199 Question->HiiValue.BufferLen = Question->StorageWidth;
3200 }
3201 FreePool (Default->ValueExpression->Result.Buffer);
3202 }
3203 HiiValue->Type = Default->ValueExpression->Result.Type;
3204 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
3205 } else {
3206 //
3207 // Default value is embedded in EFI_IFR_DEFAULT
3208 //
3209 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
3210 }
3211
3212 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3213 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
3214 if (StrValue == NULL) {
3215 return EFI_NOT_FOUND;
3216 }
3217 if (Question->StorageWidth > StrSize (StrValue)) {
3218 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
3219 } else {
3220 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
3221 }
3222 }
3223
3224 return EFI_SUCCESS;
3225 }
3226
3227 Link = GetNextNode (&Question->DefaultListHead, Link);
3228 }
3229 }
3230
3231 //
3232 // EFI_ONE_OF_OPTION
3233 //
3234 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
3235 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3236 //
3237 // OneOfOption could only provide Standard and Manufacturing default
3238 //
3239 Link = GetFirstNode (&Question->OptionListHead);
3240 while (!IsNull (&Question->OptionListHead, Link)) {
3241 Option = QUESTION_OPTION_FROM_LINK (Link);
3242 Link = GetNextNode (&Question->OptionListHead, Link);
3243
3244 if ((Option->SuppressExpression != NULL) &&
3245 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3246 continue;
3247 }
3248
3249 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
3250 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
3251 ) {
3252 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3253
3254 return EFI_SUCCESS;
3255 }
3256 }
3257 }
3258 }
3259
3260 //
3261 // EFI_IFR_CHECKBOX - lowest priority
3262 //
3263 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
3264 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3265 //
3266 // Checkbox could only provide Standard and Manufacturing default
3267 //
3268 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
3269 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
3270 ) {
3271 HiiValue->Value.b = TRUE;
3272 } else {
3273 HiiValue->Value.b = FALSE;
3274 }
3275
3276 return EFI_SUCCESS;
3277 }
3278 }
3279
3280 //
3281 // For Questions without default
3282 //
3283 Status = EFI_NOT_FOUND;
3284 switch (Question->Operand) {
3285 case EFI_IFR_NUMERIC_OP:
3286 //
3287 // Take minimum value as numeric default value
3288 //
3289 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
3290 HiiValue->Value.u64 = Question->Minimum;
3291 Status = EFI_SUCCESS;
3292 }
3293 break;
3294
3295 case EFI_IFR_ONE_OF_OP:
3296 //
3297 // Take first oneof option as oneof's default value
3298 //
3299 if (ValueToOption (Question, HiiValue) == NULL) {
3300 Link = GetFirstNode (&Question->OptionListHead);
3301 while (!IsNull (&Question->OptionListHead, Link)) {
3302 Option = QUESTION_OPTION_FROM_LINK (Link);
3303 Link = GetNextNode (&Question->OptionListHead, Link);
3304
3305 if ((Option->SuppressExpression != NULL) &&
3306 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3307 continue;
3308 }
3309
3310 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3311 Status = EFI_SUCCESS;
3312 break;
3313 }
3314 }
3315 break;
3316
3317 case EFI_IFR_ORDERED_LIST_OP:
3318 //
3319 // Take option sequence in IFR as ordered list's default value
3320 //
3321 Index = 0;
3322 Link = GetFirstNode (&Question->OptionListHead);
3323 while (!IsNull (&Question->OptionListHead, Link)) {
3324 Status = EFI_SUCCESS;
3325 Option = QUESTION_OPTION_FROM_LINK (Link);
3326 Link = GetNextNode (&Question->OptionListHead, Link);
3327
3328 if ((Option->SuppressExpression != NULL) &&
3329 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3330 continue;
3331 }
3332
3333 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
3334
3335 Index++;
3336 if (Index >= Question->MaxContainers) {
3337 break;
3338 }
3339 }
3340 break;
3341
3342 default:
3343 break;
3344 }
3345
3346 return Status;
3347 }
3348
3349
3350 /**
3351 Reset Questions to their initial value or default value in a Form, Formset or System.
3352
3353 GetDefaultValueScope parameter decides which questions will reset
3354 to its default value.
3355
3356 @param FormSet FormSet data structure.
3357 @param Form Form data structure.
3358 @param DefaultId The Class of the default.
3359 @param SettingScope Setting Scope for Default action.
3360 @param GetDefaultValueScope Get default value scope.
3361 @param Storage Get default value only for this storage.
3362 @param RetrieveValueFirst Whether call the retrieve call back to
3363 get the initial value before get default
3364 value.
3365
3366 @retval EFI_SUCCESS The function completed successfully.
3367 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3368
3369 **/
3370 EFI_STATUS
3371 ExtractDefault (
3372 IN FORM_BROWSER_FORMSET *FormSet,
3373 IN FORM_BROWSER_FORM *Form,
3374 IN UINT16 DefaultId,
3375 IN BROWSER_SETTING_SCOPE SettingScope,
3376 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
3377 IN BROWSER_STORAGE *Storage OPTIONAL,
3378 IN BOOLEAN RetrieveValueFirst
3379 )
3380 {
3381 EFI_STATUS Status;
3382 LIST_ENTRY *FormLink;
3383 LIST_ENTRY *Link;
3384 FORM_BROWSER_STATEMENT *Question;
3385 FORM_BROWSER_FORMSET *LocalFormSet;
3386 FORM_BROWSER_FORMSET *OldFormSet;
3387
3388 Status = EFI_SUCCESS;
3389
3390 //
3391 // Check the supported setting level.
3392 //
3393 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
3394 return EFI_UNSUPPORTED;
3395 }
3396
3397 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
3398 return EFI_UNSUPPORTED;
3399 }
3400
3401 if (SettingScope == FormLevel) {
3402 //
3403 // Extract Form default
3404 //
3405 Link = GetFirstNode (&Form->StatementListHead);
3406 while (!IsNull (&Form->StatementListHead, Link)) {
3407 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3408 Link = GetNextNode (&Form->StatementListHead, Link);
3409
3410 //
3411 // If get default value only for this storage, check the storage first.
3412 //
3413 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
3414 continue;
3415 }
3416
3417 //
3418 // If get default value only for no storage question, just skip the question which has storage.
3419 //
3420 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
3421 continue;
3422 }
3423
3424 //
3425 // If Question is disabled, don't reset it to default
3426 //
3427 if (Question->Expression != NULL) {
3428 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
3429 continue;
3430 }
3431 }
3432
3433 if (RetrieveValueFirst) {
3434 //
3435 // Call the Retrieve call back to get the initial question value.
3436 //
3437 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
3438 }
3439
3440 //
3441 // If not request to get the initial value or get initial value fail, then get default value.
3442 //
3443 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
3444 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
3445 if (EFI_ERROR (Status)) {
3446 continue;
3447 }
3448 }
3449
3450 //
3451 // Synchronize Buffer storage's Edit buffer
3452 //
3453 if ((Question->Storage != NULL) &&
3454 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
3455 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3456 }
3457 }
3458 } else if (SettingScope == FormSetLevel) {
3459 FormLink = GetFirstNode (&FormSet->FormListHead);
3460 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3461 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3462 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3463 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3464 }
3465 } else if (SettingScope == SystemLevel) {
3466 //
3467 // Preload all Hii formset.
3468 //
3469 LoadAllHiiFormset();
3470
3471 OldFormSet = mSystemLevelFormSet;
3472
3473 //
3474 // Set Default Value for each FormSet in the maintain list.
3475 //
3476 Link = GetFirstNode (&gBrowserFormSetList);
3477 while (!IsNull (&gBrowserFormSetList, Link)) {
3478 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3479 Link = GetNextNode (&gBrowserFormSetList, Link);
3480 if (!ValidateFormSet(LocalFormSet)) {
3481 continue;
3482 }
3483
3484 mSystemLevelFormSet = LocalFormSet;
3485
3486 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3487 }
3488
3489 mSystemLevelFormSet = OldFormSet;
3490 }
3491
3492 return EFI_SUCCESS;
3493 }
3494
3495
3496 /**
3497 Validate whether this question's value has changed.
3498
3499 @param FormSet FormSet data structure.
3500 @param Form Form data structure.
3501 @param Question Question to be initialized.
3502 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
3503
3504 @retval TRUE Question's value has changed.
3505 @retval FALSE Question's value has not changed
3506
3507 **/
3508 BOOLEAN
3509 IsQuestionValueChanged (
3510 IN FORM_BROWSER_FORMSET *FormSet,
3511 IN FORM_BROWSER_FORM *Form,
3512 IN OUT FORM_BROWSER_STATEMENT *Question,
3513 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
3514 )
3515 {
3516 EFI_HII_VALUE BackUpValue;
3517 CHAR8 *BackUpBuffer;
3518 EFI_STATUS Status;
3519 BOOLEAN ValueChanged;
3520 UINTN BufferWidth;
3521
3522 //
3523 // For quetion without storage, always mark it as data not changed.
3524 //
3525 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
3526 return FALSE;
3527 }
3528
3529 BackUpBuffer = NULL;
3530 ValueChanged = FALSE;
3531
3532 switch (Question->Operand) {
3533 case EFI_IFR_ORDERED_LIST_OP:
3534 BufferWidth = Question->StorageWidth;
3535 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
3536 ASSERT (BackUpBuffer != NULL);
3537 break;
3538
3539 case EFI_IFR_STRING_OP:
3540 case EFI_IFR_PASSWORD_OP:
3541 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
3542 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
3543 ASSERT (BackUpBuffer != NULL);
3544 break;
3545
3546 default:
3547 BufferWidth = 0;
3548 break;
3549 }
3550 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
3551
3552 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
3553 ASSERT_EFI_ERROR(Status);
3554
3555 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
3556 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
3557 ValueChanged = TRUE;
3558 }
3559
3560 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
3561 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
3562
3563 if (BackUpBuffer != NULL) {
3564 FreePool (BackUpBuffer);
3565 }
3566
3567 Question->ValueChanged = ValueChanged;
3568
3569 return ValueChanged;
3570 }
3571
3572 /**
3573 Initialize Question's Edit copy from Storage.
3574
3575 @param Selection Selection contains the information about
3576 the Selection, form and formset to be displayed.
3577 Selection action may be updated in retrieve callback.
3578 If Selection is NULL, only initialize Question value.
3579 @param FormSet FormSet data structure.
3580 @param Form Form data structure.
3581
3582 @retval EFI_SUCCESS The function completed successfully.
3583
3584 **/
3585 EFI_STATUS
3586 LoadFormConfig (
3587 IN OUT UI_MENU_SELECTION *Selection,
3588 IN FORM_BROWSER_FORMSET *FormSet,
3589 IN FORM_BROWSER_FORM *Form
3590 )
3591 {
3592 EFI_STATUS Status;
3593 LIST_ENTRY *Link;
3594 FORM_BROWSER_STATEMENT *Question;
3595
3596 Link = GetFirstNode (&Form->StatementListHead);
3597 while (!IsNull (&Form->StatementListHead, Link)) {
3598 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3599
3600 //
3601 // Initialize local copy of Value for each Question
3602 //
3603 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
3604 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
3605 } else {
3606 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3607 }
3608 if (EFI_ERROR (Status)) {
3609 return Status;
3610 }
3611
3612 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
3613 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
3614 }
3615
3616 Link = GetNextNode (&Form->StatementListHead, Link);
3617 }
3618
3619 return EFI_SUCCESS;
3620 }
3621
3622 /**
3623 Initialize Question's Edit copy from Storage for the whole Formset.
3624
3625 @param Selection Selection contains the information about
3626 the Selection, form and formset to be displayed.
3627 Selection action may be updated in retrieve callback.
3628 If Selection is NULL, only initialize Question value.
3629 @param FormSet FormSet data structure.
3630
3631 @retval EFI_SUCCESS The function completed successfully.
3632
3633 **/
3634 EFI_STATUS
3635 LoadFormSetConfig (
3636 IN OUT UI_MENU_SELECTION *Selection,
3637 IN FORM_BROWSER_FORMSET *FormSet
3638 )
3639 {
3640 EFI_STATUS Status;
3641 LIST_ENTRY *Link;
3642 FORM_BROWSER_FORM *Form;
3643
3644 Link = GetFirstNode (&FormSet->FormListHead);
3645 while (!IsNull (&FormSet->FormListHead, Link)) {
3646 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3647
3648 //
3649 // Initialize local copy of Value for each Form
3650 //
3651 Status = LoadFormConfig (Selection, FormSet, Form);
3652 if (EFI_ERROR (Status)) {
3653 return Status;
3654 }
3655
3656 Link = GetNextNode (&FormSet->FormListHead, Link);
3657 }
3658
3659 //
3660 // Finished question initialization.
3661 //
3662 FormSet->QuestionInited = TRUE;
3663
3664 return EFI_SUCCESS;
3665 }
3666
3667 /**
3668 Remove the Request element from the Config Request.
3669
3670 @param Storage Pointer to the browser storage.
3671 @param RequestElement The pointer to the Request element.
3672
3673 **/
3674 VOID
3675 RemoveElement (
3676 IN OUT BROWSER_STORAGE *Storage,
3677 IN CHAR16 *RequestElement
3678 )
3679 {
3680 CHAR16 *NewStr;
3681 CHAR16 *DestStr;
3682
3683 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
3684
3685 NewStr = StrStr (Storage->ConfigRequest, RequestElement);
3686
3687 if (NewStr == NULL) {
3688 return;
3689 }
3690
3691 //
3692 // Remove this element from this ConfigRequest.
3693 //
3694 DestStr = NewStr;
3695 NewStr += StrLen (RequestElement);
3696 CopyMem (DestStr, NewStr, StrSize (NewStr));
3697
3698 Storage->SpareStrLen += StrLen (RequestElement);
3699 }
3700
3701 /**
3702 Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
3703
3704 @param Storage Pointer to the browser storage.
3705 @param ConfigRequest The pointer to the Request element.
3706
3707 **/
3708 VOID
3709 RemoveConfigRequest (
3710 BROWSER_STORAGE *Storage,
3711 CHAR16 *ConfigRequest
3712 )
3713 {
3714 CHAR16 *RequestElement;
3715 CHAR16 *NextRequestElement;
3716 CHAR16 *SearchKey;
3717
3718 //
3719 // No request element in it, just return.
3720 //
3721 if (ConfigRequest == NULL) {
3722 return;
3723 }
3724
3725 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3726 //
3727 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
3728 //
3729 SearchKey = L"&";
3730 } else {
3731 //
3732 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
3733 //
3734 SearchKey = L"&OFFSET";
3735 }
3736
3737 //
3738 // Find SearchKey storage
3739 //
3740 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3741 RequestElement = StrStr (ConfigRequest, L"PATH");
3742 ASSERT (RequestElement != NULL);
3743 RequestElement = StrStr (RequestElement, SearchKey);
3744 } else {
3745 RequestElement = StrStr (ConfigRequest, SearchKey);
3746 }
3747
3748 while (RequestElement != NULL) {
3749 //
3750 // +1 to avoid find header itself.
3751 //
3752 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
3753
3754 //
3755 // The last Request element in configRequest string.
3756 //
3757 if (NextRequestElement != NULL) {
3758 //
3759 // Replace "&" with '\0'.
3760 //
3761 *NextRequestElement = L'\0';
3762 }
3763
3764 RemoveElement (Storage, RequestElement);
3765
3766 if (NextRequestElement != NULL) {
3767 //
3768 // Restore '&' with '\0' for later used.
3769 //
3770 *NextRequestElement = L'&';
3771 }
3772
3773 RequestElement = NextRequestElement;
3774 }
3775
3776 //
3777 // If no request element remain, just remove the ConfigRequest string.
3778 //
3779 if (StrCmp (Storage->ConfigRequest, Storage->ConfigHdr) == 0) {
3780 FreePool (Storage->ConfigRequest);
3781 Storage->ConfigRequest = NULL;
3782 Storage->SpareStrLen = 0;
3783 }
3784 }
3785
3786 /**
3787 Base on the current formset info, clean the ConfigRequest string in browser storage.
3788
3789 @param FormSet Pointer of the FormSet
3790
3791 **/
3792 VOID
3793 CleanBrowserStorage (
3794 IN OUT FORM_BROWSER_FORMSET *FormSet
3795 )
3796 {
3797 LIST_ENTRY *Link;
3798 FORMSET_STORAGE *Storage;
3799
3800 Link = GetFirstNode (&FormSet->StorageListHead);
3801 while (!IsNull (&FormSet->StorageListHead, Link)) {
3802 Storage = FORMSET_STORAGE_FROM_LINK (Link);
3803 Link = GetNextNode (&FormSet->StorageListHead, Link);
3804
3805 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
3806 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
3807 continue;
3808 }
3809
3810 RemoveConfigRequest (Storage->BrowserStorage, Storage->ConfigRequest);
3811 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
3812 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3813 if (Storage->BrowserStorage->ConfigRequest != NULL) {
3814 FreePool (Storage->BrowserStorage->ConfigRequest);
3815 Storage->BrowserStorage->ConfigRequest = NULL;
3816 }
3817 Storage->BrowserStorage->Initialized = FALSE;
3818 }
3819 }
3820 }
3821
3822 /**
3823 Check whether current element in the ConfigReqeust string.
3824
3825 @param BrowserStorage Storage which includes ConfigReqeust.
3826 @param RequestElement New element need to check.
3827
3828 @retval TRUE The Element is in the ConfigReqeust string.
3829 @retval FALSE The Element not in the configReqeust String.
3830
3831 **/
3832 BOOLEAN
3833 ElementValidation (
3834 BROWSER_STORAGE *BrowserStorage,
3835 CHAR16 *RequestElement
3836 )
3837 {
3838 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
3839 }
3840
3841 /**
3842 Append the Request element to the Config Request.
3843
3844 @param ConfigRequest Current ConfigRequest info.
3845 @param SpareStrLen Current remain free buffer for config reqeust.
3846 @param RequestElement New Request element.
3847
3848 **/
3849 VOID
3850 AppendConfigRequest (
3851 IN OUT CHAR16 **ConfigRequest,
3852 IN OUT UINTN *SpareStrLen,
3853 IN CHAR16 *RequestElement
3854 )
3855 {
3856 CHAR16 *NewStr;
3857 UINTN StringSize;
3858 UINTN StrLength;
3859
3860 StrLength = StrLen (RequestElement);
3861
3862 //
3863 // Append <RequestElement> to <ConfigRequest>
3864 //
3865 if (StrLength > *SpareStrLen) {
3866 //
3867 // Old String buffer is not sufficient for RequestElement, allocate a new one
3868 //
3869 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
3870 NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));
3871 ASSERT (NewStr != NULL);
3872
3873 if (*ConfigRequest != NULL) {
3874 CopyMem (NewStr, *ConfigRequest, StringSize);
3875 FreePool (*ConfigRequest);
3876 }
3877 *ConfigRequest = NewStr;
3878 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
3879 }
3880
3881 StrCat (*ConfigRequest, RequestElement);
3882 *SpareStrLen -= StrLength;
3883 }
3884
3885 /**
3886 Adjust the config request info, remove the request elements which already in AllConfigRequest string.
3887
3888 @param Storage Form set Storage.
3889 @param Request The input request string.
3890 @param RespString Whether the input is ConfigRequest or ConfigResp format.
3891
3892 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
3893 @retval FALSE All elements covered by current used elements.
3894
3895 **/
3896 BOOLEAN
3897 ConfigRequestAdjust (
3898 IN BROWSER_STORAGE *Storage,
3899 IN CHAR16 *Request,
3900 IN BOOLEAN RespString
3901 )
3902 {
3903 CHAR16 *RequestElement;
3904 CHAR16 *NextRequestElement;
3905 CHAR16 *NextElementBakup;
3906 UINTN SpareBufLen;
3907 CHAR16 *SearchKey;
3908 CHAR16 *ValueKey;
3909 BOOLEAN RetVal;
3910 CHAR16 *ConfigRequest;
3911
3912 SpareBufLen = 0;
3913 RetVal = FALSE;
3914 NextElementBakup = NULL;
3915 ValueKey = NULL;
3916
3917 if (Request != NULL) {
3918 ConfigRequest = Request;
3919 } else {
3920 ConfigRequest = Storage->ConfigRequest;
3921 }
3922
3923 if (Storage->ConfigRequest == NULL) {
3924 Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
3925 return TRUE;
3926 }
3927
3928 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3929 //
3930 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
3931 //
3932 SearchKey = L"&";
3933 } else {
3934 //
3935 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
3936 //
3937 SearchKey = L"&OFFSET";
3938 ValueKey = L"&VALUE";
3939 }
3940
3941 //
3942 // Find SearchKey storage
3943 //
3944 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3945 RequestElement = StrStr (ConfigRequest, L"PATH");
3946 ASSERT (RequestElement != NULL);
3947 RequestElement = StrStr (RequestElement, SearchKey);
3948 } else {
3949 RequestElement = StrStr (ConfigRequest, SearchKey);
3950 }
3951
3952 while (RequestElement != NULL) {
3953
3954 //
3955 // +1 to avoid find header itself.
3956 //
3957 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
3958
3959 //
3960 // The last Request element in configRequest string.
3961 //
3962 if (NextRequestElement != NULL) {
3963 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
3964 NextElementBakup = NextRequestElement;
3965 NextRequestElement = StrStr (RequestElement, ValueKey);
3966 ASSERT (NextRequestElement != NULL);
3967 }
3968 //
3969 // Replace "&" with '\0'.
3970 //
3971 *NextRequestElement = L'\0';
3972 } else {
3973 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
3974 NextElementBakup = NextRequestElement;
3975 NextRequestElement = StrStr (RequestElement, ValueKey);
3976 ASSERT (NextRequestElement != NULL);
3977 //
3978 // Replace "&" with '\0'.
3979 //
3980 *NextRequestElement = L'\0';
3981 }
3982 }
3983
3984 if (!ElementValidation (Storage, RequestElement)) {
3985 //
3986 // Add this element to the Storage->BrowserStorage->AllRequestElement.
3987 //
3988 AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
3989 RetVal = TRUE;
3990 }
3991
3992 if (NextRequestElement != NULL) {
3993 //
3994 // Restore '&' with '\0' for later used.
3995 //
3996 *NextRequestElement = L'&';
3997 }
3998
3999 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4000 RequestElement = NextElementBakup;
4001 } else {
4002 RequestElement = NextRequestElement;
4003 }
4004 }
4005
4006 return RetVal;
4007 }
4008
4009 /**
4010
4011 Base on ConfigRequest info to get default value for current formset.
4012
4013 ConfigRequest info include the info about which questions in current formset need to
4014 get default value. This function only get these questions default value.
4015
4016 @param FormSet FormSet data structure.
4017 @param Storage Storage need to update value.
4018 @param ConfigRequest The config request string.
4019
4020 **/
4021 VOID
4022 GetDefaultForFormset (
4023 IN FORM_BROWSER_FORMSET *FormSet,
4024 IN BROWSER_STORAGE *Storage,
4025 IN CHAR16 *ConfigRequest
4026 )
4027 {
4028 UINT8 *BackUpBuf;
4029 UINTN BufferSize;
4030 LIST_ENTRY BackUpList;
4031 NAME_VALUE_NODE *Node;
4032 LIST_ENTRY *Link;
4033 LIST_ENTRY *NodeLink;
4034 NAME_VALUE_NODE *TmpNode;
4035 EFI_STATUS Status;
4036 EFI_STRING Progress;
4037 EFI_STRING Result;
4038
4039 BackUpBuf = NULL;
4040 InitializeListHead(&BackUpList);
4041
4042 //
4043 // Back update the edit buffer.
4044 //
4045 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
4046 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4047 BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);
4048 ASSERT (BackUpBuf != NULL);
4049 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4050 Link = GetFirstNode (&Storage->NameValueListHead);
4051 while (!IsNull (&Storage->NameValueListHead, Link)) {
4052 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4053 Link = GetNextNode (&Storage->NameValueListHead, Link);
4054
4055 //
4056 // Only back Node belong to this formset.
4057 //
4058 if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {
4059 continue;
4060 }
4061
4062 TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);
4063 TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);
4064 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
4065
4066 InsertTailList(&BackUpList, &TmpNode->Link);
4067 }
4068 }
4069
4070 //
4071 // Get default value.
4072 //
4073 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);
4074
4075 //
4076 // Update the question value based on the input ConfigRequest.
4077 //
4078 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
4079 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
4080 ASSERT (BackUpBuf != NULL);
4081 BufferSize = Storage->Size;
4082 Status = mHiiConfigRouting->BlockToConfig(
4083 mHiiConfigRouting,
4084 ConfigRequest,
4085 Storage->EditBuffer,
4086 BufferSize,
4087 &Result,
4088 &Progress
4089 );
4090 ASSERT_EFI_ERROR (Status);
4091
4092 Status = mHiiConfigRouting->ConfigToBlock (
4093 mHiiConfigRouting,
4094 Result,
4095 BackUpBuf,
4096 &BufferSize,
4097 &Progress
4098 );
4099 ASSERT_EFI_ERROR (Status);
4100
4101 if (Result != NULL) {
4102 FreePool (Result);
4103 }
4104
4105 CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);
4106 FreePool (BackUpBuf);
4107 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4108 //
4109 // Update question value, only element in ConfigReqeust will be update.
4110 //
4111 Link = GetFirstNode (&BackUpList);
4112 while (!IsNull (&BackUpList, Link)) {
4113 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4114 Link = GetNextNode (&BackUpList, Link);
4115
4116 if (StrStr (ConfigRequest, Node->Name) != NULL) {
4117 continue;
4118 }
4119
4120 NodeLink = GetFirstNode (&Storage->NameValueListHead);
4121 while (!IsNull (&Storage->NameValueListHead, NodeLink)) {
4122 TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink);
4123 NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);
4124
4125 if (StrCmp (Node->Name, TmpNode->Name) != 0) {
4126 continue;
4127 }
4128
4129 FreePool (TmpNode->EditValue);
4130 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
4131
4132 RemoveEntryList (&Node->Link);
4133 FreePool (Node->EditValue);
4134 FreePool (Node->Name);
4135 FreePool (Node);
4136 }
4137 }
4138
4139 //
4140 // Restore the Name/Value node.
4141 //
4142 Link = GetFirstNode (&BackUpList);
4143 while (!IsNull (&BackUpList, Link)) {
4144 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4145 Link = GetNextNode (&BackUpList, Link);
4146
4147 //
4148 // Free this node.
4149 //
4150 RemoveEntryList (&Node->Link);
4151 FreePool (Node->EditValue);
4152 FreePool (Node->Name);
4153 FreePool (Node);
4154 }
4155 }
4156 }
4157
4158 /**
4159 Fill storage's edit copy with settings requested from Configuration Driver.
4160
4161 @param FormSet FormSet data structure.
4162 @param Storage Buffer Storage.
4163
4164 **/
4165 VOID
4166 LoadStorage (
4167 IN FORM_BROWSER_FORMSET *FormSet,
4168 IN FORMSET_STORAGE *Storage
4169 )
4170 {
4171 EFI_STATUS Status;
4172 EFI_STRING Progress;
4173 EFI_STRING Result;
4174 CHAR16 *StrPtr;
4175 EFI_STRING ConfigRequest;
4176 UINTN StrLen;
4177
4178 ConfigRequest = NULL;
4179
4180 switch (Storage->BrowserStorage->Type) {
4181 case EFI_HII_VARSTORE_EFI_VARIABLE:
4182 return;
4183
4184 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
4185 if (Storage->BrowserStorage->ConfigRequest != NULL) {
4186 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
4187 return;
4188 }
4189 break;
4190
4191 case EFI_HII_VARSTORE_BUFFER:
4192 case EFI_HII_VARSTORE_NAME_VALUE:
4193 //
4194 // Skip if there is no RequestElement.
4195 //
4196 if (Storage->ElementCount == 0) {
4197 return;
4198 }
4199
4200 //
4201 // Just update the ConfigRequest, if storage already initialized.
4202 //
4203 if (Storage->BrowserStorage->Initialized) {
4204 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
4205 return;
4206 }
4207
4208 Storage->BrowserStorage->Initialized = TRUE;
4209 break;
4210
4211 default:
4212 return;
4213 }
4214
4215 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
4216 //
4217 // Create the config request string to get all fields for this storage.
4218 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
4219 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
4220 //
4221 StrLen = StrSize (Storage->BrowserStorage->ConfigHdr) + 20 * sizeof (CHAR16);
4222 ConfigRequest = AllocateZeroPool (StrLen);
4223 ASSERT (ConfigRequest != NULL);
4224 UnicodeSPrint (
4225 ConfigRequest,
4226 StrLen,
4227 L"%s&OFFSET=0&WIDTH=%04x",
4228 Storage->BrowserStorage->ConfigHdr,
4229 Storage->BrowserStorage->Size);
4230 } else {
4231 ConfigRequest = Storage->ConfigRequest;
4232 }
4233
4234 //
4235 // Request current settings from Configuration Driver
4236 //
4237 Status = mHiiConfigRouting->ExtractConfig (
4238 mHiiConfigRouting,
4239 ConfigRequest,
4240 &Progress,
4241 &Result
4242 );
4243
4244 //
4245 // If get value fail, extract default from IFR binary
4246 //
4247 if (EFI_ERROR (Status)) {
4248 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);
4249 } else {
4250 //
4251 // Convert Result from <ConfigAltResp> to <ConfigResp>
4252 //
4253 StrPtr = StrStr (Result, L"&GUID=");
4254 if (StrPtr != NULL) {
4255 *StrPtr = L'\0';
4256 }
4257
4258 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
4259 FreePool (Result);
4260 }
4261
4262 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
4263
4264 //
4265 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
4266 //
4267 SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE);
4268
4269 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
4270 if (ConfigRequest != NULL) {
4271 FreePool (ConfigRequest);
4272 }
4273 }
4274 }
4275
4276 /**
4277 Get Value changed status from old question.
4278
4279 @param NewFormSet FormSet data structure.
4280 @param OldQuestion Old question which has value changed.
4281
4282 **/
4283 VOID
4284 SyncStatusForQuestion (
4285 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
4286 IN FORM_BROWSER_STATEMENT *OldQuestion
4287 )
4288 {
4289 LIST_ENTRY *Link;
4290 LIST_ENTRY *QuestionLink;
4291 FORM_BROWSER_FORM *Form;
4292 FORM_BROWSER_STATEMENT *Question;
4293
4294 //
4295 // For each form in one formset.
4296 //
4297 Link = GetFirstNode (&NewFormSet->FormListHead);
4298 while (!IsNull (&NewFormSet->FormListHead, Link)) {
4299 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4300 Link = GetNextNode (&NewFormSet->FormListHead, Link);
4301
4302 //
4303 // for each question in one form.
4304 //
4305 QuestionLink = GetFirstNode (&Form->StatementListHead);
4306 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
4307 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
4308 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
4309
4310 if (Question->QuestionId == OldQuestion->QuestionId) {
4311 Question->ValueChanged = TRUE;
4312 return;
4313 }
4314 }
4315 }
4316 }
4317
4318 /**
4319 Get Value changed status from old formset.
4320
4321 @param NewFormSet FormSet data structure.
4322 @param OldFormSet FormSet data structure.
4323
4324 **/
4325 VOID
4326 SyncStatusForFormSet (
4327 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
4328 IN FORM_BROWSER_FORMSET *OldFormSet
4329 )
4330 {
4331 LIST_ENTRY *Link;
4332 LIST_ENTRY *QuestionLink;
4333 FORM_BROWSER_FORM *Form;
4334 FORM_BROWSER_STATEMENT *Question;
4335
4336 //
4337 // For each form in one formset.
4338 //
4339 Link = GetFirstNode (&OldFormSet->FormListHead);
4340 while (!IsNull (&OldFormSet->FormListHead, Link)) {
4341 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4342 Link = GetNextNode (&OldFormSet->FormListHead, Link);
4343
4344 //
4345 // for each question in one form.
4346 //
4347 QuestionLink = GetFirstNode (&Form->StatementListHead);
4348 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
4349 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
4350 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
4351
4352 if (!Question->ValueChanged) {
4353 continue;
4354 }
4355
4356 //
4357 // Find the same question in new formset and update the value changed flag.
4358 //
4359 SyncStatusForQuestion (NewFormSet, Question);
4360 }
4361 }
4362 }
4363
4364 /**
4365 Get current setting of Questions.
4366
4367 @param FormSet FormSet data structure.
4368
4369 **/
4370 VOID
4371 InitializeCurrentSetting (
4372 IN OUT FORM_BROWSER_FORMSET *FormSet
4373 )
4374 {
4375 LIST_ENTRY *Link;
4376 FORMSET_STORAGE *Storage;
4377 FORM_BROWSER_FORMSET *OldFormSet;
4378
4379 //
4380 // Try to find pre FormSet in the maintain backup list.
4381 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
4382 //
4383 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
4384 if (OldFormSet != NULL) {
4385 SyncStatusForFormSet (FormSet, OldFormSet);
4386 RemoveEntryList (&OldFormSet->Link);
4387 DestroyFormSet (OldFormSet);
4388 }
4389 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
4390
4391 //
4392 // Extract default from IFR binary for no storage questions.
4393 //
4394 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);
4395
4396 //
4397 // Request current settings from Configuration Driver
4398 //
4399 Link = GetFirstNode (&FormSet->StorageListHead);
4400 while (!IsNull (&FormSet->StorageListHead, Link)) {
4401 Storage = FORMSET_STORAGE_FROM_LINK (Link);
4402
4403 LoadStorage (FormSet, Storage);
4404
4405 Link = GetNextNode (&FormSet->StorageListHead, Link);
4406 }
4407 }
4408
4409
4410 /**
4411 Fetch the Ifr binary data of a FormSet.
4412
4413 @param Handle PackageList Handle
4414 @param FormSetGuid On input, GUID or class GUID of a formset. If not
4415 specified (NULL or zero GUID), take the first
4416 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
4417 found in package list.
4418 On output, GUID of the formset found(if not NULL).
4419 @param BinaryLength The length of the FormSet IFR binary.
4420 @param BinaryData The buffer designed to receive the FormSet.
4421
4422 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
4423 BufferLength was updated.
4424 @retval EFI_INVALID_PARAMETER The handle is unknown.
4425 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
4426 be found with the requested FormId.
4427
4428 **/
4429 EFI_STATUS
4430 GetIfrBinaryData (
4431 IN EFI_HII_HANDLE Handle,
4432 IN OUT EFI_GUID *FormSetGuid,
4433 OUT UINTN *BinaryLength,
4434 OUT UINT8 **BinaryData
4435 )
4436 {
4437 EFI_STATUS Status;
4438 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
4439 UINTN BufferSize;
4440 UINT8 *Package;
4441 UINT8 *OpCodeData;
4442 UINT32 Offset;
4443 UINT32 Offset2;
4444 UINT32 PackageListLength;
4445 EFI_HII_PACKAGE_HEADER PackageHeader;
4446 UINT8 Index;
4447 UINT8 NumberOfClassGuid;
4448 BOOLEAN ClassGuidMatch;
4449 EFI_GUID *ClassGuid;
4450 EFI_GUID *ComparingGuid;
4451
4452 OpCodeData = NULL;
4453 Package = NULL;
4454 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
4455
4456 //
4457 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
4458 //
4459 if (FormSetGuid == NULL) {
4460 ComparingGuid = &gZeroGuid;
4461 } else {
4462 ComparingGuid = FormSetGuid;
4463 }
4464
4465 //
4466 // Get HII PackageList
4467 //
4468 BufferSize = 0;
4469 HiiPackageList = NULL;
4470 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
4471 if (Status == EFI_BUFFER_TOO_SMALL) {
4472 HiiPackageList = AllocatePool (BufferSize);
4473 ASSERT (HiiPackageList != NULL);
4474
4475 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
4476 }
4477 if (EFI_ERROR (Status)) {
4478 return Status;
4479 }
4480 ASSERT (HiiPackageList != NULL);
4481
4482 //
4483 // Get Form package from this HII package List
4484 //
4485 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
4486 Offset2 = 0;
4487 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
4488
4489 ClassGuidMatch = FALSE;
4490 while (Offset < PackageListLength) {
4491 Package = ((UINT8 *) HiiPackageList) + Offset;
4492 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4493
4494 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
4495 //
4496 // Search FormSet in this Form Package
4497 //
4498 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
4499 while (Offset2 < PackageHeader.Length) {
4500 OpCodeData = Package + Offset2;
4501
4502 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
4503 //
4504 // Try to compare against formset GUID
4505 //
4506 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
4507 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
4508 break;
4509 }
4510
4511 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
4512 //
4513 // Try to compare against formset class GUID
4514 //
4515 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
4516 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
4517 for (Index = 0; Index < NumberOfClassGuid; Index++) {
4518 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
4519 ClassGuidMatch = TRUE;
4520 break;
4521 }
4522 }
4523 if (ClassGuidMatch) {
4524 break;
4525 }
4526 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
4527 ClassGuidMatch = TRUE;
4528 break;
4529 }
4530 }
4531
4532 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
4533 }
4534
4535 if (Offset2 < PackageHeader.Length) {
4536 //
4537 // Target formset found
4538 //
4539 break;
4540 }
4541 }
4542
4543 Offset += PackageHeader.Length;
4544 }
4545
4546 if (Offset >= PackageListLength) {
4547 //
4548 // Form package not found in this Package List
4549 //
4550 FreePool (HiiPackageList);
4551 return EFI_NOT_FOUND;
4552 }
4553
4554 if (FormSetGuid != NULL) {
4555 //
4556 // Return the FormSet GUID
4557 //
4558 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
4559 }
4560
4561 //
4562 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
4563 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
4564 // of the Form Package.
4565 //
4566 *BinaryLength = PackageHeader.Length - Offset2;
4567 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
4568
4569 FreePool (HiiPackageList);
4570
4571 if (*BinaryData == NULL) {
4572 return EFI_OUT_OF_RESOURCES;
4573 }
4574
4575 return EFI_SUCCESS;
4576 }
4577
4578
4579 /**
4580 Initialize the internal data structure of a FormSet.
4581
4582 @param Handle PackageList Handle
4583 @param FormSetGuid On input, GUID or class GUID of a formset. If not
4584 specified (NULL or zero GUID), take the first
4585 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
4586 found in package list.
4587 On output, GUID of the formset found(if not NULL).
4588 @param FormSet FormSet data structure.
4589
4590 @retval EFI_SUCCESS The function completed successfully.
4591 @retval EFI_NOT_FOUND The specified FormSet could not be found.
4592
4593 **/
4594 EFI_STATUS
4595 InitializeFormSet (
4596 IN EFI_HII_HANDLE Handle,
4597 IN OUT EFI_GUID *FormSetGuid,
4598 OUT FORM_BROWSER_FORMSET *FormSet
4599 )
4600 {
4601 EFI_STATUS Status;
4602 EFI_HANDLE DriverHandle;
4603
4604 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
4605 if (EFI_ERROR (Status)) {
4606 return Status;
4607 }
4608
4609 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
4610 FormSet->HiiHandle = Handle;
4611 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
4612 FormSet->QuestionInited = FALSE;
4613
4614 //
4615 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
4616 //
4617 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
4618 if (EFI_ERROR (Status)) {
4619 return Status;
4620 }
4621 FormSet->DriverHandle = DriverHandle;
4622 Status = gBS->HandleProtocol (
4623 DriverHandle,
4624 &gEfiHiiConfigAccessProtocolGuid,
4625 (VOID **) &FormSet->ConfigAccess
4626 );
4627 if (EFI_ERROR (Status)) {
4628 //
4629 // Configuration Driver don't attach ConfigAccess protocol to its HII package
4630 // list, then there will be no configuration action required
4631 //
4632 FormSet->ConfigAccess = NULL;
4633 }
4634
4635 //
4636 // Parse the IFR binary OpCodes
4637 //
4638 Status = ParseOpCodes (FormSet);
4639
4640 return Status;
4641 }
4642
4643
4644 /**
4645 Save globals used by previous call to SendForm(). SendForm() may be called from
4646 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
4647 So, save globals of previous call to SendForm() and restore them upon exit.
4648
4649 **/
4650 VOID
4651 SaveBrowserContext (
4652 VOID
4653 )
4654 {
4655 BROWSER_CONTEXT *Context;
4656 FORM_ENTRY_INFO *MenuList;
4657
4658 gBrowserContextCount++;
4659 if (gBrowserContextCount == 1) {
4660 //
4661 // This is not reentry of SendForm(), no context to save
4662 //
4663 return;
4664 }
4665
4666 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
4667 ASSERT (Context != NULL);
4668
4669 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
4670
4671 //
4672 // Save FormBrowser context
4673 //
4674 Context->Selection = gCurrentSelection;
4675 Context->ResetRequired = gResetRequired;
4676 Context->ExitRequired = gExitRequired;
4677 Context->HiiHandle = mCurrentHiiHandle;
4678 Context->FormId = mCurrentFormId;
4679 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
4680
4681 //
4682 // Save the menu history data.
4683 //
4684 InitializeListHead(&Context->FormHistoryList);
4685 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
4686 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
4687 RemoveEntryList (&MenuList->Link);
4688
4689 InsertTailList(&Context->FormHistoryList, &MenuList->Link);
4690 }
4691
4692 //
4693 // Insert to FormBrowser context list
4694 //
4695 InsertHeadList (&gBrowserContextList, &Context->Link);
4696 }
4697
4698
4699 /**
4700 Restore globals used by previous call to SendForm().
4701
4702 **/
4703 VOID
4704 RestoreBrowserContext (
4705 VOID
4706 )
4707 {
4708 LIST_ENTRY *Link;
4709 BROWSER_CONTEXT *Context;
4710 FORM_ENTRY_INFO *MenuList;
4711
4712 ASSERT (gBrowserContextCount != 0);
4713 gBrowserContextCount--;
4714 if (gBrowserContextCount == 0) {
4715 //
4716 // This is not reentry of SendForm(), no context to restore
4717 //
4718 return;
4719 }
4720
4721 ASSERT (!IsListEmpty (&gBrowserContextList));
4722
4723 Link = GetFirstNode (&gBrowserContextList);
4724 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4725
4726 //
4727 // Restore FormBrowser context
4728 //
4729 gCurrentSelection = Context->Selection;
4730 gResetRequired = Context->ResetRequired;
4731 gExitRequired = Context->ExitRequired;
4732 mCurrentHiiHandle = Context->HiiHandle;
4733 mCurrentFormId = Context->FormId;
4734 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
4735
4736 //
4737 // Restore the menu history data.
4738 //
4739 while (!IsListEmpty (&Context->FormHistoryList)) {
4740 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
4741 RemoveEntryList (&MenuList->Link);
4742
4743 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
4744 }
4745
4746 //
4747 // Remove from FormBrowser context list
4748 //
4749 RemoveEntryList (&Context->Link);
4750 gBS->FreePool (Context);
4751 }
4752
4753 /**
4754 Find the matched FormSet context in the backup maintain list based on HiiHandle.
4755
4756 @param Handle The Hii Handle.
4757
4758 @return the found FormSet context. If no found, NULL will return.
4759
4760 **/
4761 FORM_BROWSER_FORMSET *
4762 GetFormSetFromHiiHandle (
4763 EFI_HII_HANDLE Handle
4764 )
4765 {
4766 LIST_ENTRY *Link;
4767 FORM_BROWSER_FORMSET *FormSet;
4768
4769 Link = GetFirstNode (&gBrowserFormSetList);
4770 while (!IsNull (&gBrowserFormSetList, Link)) {
4771 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4772 Link = GetNextNode (&gBrowserFormSetList, Link);
4773 if (!ValidateFormSet(FormSet)) {
4774 continue;
4775 }
4776 if (FormSet->HiiHandle == Handle) {
4777 return FormSet;
4778 }
4779 }
4780
4781 return NULL;
4782 }
4783
4784 /**
4785 Check whether the input HII handle is the FormSet that is being used.
4786
4787 @param Handle The Hii Handle.
4788
4789 @retval TRUE HII handle is being used.
4790 @retval FALSE HII handle is not being used.
4791
4792 **/
4793 BOOLEAN
4794 IsHiiHandleInBrowserContext (
4795 EFI_HII_HANDLE Handle
4796 )
4797 {
4798 LIST_ENTRY *Link;
4799 BROWSER_CONTEXT *Context;
4800
4801 //
4802 // HiiHandle is Current FormSet.
4803 //
4804 if (mCurrentHiiHandle == Handle) {
4805 return TRUE;
4806 }
4807
4808 //
4809 // Check whether HiiHandle is in BrowserContext.
4810 //
4811 Link = GetFirstNode (&gBrowserContextList);
4812 while (!IsNull (&gBrowserContextList, Link)) {
4813 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4814 if (Context->HiiHandle == Handle) {
4815 //
4816 // HiiHandle is in BrowserContext
4817 //
4818 return TRUE;
4819 }
4820 Link = GetNextNode (&gBrowserContextList, Link);
4821 }
4822
4823 return FALSE;
4824 }
4825
4826 /**
4827 Perform Password check.
4828 Passwork may be encrypted by driver that requires the specific check.
4829
4830 @param Form Form where Password Statement is in.
4831 @param Statement Password statement
4832 @param PasswordString Password string to be checked. It may be NULL.
4833 NULL means to restore password.
4834 "" string can be used to checked whether old password does exist.
4835
4836 @return Status Status of Password check.
4837 **/
4838 EFI_STATUS
4839 EFIAPI
4840 PasswordCheck (
4841 IN FORM_DISPLAY_ENGINE_FORM *Form,
4842 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
4843 IN EFI_STRING PasswordString OPTIONAL
4844 )
4845 {
4846 EFI_STATUS Status;
4847 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
4848 EFI_BROWSER_ACTION_REQUEST ActionRequest;
4849 EFI_IFR_TYPE_VALUE IfrTypeValue;
4850 FORM_BROWSER_STATEMENT *Question;
4851
4852 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
4853 Question = GetBrowserStatement(Statement);
4854 ASSERT (Question != NULL);
4855
4856 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
4857 if (ConfigAccess == NULL) {
4858 return EFI_UNSUPPORTED;
4859 }
4860 } else {
4861 if (PasswordString == NULL) {
4862 return EFI_SUCCESS;
4863 }
4864
4865 //
4866 // Check whether has preexisted password.
4867 //
4868 if (PasswordString[0] == 0) {
4869 if (*((CHAR16 *) Question->BufferValue) == 0) {
4870 return EFI_SUCCESS;
4871 } else {
4872 return EFI_NOT_READY;
4873 }
4874 }
4875
4876 //
4877 // Check whether the input password is same as preexisted password.
4878 //
4879 if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {
4880 return EFI_SUCCESS;
4881 } else {
4882 return EFI_NOT_READY;
4883 }
4884 }
4885
4886 //
4887 // Prepare password string in HII database
4888 //
4889 if (PasswordString != NULL) {
4890 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
4891 } else {
4892 IfrTypeValue.string = 0;
4893 }
4894
4895 //
4896 // Send password to Configuration Driver for validation
4897 //
4898 Status = ConfigAccess->Callback (
4899 ConfigAccess,
4900 EFI_BROWSER_ACTION_CHANGING,
4901 Question->QuestionId,
4902 Question->HiiValue.Type,
4903 &IfrTypeValue,
4904 &ActionRequest
4905 );
4906
4907 //
4908 // Remove password string from HII database
4909 //
4910 if (PasswordString != NULL) {
4911 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
4912 }
4913
4914 return Status;
4915 }
4916
4917 /**
4918 Find the registered HotKey based on KeyData.
4919
4920 @param[in] KeyData A pointer to a buffer that describes the keystroke
4921 information for the hot key.
4922
4923 @return The registered HotKey context. If no found, NULL will return.
4924 **/
4925 BROWSER_HOT_KEY *
4926 GetHotKeyFromRegisterList (
4927 IN EFI_INPUT_KEY *KeyData
4928 )
4929 {
4930 LIST_ENTRY *Link;
4931 BROWSER_HOT_KEY *HotKey;
4932
4933 Link = GetFirstNode (&gBrowserHotKeyList);
4934 while (!IsNull (&gBrowserHotKeyList, Link)) {
4935 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
4936 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
4937 return HotKey;
4938 }
4939 Link = GetNextNode (&gBrowserHotKeyList, Link);
4940 }
4941
4942 return NULL;
4943 }
4944
4945 /**
4946 Configure what scope the hot key will impact.
4947 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
4948 If no scope is set, the default scope will be FormSet level.
4949 After all registered hot keys are removed, previous Scope can reset to another level.
4950
4951 @param[in] Scope Scope level to be set.
4952
4953 @retval EFI_SUCCESS Scope is set correctly.
4954 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
4955 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
4956
4957 **/
4958 EFI_STATUS
4959 EFIAPI
4960 SetScope (
4961 IN BROWSER_SETTING_SCOPE Scope
4962 )
4963 {
4964 if (Scope >= MaxLevel) {
4965 return EFI_INVALID_PARAMETER;
4966 }
4967
4968 //
4969 // When no hot key registered in system or on the first setting,
4970 // Scope can be set.
4971 //
4972 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
4973 gBrowserSettingScope = Scope;
4974 mBrowserScopeFirstSet = FALSE;
4975 } else if (Scope != gBrowserSettingScope) {
4976 return EFI_UNSUPPORTED;
4977 }
4978
4979 return EFI_SUCCESS;
4980 }
4981
4982 /**
4983 Register the hot key with its browser action, or unregistered the hot key.
4984 Only support hot key that is not printable character (control key, function key, etc.).
4985 If the action value is zero, the hot key will be unregistered if it has been registered.
4986 If the same hot key has been registered, the new action and help string will override the previous ones.
4987
4988 @param[in] KeyData A pointer to a buffer that describes the keystroke
4989 information for the hot key. Its type is EFI_INPUT_KEY to
4990 be supported by all ConsoleIn devices.
4991 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
4992 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
4993 @param[in] HelpString Help string that describes the hot key information.
4994 Its value may be NULL for the unregistered hot key.
4995
4996 @retval EFI_SUCCESS Hot key is registered or unregistered.
4997 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
4998 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
4999 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
5000 **/
5001 EFI_STATUS
5002 EFIAPI
5003 RegisterHotKey (
5004 IN EFI_INPUT_KEY *KeyData,
5005 IN UINT32 Action,
5006 IN UINT16 DefaultId,
5007 IN EFI_STRING HelpString OPTIONAL
5008 )
5009 {
5010 BROWSER_HOT_KEY *HotKey;
5011
5012 //
5013 // Check input parameters.
5014 //
5015 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
5016 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
5017 return EFI_INVALID_PARAMETER;
5018 }
5019
5020 //
5021 // Check whether the input KeyData is in BrowserHotKeyList.
5022 //
5023 HotKey = GetHotKeyFromRegisterList (KeyData);
5024
5025 //
5026 // Unregister HotKey
5027 //
5028 if (Action == BROWSER_ACTION_UNREGISTER) {
5029 if (HotKey != NULL) {
5030 //
5031 // The registered HotKey is found.
5032 // Remove it from List, and free its resource.
5033 //
5034 RemoveEntryList (&HotKey->Link);
5035 FreePool (HotKey->KeyData);
5036 FreePool (HotKey->HelpString);
5037 return EFI_SUCCESS;
5038 } else {
5039 //
5040 // The registered HotKey is not found.
5041 //
5042 return EFI_NOT_FOUND;
5043 }
5044 }
5045
5046 //
5047 // Register HotKey into List.
5048 //
5049 if (HotKey == NULL) {
5050 //
5051 // Create new Key, and add it into List.
5052 //
5053 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
5054 ASSERT (HotKey != NULL);
5055 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
5056 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
5057 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
5058 }
5059
5060 //
5061 // Fill HotKey information.
5062 //
5063 HotKey->Action = Action;
5064 HotKey->DefaultId = DefaultId;
5065 if (HotKey->HelpString != NULL) {
5066 FreePool (HotKey->HelpString);
5067 }
5068 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
5069
5070 return EFI_SUCCESS;
5071 }
5072
5073 /**
5074 Register Exit handler function.
5075 When more than one handler function is registered, the latter one will override the previous one.
5076 When NULL handler is specified, the previous Exit handler will be unregistered.
5077
5078 @param[in] Handler Pointer to handler function.
5079
5080 **/
5081 VOID
5082 EFIAPI
5083 RegiserExitHandler (
5084 IN EXIT_HANDLER Handler
5085 )
5086 {
5087 ExitHandlerFunction = Handler;
5088 return;
5089 }
5090
5091 /**
5092 Check whether the browser data has been modified.
5093
5094 @retval TRUE Browser data is modified.
5095 @retval FALSE No browser data is modified.
5096
5097 **/
5098 BOOLEAN
5099 EFIAPI
5100 IsBrowserDataModified (
5101 VOID
5102 )
5103 {
5104 LIST_ENTRY *Link;
5105 FORM_BROWSER_FORMSET *FormSet;
5106
5107 switch (gBrowserSettingScope) {
5108 case FormLevel:
5109 if (gCurrentSelection == NULL) {
5110 return FALSE;
5111 }
5112 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
5113
5114 case FormSetLevel:
5115 if (gCurrentSelection == NULL) {
5116 return FALSE;
5117 }
5118 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
5119
5120 case SystemLevel:
5121 Link = GetFirstNode (&gBrowserFormSetList);
5122 while (!IsNull (&gBrowserFormSetList, Link)) {
5123 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5124 if (!ValidateFormSet(FormSet)) {
5125 continue;
5126 }
5127
5128 if (IsNvUpdateRequiredForFormSet (FormSet)) {
5129 return TRUE;
5130 }
5131 Link = GetNextNode (&gBrowserFormSetList, Link);
5132 }
5133 return FALSE;
5134
5135 default:
5136 return FALSE;
5137 }
5138 }
5139
5140 /**
5141 Execute the action requested by the Action parameter.
5142
5143 @param[in] Action Execute the request action.
5144 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
5145
5146 @retval EFI_SUCCESS Execute the request action succss.
5147 @retval EFI_INVALID_PARAMETER The input action value is invalid.
5148
5149 **/
5150 EFI_STATUS
5151 EFIAPI
5152 ExecuteAction (
5153 IN UINT32 Action,
5154 IN UINT16 DefaultId
5155 )
5156 {
5157 EFI_STATUS Status;
5158 FORM_BROWSER_FORMSET *FormSet;
5159 FORM_BROWSER_FORM *Form;
5160
5161 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
5162 return EFI_NOT_READY;
5163 }
5164
5165 Status = EFI_SUCCESS;
5166 FormSet = NULL;
5167 Form = NULL;
5168 if (gBrowserSettingScope < SystemLevel) {
5169 FormSet = gCurrentSelection->FormSet;
5170 Form = gCurrentSelection->Form;
5171 }
5172
5173 //
5174 // Executet the discard action.
5175 //
5176 if ((Action & BROWSER_ACTION_DISCARD) != 0) {
5177 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
5178 if (EFI_ERROR (Status)) {
5179 return Status;
5180 }
5181 }
5182
5183 //
5184 // Executet the difault action.
5185 //
5186 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
5187 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
5188 if (EFI_ERROR (Status)) {
5189 return Status;
5190 }
5191 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
5192 }
5193
5194 //
5195 // Executet the submit action.
5196 //
5197 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
5198 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
5199 if (EFI_ERROR (Status)) {
5200 return Status;
5201 }
5202 }
5203
5204 //
5205 // Executet the reset action.
5206 //
5207 if ((Action & BROWSER_ACTION_RESET) != 0) {
5208 gResetRequired = TRUE;
5209 }
5210
5211 //
5212 // Executet the exit action.
5213 //
5214 if ((Action & BROWSER_ACTION_EXIT) != 0) {
5215 DiscardForm (FormSet, Form, gBrowserSettingScope);
5216 if (gBrowserSettingScope == SystemLevel) {
5217 if (ExitHandlerFunction != NULL) {
5218 ExitHandlerFunction ();
5219 }
5220 }
5221
5222 gExitRequired = TRUE;
5223 }
5224
5225 return Status;
5226 }
5227
5228 /**
5229 Create reminder to let user to choose save or discard the changed browser data.
5230 Caller can use it to actively check the changed browser data.
5231
5232 @retval BROWSER_NO_CHANGES No browser data is changed.
5233 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
5234 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
5235 @retval BROWSER_KEEP_CURRENT Browser keep current changes.
5236
5237 **/
5238 UINT32
5239 EFIAPI
5240 SaveReminder (
5241 VOID
5242 )
5243 {
5244 LIST_ENTRY *Link;
5245 FORM_BROWSER_FORMSET *FormSet;
5246 BOOLEAN IsDataChanged;
5247 UINT32 DataSavedAction;
5248 UINT32 ConfirmRet;
5249
5250 DataSavedAction = BROWSER_NO_CHANGES;
5251 IsDataChanged = FALSE;
5252 Link = GetFirstNode (&gBrowserFormSetList);
5253 while (!IsNull (&gBrowserFormSetList, Link)) {
5254 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5255 Link = GetNextNode (&gBrowserFormSetList, Link);
5256 if (!ValidateFormSet(FormSet)) {
5257 continue;
5258 }
5259 if (IsNvUpdateRequiredForFormSet (FormSet)) {
5260 IsDataChanged = TRUE;
5261 break;
5262 }
5263 }
5264
5265 //
5266 // No data is changed. No save is required.
5267 //
5268 if (!IsDataChanged) {
5269 return DataSavedAction;
5270 }
5271
5272 //
5273 // If data is changed, prompt user to save or discard it.
5274 //
5275 do {
5276 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
5277
5278 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
5279 SubmitForm (NULL, NULL, SystemLevel);
5280 DataSavedAction = BROWSER_SAVE_CHANGES;
5281 break;
5282 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
5283 DiscardForm (NULL, NULL, SystemLevel);
5284 DataSavedAction = BROWSER_DISCARD_CHANGES;
5285 break;
5286 } else if (ConfirmRet == BROWSER_ACTION_NONE) {
5287 DataSavedAction = BROWSER_KEEP_CURRENT;
5288 break;
5289 }
5290 } while (1);
5291
5292 return DataSavedAction;
5293 }
5294
5295 /**
5296 Check whether the Reset Required for the browser
5297
5298 @retval TRUE Browser required to reset after exit.
5299 @retval FALSE Browser not need to reset after exit.
5300
5301 **/
5302 BOOLEAN
5303 EFIAPI
5304 IsResetRequired (
5305 VOID
5306 )
5307 {
5308 return gResetRequired;
5309 }
5310