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