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