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