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