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