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