]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
f86f369ff28c7c27b257db6cdbf3d0f89ebb0328
[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 //
612 // If set browser data, pre load all hii formset to avoid set the varstore which is not
613 // saved in browser.
614 //
615 if (!RetrieveData && (gBrowserSettingScope == SystemLevel)) {
616 LoadAllHiiFormset();
617 }
618
619 if (VariableGuid != NULL) {
620 //
621 // Try to find target storage in the current formset.
622 //
623 Link = GetFirstNode (&gBrowserStorageList);
624 while (!IsNull (&gBrowserStorageList, Link)) {
625 Storage = BROWSER_STORAGE_FROM_LINK (Link);
626 Link = GetNextNode (&gBrowserStorageList, Link);
627 //
628 // Check the current storage.
629 //
630 if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
631 continue;
632 }
633
634 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
635 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
636 //
637 // Buffer storage require both GUID and Name
638 //
639 if (VariableName == NULL) {
640 return EFI_NOT_FOUND;
641 }
642
643 if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
644 continue;
645 }
646 }
647
648 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE ||
649 Storage->Type == EFI_HII_VARSTORE_BUFFER) {
650 if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) {
651 return EFI_NOT_FOUND;
652 }
653
654 if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {
655 continue;
656 }
657 }
658
659 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);
660 if (EFI_ERROR (Status)) {
661 return Status;
662 }
663
664 //
665 // Different formsets may have same varstore, so here just set the flag
666 // not exit the circle.
667 //
668 Found = TRUE;
669 break;
670 }
671
672 if (!Found) {
673 return EFI_NOT_FOUND;
674 }
675 } else {
676 //
677 // GUID/Name is not specified, take the first storage in FormSet
678 //
679 if (mSystemLevelFormSet == NULL) {
680 return EFI_NOT_READY;
681 }
682
683 //
684 // Generate <ConfigResp>
685 //
686 Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);
687 if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {
688 return EFI_UNSUPPORTED;
689 }
690
691 FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
692
693 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);
694 if (EFI_ERROR (Status)) {
695 return Status;
696 }
697 }
698
699 if (RetrieveData) {
700 Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
701 *ResultsDataSize = TotalSize;
702 }
703
704 return Status;
705
706 }
707
708
709 /**
710 Callback function for SimpleTextInEx protocol install events
711
712 @param Event the event that is signaled.
713 @param Context not used here.
714
715 **/
716 VOID
717 EFIAPI
718 FormDisplayCallback (
719 IN EFI_EVENT Event,
720 IN VOID *Context
721 )
722 {
723 EFI_STATUS Status;
724
725 if (mFormDisplay != NULL) {
726 return;
727 }
728
729 Status = gBS->LocateProtocol (
730 &gEdkiiFormDisplayEngineProtocolGuid,
731 NULL,
732 (VOID **) &mFormDisplay
733 );
734 }
735
736 /**
737 Initialize Setup Browser driver.
738
739 @param ImageHandle The image handle.
740 @param SystemTable The system table.
741
742 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
743 @return Other value if failed to initialize the Setup Browser module.
744
745 **/
746 EFI_STATUS
747 EFIAPI
748 InitializeSetup (
749 IN EFI_HANDLE ImageHandle,
750 IN EFI_SYSTEM_TABLE *SystemTable
751 )
752 {
753 EFI_STATUS Status;
754 VOID *Registration;
755
756 //
757 // Locate required Hii relative protocols
758 //
759 Status = gBS->LocateProtocol (
760 &gEfiHiiDatabaseProtocolGuid,
761 NULL,
762 (VOID **) &mHiiDatabase
763 );
764 ASSERT_EFI_ERROR (Status);
765
766 Status = gBS->LocateProtocol (
767 &gEfiHiiConfigRoutingProtocolGuid,
768 NULL,
769 (VOID **) &mHiiConfigRouting
770 );
771 ASSERT_EFI_ERROR (Status);
772
773 Status = gBS->LocateProtocol (
774 &gEfiDevicePathFromTextProtocolGuid,
775 NULL,
776 (VOID **) &mPathFromText
777 );
778
779 //
780 // Install FormBrowser2 protocol
781 //
782 mPrivateData.Handle = NULL;
783 Status = gBS->InstallProtocolInterface (
784 &mPrivateData.Handle,
785 &gEfiFormBrowser2ProtocolGuid,
786 EFI_NATIVE_INTERFACE,
787 &mPrivateData.FormBrowser2
788 );
789 ASSERT_EFI_ERROR (Status);
790
791 //
792 // Install FormBrowserEx2 protocol
793 //
794 InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
795 InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
796 mPrivateData.Handle = NULL;
797 Status = gBS->InstallProtocolInterface (
798 &mPrivateData.Handle,
799 &gEdkiiFormBrowserEx2ProtocolGuid,
800 EFI_NATIVE_INTERFACE,
801 &mPrivateData.FormBrowserEx2
802 );
803 ASSERT_EFI_ERROR (Status);
804
805 Status = gBS->InstallProtocolInterface (
806 &mPrivateData.Handle,
807 &gEfiFormBrowserExProtocolGuid,
808 EFI_NATIVE_INTERFACE,
809 &mPrivateData.FormBrowserEx
810 );
811 ASSERT_EFI_ERROR (Status);
812
813 InitializeDisplayFormData ();
814
815 Status = gBS->LocateProtocol (
816 &gEdkiiFormDisplayEngineProtocolGuid,
817 NULL,
818 (VOID **) &mFormDisplay
819 );
820
821 if (EFI_ERROR (Status)) {
822 EfiCreateProtocolNotifyEvent (
823 &gEdkiiFormDisplayEngineProtocolGuid,
824 TPL_CALLBACK,
825 FormDisplayCallback,
826 NULL,
827 &Registration
828 );
829 }
830
831 return EFI_SUCCESS;
832 }
833
834
835 /**
836 Create a new string in HII Package List.
837
838 @param String The String to be added
839 @param HiiHandle The package list in the HII database to insert the
840 specified string.
841
842 @return The output string.
843
844 **/
845 EFI_STRING_ID
846 NewString (
847 IN CHAR16 *String,
848 IN EFI_HII_HANDLE HiiHandle
849 )
850 {
851 EFI_STRING_ID StringId;
852
853 StringId = HiiSetString (HiiHandle, 0, String, NULL);
854 ASSERT (StringId != 0);
855
856 return StringId;
857 }
858
859
860 /**
861 Delete a string from HII Package List.
862
863 @param StringId Id of the string in HII database.
864 @param HiiHandle The HII package list handle.
865
866 @retval EFI_SUCCESS The string was deleted successfully.
867
868 **/
869 EFI_STATUS
870 DeleteString (
871 IN EFI_STRING_ID StringId,
872 IN EFI_HII_HANDLE HiiHandle
873 )
874 {
875 CHAR16 NullChar;
876
877 NullChar = CHAR_NULL;
878 HiiSetString (HiiHandle, StringId, &NullChar, NULL);
879 return EFI_SUCCESS;
880 }
881
882
883 /**
884 Get the string based on the StringId and HII Package List Handle.
885
886 @param Token The String's ID.
887 @param HiiHandle The package list in the HII database to search for
888 the specified string.
889
890 @return The output string.
891
892 **/
893 CHAR16 *
894 GetToken (
895 IN EFI_STRING_ID Token,
896 IN EFI_HII_HANDLE HiiHandle
897 )
898 {
899 EFI_STRING String;
900
901 if (HiiHandle == NULL) {
902 return NULL;
903 }
904
905 String = HiiGetString (HiiHandle, Token, NULL);
906 if (String == NULL) {
907 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
908 ASSERT (String != NULL);
909 }
910 return (CHAR16 *) String;
911 }
912
913
914 /**
915 Allocate new memory and then copy the Unicode string Source to Destination.
916
917 @param Dest Location to copy string
918 @param Src String to copy
919
920 **/
921 VOID
922 NewStringCpy (
923 IN OUT CHAR16 **Dest,
924 IN CHAR16 *Src
925 )
926 {
927 if (*Dest != NULL) {
928 FreePool (*Dest);
929 }
930 *Dest = AllocateCopyPool (StrSize (Src), Src);
931 ASSERT (*Dest != NULL);
932 }
933
934
935 /**
936 Allocate new memory and concatinate Source on the end of Destination.
937
938 @param Dest String to added to the end of.
939 @param Src String to concatinate.
940
941 **/
942 VOID
943 NewStringCat (
944 IN OUT CHAR16 **Dest,
945 IN CHAR16 *Src
946 )
947 {
948 CHAR16 *NewString;
949 UINTN TmpSize;
950
951 if (*Dest == NULL) {
952 NewStringCpy (Dest, Src);
953 return;
954 }
955
956 TmpSize = StrSize (*Dest);
957 NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);
958 ASSERT (NewString != NULL);
959
960 StrCpy (NewString, *Dest);
961 StrCat (NewString, Src);
962
963 FreePool (*Dest);
964 *Dest = NewString;
965 }
966
967 /**
968 Get Value for given Name from a NameValue Storage.
969
970 @param Storage The NameValue Storage.
971 @param Name The Name.
972 @param Value The retured Value.
973 @param GetValueFrom Where to get source value, from EditValue or Value.
974
975 @retval EFI_SUCCESS Value found for given Name.
976 @retval EFI_NOT_FOUND No such Name found in NameValue storage.
977
978 **/
979 EFI_STATUS
980 GetValueByName (
981 IN BROWSER_STORAGE *Storage,
982 IN CHAR16 *Name,
983 IN OUT CHAR16 **Value,
984 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
985 )
986 {
987 LIST_ENTRY *Link;
988 NAME_VALUE_NODE *Node;
989
990 if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {
991 return EFI_INVALID_PARAMETER;
992 }
993
994 *Value = NULL;
995
996 Link = GetFirstNode (&Storage->NameValueListHead);
997 while (!IsNull (&Storage->NameValueListHead, Link)) {
998 Node = NAME_VALUE_NODE_FROM_LINK (Link);
999
1000 if (StrCmp (Name, Node->Name) == 0) {
1001 if (GetValueFrom == GetSetValueWithEditBuffer) {
1002 NewStringCpy (Value, Node->EditValue);
1003 } else {
1004 NewStringCpy (Value, Node->Value);
1005 }
1006 return EFI_SUCCESS;
1007 }
1008
1009 Link = GetNextNode (&Storage->NameValueListHead, Link);
1010 }
1011
1012 return EFI_NOT_FOUND;
1013 }
1014
1015
1016 /**
1017 Set Value of given Name in a NameValue Storage.
1018
1019 @param Storage The NameValue Storage.
1020 @param Name The Name.
1021 @param Value The Value to set.
1022 @param SetValueTo Whether update editValue or Value.
1023 @param ReturnNode The node use the input name.
1024
1025 @retval EFI_SUCCESS Value found for given Name.
1026 @retval EFI_NOT_FOUND No such Name found in NameValue storage.
1027
1028 **/
1029 EFI_STATUS
1030 SetValueByName (
1031 IN BROWSER_STORAGE *Storage,
1032 IN CHAR16 *Name,
1033 IN CHAR16 *Value,
1034 IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
1035 OUT NAME_VALUE_NODE **ReturnNode
1036 )
1037 {
1038 LIST_ENTRY *Link;
1039 NAME_VALUE_NODE *Node;
1040 CHAR16 *Buffer;
1041
1042 if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {
1043 return EFI_INVALID_PARAMETER;
1044 }
1045
1046 Link = GetFirstNode (&Storage->NameValueListHead);
1047 while (!IsNull (&Storage->NameValueListHead, Link)) {
1048 Node = NAME_VALUE_NODE_FROM_LINK (Link);
1049
1050 if (StrCmp (Name, Node->Name) == 0) {
1051 if (SetValueTo == GetSetValueWithEditBuffer) {
1052 Buffer = Node->EditValue;
1053 } else {
1054 Buffer = Node->Value;
1055 }
1056 if (Buffer != NULL) {
1057 FreePool (Buffer);
1058 }
1059 Buffer = AllocateCopyPool (StrSize (Value), Value);
1060 ASSERT (Buffer != NULL);
1061 if (SetValueTo == GetSetValueWithEditBuffer) {
1062 Node->EditValue = Buffer;
1063 } else {
1064 Node->Value = Buffer;
1065 }
1066
1067 if (ReturnNode != NULL) {
1068 *ReturnNode = Node;
1069 }
1070
1071 return EFI_SUCCESS;
1072 }
1073
1074 Link = GetNextNode (&Storage->NameValueListHead, Link);
1075 }
1076
1077 return EFI_NOT_FOUND;
1078 }
1079
1080
1081 /**
1082 Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
1083
1084 @param Storage The Storage to be conveted.
1085 @param ConfigResp The returned <ConfigResp>.
1086 @param ConfigRequest The ConfigRequest string.
1087 @param GetEditBuf Get the data from editbuffer or buffer.
1088
1089 @retval EFI_SUCCESS Convert success.
1090 @retval EFI_INVALID_PARAMETER Incorrect storage type.
1091
1092 **/
1093 EFI_STATUS
1094 StorageToConfigResp (
1095 IN BROWSER_STORAGE *Storage,
1096 IN CHAR16 **ConfigResp,
1097 IN CHAR16 *ConfigRequest,
1098 IN BOOLEAN GetEditBuf
1099 )
1100 {
1101 EFI_STATUS Status;
1102 EFI_STRING Progress;
1103 LIST_ENTRY *Link;
1104 NAME_VALUE_NODE *Node;
1105 UINT8 *SourceBuf;
1106
1107 Status = EFI_SUCCESS;
1108
1109 switch (Storage->Type) {
1110 case EFI_HII_VARSTORE_BUFFER:
1111 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
1112 SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;
1113 Status = mHiiConfigRouting->BlockToConfig (
1114 mHiiConfigRouting,
1115 ConfigRequest,
1116 SourceBuf,
1117 Storage->Size,
1118 ConfigResp,
1119 &Progress
1120 );
1121 break;
1122
1123 case EFI_HII_VARSTORE_NAME_VALUE:
1124 *ConfigResp = NULL;
1125 NewStringCat (ConfigResp, Storage->ConfigHdr);
1126
1127 Link = GetFirstNode (&Storage->NameValueListHead);
1128 while (!IsNull (&Storage->NameValueListHead, Link)) {
1129 Node = NAME_VALUE_NODE_FROM_LINK (Link);
1130
1131 if (StrStr (ConfigRequest, Node->Name) != NULL) {
1132 NewStringCat (ConfigResp, L"&");
1133 NewStringCat (ConfigResp, Node->Name);
1134 NewStringCat (ConfigResp, L"=");
1135 if (GetEditBuf) {
1136 NewStringCat (ConfigResp, Node->EditValue);
1137 } else {
1138 NewStringCat (ConfigResp, Node->Value);
1139 }
1140 }
1141 Link = GetNextNode (&Storage->NameValueListHead, Link);
1142 }
1143 break;
1144
1145 case EFI_HII_VARSTORE_EFI_VARIABLE:
1146 default:
1147 Status = EFI_INVALID_PARAMETER;
1148 break;
1149 }
1150
1151 return Status;
1152 }
1153
1154
1155 /**
1156 Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
1157
1158 @param Storage The Storage to receive the settings.
1159 @param ConfigResp The <ConfigResp> to be converted.
1160
1161 @retval EFI_SUCCESS Convert success.
1162 @retval EFI_INVALID_PARAMETER Incorrect storage type.
1163
1164 **/
1165 EFI_STATUS
1166 ConfigRespToStorage (
1167 IN BROWSER_STORAGE *Storage,
1168 IN CHAR16 *ConfigResp
1169 )
1170 {
1171 EFI_STATUS Status;
1172 EFI_STRING Progress;
1173 UINTN BufferSize;
1174 CHAR16 *StrPtr;
1175 CHAR16 *Name;
1176 CHAR16 *Value;
1177
1178 Status = EFI_SUCCESS;
1179
1180 switch (Storage->Type) {
1181 case EFI_HII_VARSTORE_BUFFER:
1182 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
1183 BufferSize = Storage->Size;
1184 Status = mHiiConfigRouting->ConfigToBlock (
1185 mHiiConfigRouting,
1186 ConfigResp,
1187 Storage->EditBuffer,
1188 &BufferSize,
1189 &Progress
1190 );
1191 break;
1192
1193 case EFI_HII_VARSTORE_NAME_VALUE:
1194 StrPtr = StrStr (ConfigResp, L"PATH");
1195 if (StrPtr == NULL) {
1196 break;
1197 }
1198 StrPtr = StrStr (ConfigResp, L"&");
1199 while (StrPtr != NULL) {
1200 //
1201 // Skip '&'
1202 //
1203 StrPtr = StrPtr + 1;
1204 Name = StrPtr;
1205 StrPtr = StrStr (StrPtr, L"=");
1206 if (StrPtr == NULL) {
1207 break;
1208 }
1209 *StrPtr = 0;
1210
1211 //
1212 // Skip '='
1213 //
1214 StrPtr = StrPtr + 1;
1215 Value = StrPtr;
1216 StrPtr = StrStr (StrPtr, L"&");
1217 if (StrPtr != NULL) {
1218 *StrPtr = 0;
1219 }
1220 SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);
1221 }
1222 break;
1223
1224 case EFI_HII_VARSTORE_EFI_VARIABLE:
1225 default:
1226 Status = EFI_INVALID_PARAMETER;
1227 break;
1228 }
1229
1230 return Status;
1231 }
1232
1233
1234 /**
1235 Get Question's current Value.
1236
1237 @param FormSet FormSet data structure.
1238 @param Form Form data structure.
1239 @param Question Question to be initialized.
1240 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
1241
1242 @retval EFI_SUCCESS The function completed successfully.
1243
1244 **/
1245 EFI_STATUS
1246 GetQuestionValue (
1247 IN FORM_BROWSER_FORMSET *FormSet,
1248 IN FORM_BROWSER_FORM *Form,
1249 IN OUT FORM_BROWSER_STATEMENT *Question,
1250 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
1251 )
1252 {
1253 EFI_STATUS Status;
1254 BOOLEAN Enabled;
1255 BOOLEAN Pending;
1256 UINT8 *Dst;
1257 UINTN StorageWidth;
1258 EFI_TIME EfiTime;
1259 BROWSER_STORAGE *Storage;
1260 EFI_IFR_TYPE_VALUE *QuestionValue;
1261 CHAR16 *ConfigRequest;
1262 CHAR16 *Progress;
1263 CHAR16 *Result;
1264 CHAR16 *Value;
1265 CHAR16 *StringPtr;
1266 UINTN Length;
1267 UINTN Index;
1268 UINTN LengthStr;
1269 BOOLEAN IsBufferStorage;
1270 BOOLEAN IsString;
1271 CHAR16 TemStr[5];
1272 UINT8 DigitUint8;
1273
1274 Status = EFI_SUCCESS;
1275 Value = NULL;
1276 Result = NULL;
1277
1278 if (GetValueFrom >= GetSetValueWithMax) {
1279 return EFI_INVALID_PARAMETER;
1280 }
1281
1282 //
1283 // Question value is provided by an Expression, evaluate it
1284 //
1285 if (Question->ValueExpression != NULL) {
1286 Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
1287 if (!EFI_ERROR (Status)) {
1288 if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
1289 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
1290 if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
1291 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
1292 Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
1293 } else {
1294 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
1295 Question->HiiValue.BufferLen = Question->StorageWidth;
1296 }
1297 FreePool (Question->ValueExpression->Result.Buffer);
1298 }
1299 Question->HiiValue.Type = Question->ValueExpression->Result.Type;
1300 CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
1301 }
1302 return Status;
1303 }
1304
1305 //
1306 // Get question value by read expression.
1307 //
1308 if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1309 Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
1310 if (!EFI_ERROR (Status) &&
1311 ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
1312 //
1313 // Only update question value to the valid result.
1314 //
1315 if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
1316 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
1317 if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
1318 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
1319 Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
1320 } else {
1321 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
1322 Question->HiiValue.BufferLen = Question->StorageWidth;
1323 }
1324 FreePool (Question->ReadExpression->Result.Buffer);
1325 }
1326 Question->HiiValue.Type = Question->ReadExpression->Result.Type;
1327 CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
1328 return EFI_SUCCESS;
1329 }
1330 }
1331
1332 //
1333 // Question value is provided by RTC
1334 //
1335 Storage = Question->Storage;
1336 QuestionValue = &Question->HiiValue.Value;
1337 if (Storage == NULL) {
1338 //
1339 // It's a Question without storage, or RTC date/time
1340 //
1341 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1342 //
1343 // Date and time define the same Flags bit
1344 //
1345 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1346 case QF_DATE_STORAGE_TIME:
1347 Status = gRT->GetTime (&EfiTime, NULL);
1348 break;
1349
1350 case QF_DATE_STORAGE_WAKEUP:
1351 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1352 break;
1353
1354 case QF_DATE_STORAGE_NORMAL:
1355 default:
1356 //
1357 // For date/time without storage
1358 //
1359 return EFI_SUCCESS;
1360 }
1361
1362 if (EFI_ERROR (Status)) {
1363 return Status;
1364 }
1365
1366 if (Question->Operand == EFI_IFR_DATE_OP) {
1367 QuestionValue->date.Year = EfiTime.Year;
1368 QuestionValue->date.Month = EfiTime.Month;
1369 QuestionValue->date.Day = EfiTime.Day;
1370 } else {
1371 QuestionValue->time.Hour = EfiTime.Hour;
1372 QuestionValue->time.Minute = EfiTime.Minute;
1373 QuestionValue->time.Second = EfiTime.Second;
1374 }
1375 }
1376
1377 return EFI_SUCCESS;
1378 }
1379
1380 //
1381 // Question value is provided by EFI variable
1382 //
1383 StorageWidth = Question->StorageWidth;
1384 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1385 if (Question->BufferValue != NULL) {
1386 Dst = Question->BufferValue;
1387 } else {
1388 Dst = (UINT8 *) QuestionValue;
1389 }
1390
1391 Status = gRT->GetVariable (
1392 Question->VariableName,
1393 &Storage->Guid,
1394 NULL,
1395 &StorageWidth,
1396 Dst
1397 );
1398 //
1399 // Always return success, even this EFI variable doesn't exist
1400 //
1401 return EFI_SUCCESS;
1402 }
1403
1404 //
1405 // Question Value is provided by Buffer Storage or NameValue Storage
1406 //
1407 if (Question->BufferValue != NULL) {
1408 //
1409 // This Question is password or orderedlist
1410 //
1411 Dst = Question->BufferValue;
1412 } else {
1413 //
1414 // Other type of Questions
1415 //
1416 Dst = (UINT8 *) &Question->HiiValue.Value;
1417 }
1418
1419 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1420 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1421 IsBufferStorage = TRUE;
1422 } else {
1423 IsBufferStorage = FALSE;
1424 }
1425 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1426 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
1427 if (IsBufferStorage) {
1428 if (GetValueFrom == GetSetValueWithEditBuffer) {
1429 //
1430 // Copy from storage Edit buffer
1431 //
1432 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1433 } else {
1434 //
1435 // Copy from storage Edit buffer
1436 //
1437 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1438 }
1439 } else {
1440 Value = NULL;
1441 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
1442 if (EFI_ERROR (Status)) {
1443 return Status;
1444 }
1445
1446 ASSERT (Value != NULL);
1447 LengthStr = StrLen (Value);
1448 Status = EFI_SUCCESS;
1449 if (IsString) {
1450 //
1451 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1452 // Add string tail char L'\0' into Length
1453 //
1454 Length = StorageWidth + sizeof (CHAR16);
1455 if (Length < ((LengthStr / 4 + 1) * 2)) {
1456 Status = EFI_BUFFER_TOO_SMALL;
1457 } else {
1458 StringPtr = (CHAR16 *) Dst;
1459 ZeroMem (TemStr, sizeof (TemStr));
1460 for (Index = 0; Index < LengthStr; Index += 4) {
1461 StrnCpy (TemStr, Value + Index, 4);
1462 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1463 }
1464 //
1465 // Add tailing L'\0' character
1466 //
1467 StringPtr[Index/4] = L'\0';
1468 }
1469 } else {
1470 if (StorageWidth < ((LengthStr + 1) / 2)) {
1471 Status = EFI_BUFFER_TOO_SMALL;
1472 } else {
1473 ZeroMem (TemStr, sizeof (TemStr));
1474 for (Index = 0; Index < LengthStr; Index ++) {
1475 TemStr[0] = Value[LengthStr - Index - 1];
1476 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1477 if ((Index & 1) == 0) {
1478 Dst [Index/2] = DigitUint8;
1479 } else {
1480 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1481 }
1482 }
1483 }
1484 }
1485
1486 FreePool (Value);
1487 }
1488 } else {
1489 //
1490 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
1491 // <ConfigHdr> + "&" + <VariableName>
1492 //
1493 if (IsBufferStorage) {
1494 Length = StrLen (Storage->ConfigHdr);
1495 Length += StrLen (Question->BlockName);
1496 } else {
1497 Length = StrLen (Storage->ConfigHdr);
1498 Length += StrLen (Question->VariableName) + 1;
1499 }
1500 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
1501 ASSERT (ConfigRequest != NULL);
1502
1503 StrCpy (ConfigRequest, Storage->ConfigHdr);
1504 if (IsBufferStorage) {
1505 StrCat (ConfigRequest, Question->BlockName);
1506 } else {
1507 StrCat (ConfigRequest, L"&");
1508 StrCat (ConfigRequest, Question->VariableName);
1509 }
1510
1511 //
1512 // Request current settings from Configuration Driver
1513 //
1514 Status = mHiiConfigRouting->ExtractConfig (
1515 mHiiConfigRouting,
1516 ConfigRequest,
1517 &Progress,
1518 &Result
1519 );
1520 FreePool (ConfigRequest);
1521 if (EFI_ERROR (Status)) {
1522 return Status;
1523 }
1524
1525 //
1526 // Skip <ConfigRequest>
1527 //
1528 if (IsBufferStorage) {
1529 Value = StrStr (Result, L"&VALUE");
1530 if (Value == NULL) {
1531 FreePool (Result);
1532 return EFI_NOT_FOUND;
1533 }
1534 //
1535 // Skip "&VALUE"
1536 //
1537 Value = Value + 6;
1538 } else {
1539 Value = Result + Length;
1540 }
1541 if (*Value != '=') {
1542 FreePool (Result);
1543 return EFI_NOT_FOUND;
1544 }
1545 //
1546 // Skip '=', point to value
1547 //
1548 Value = Value + 1;
1549
1550 //
1551 // Suppress <AltResp> if any
1552 //
1553 StringPtr = Value;
1554 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1555 StringPtr++;
1556 }
1557 *StringPtr = L'\0';
1558
1559 LengthStr = StrLen (Value);
1560 Status = EFI_SUCCESS;
1561 if (!IsBufferStorage && IsString) {
1562 //
1563 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1564 // Add string tail char L'\0' into Length
1565 //
1566 Length = StorageWidth + sizeof (CHAR16);
1567 if (Length < ((LengthStr / 4 + 1) * 2)) {
1568 Status = EFI_BUFFER_TOO_SMALL;
1569 } else {
1570 StringPtr = (CHAR16 *) Dst;
1571 ZeroMem (TemStr, sizeof (TemStr));
1572 for (Index = 0; Index < LengthStr; Index += 4) {
1573 StrnCpy (TemStr, Value + Index, 4);
1574 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1575 }
1576 //
1577 // Add tailing L'\0' character
1578 //
1579 StringPtr[Index/4] = L'\0';
1580 }
1581 } else {
1582 if (StorageWidth < ((LengthStr + 1) / 2)) {
1583 Status = EFI_BUFFER_TOO_SMALL;
1584 } else {
1585 ZeroMem (TemStr, sizeof (TemStr));
1586 for (Index = 0; Index < LengthStr; Index ++) {
1587 TemStr[0] = Value[LengthStr - Index - 1];
1588 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1589 if ((Index & 1) == 0) {
1590 Dst [Index/2] = DigitUint8;
1591 } else {
1592 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1593 }
1594 }
1595 }
1596 }
1597
1598 if (EFI_ERROR (Status)) {
1599 FreePool (Result);
1600 return Status;
1601 }
1602
1603 //
1604 // Synchronize Edit Buffer
1605 //
1606 if (IsBufferStorage) {
1607 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
1608 } else {
1609 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
1610 }
1611
1612 if (Result != NULL) {
1613 FreePool (Result);
1614 }
1615 }
1616
1617 return Status;
1618 }
1619
1620
1621 /**
1622 Save Question Value to edit copy(cached) or Storage(uncached).
1623
1624 @param FormSet FormSet data structure.
1625 @param Form Form data structure.
1626 @param Question Pointer to the Question.
1627 @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
1628
1629 @retval EFI_SUCCESS The function completed successfully.
1630
1631 **/
1632 EFI_STATUS
1633 SetQuestionValue (
1634 IN FORM_BROWSER_FORMSET *FormSet,
1635 IN FORM_BROWSER_FORM *Form,
1636 IN OUT FORM_BROWSER_STATEMENT *Question,
1637 IN GET_SET_QUESTION_VALUE_WITH SetValueTo
1638 )
1639 {
1640 EFI_STATUS Status;
1641 BOOLEAN Enabled;
1642 BOOLEAN Pending;
1643 UINT8 *Src;
1644 EFI_TIME EfiTime;
1645 UINTN BufferLen;
1646 UINTN StorageWidth;
1647 BROWSER_STORAGE *Storage;
1648 EFI_IFR_TYPE_VALUE *QuestionValue;
1649 CHAR16 *ConfigResp;
1650 CHAR16 *Progress;
1651 CHAR16 *Value;
1652 UINTN Length;
1653 BOOLEAN IsBufferStorage;
1654 BOOLEAN IsString;
1655 UINT8 *TemBuffer;
1656 CHAR16 *TemName;
1657 CHAR16 *TemString;
1658 UINTN Index;
1659 NAME_VALUE_NODE *Node;
1660
1661 Status = EFI_SUCCESS;
1662 Node = NULL;
1663
1664 if (SetValueTo >= GetSetValueWithMax) {
1665 return EFI_INVALID_PARAMETER;
1666 }
1667
1668 //
1669 // If Question value is provided by an Expression, then it is read only
1670 //
1671 if (Question->ValueExpression != NULL) {
1672 return Status;
1673 }
1674
1675 //
1676 // Before set question value, evaluate its write expression.
1677 //
1678 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1679 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
1680 if (EFI_ERROR (Status)) {
1681 return Status;
1682 }
1683 }
1684
1685 //
1686 // Question value is provided by RTC
1687 //
1688 Storage = Question->Storage;
1689 QuestionValue = &Question->HiiValue.Value;
1690 if (Storage == NULL) {
1691 //
1692 // It's a Question without storage, or RTC date/time
1693 //
1694 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1695 //
1696 // Date and time define the same Flags bit
1697 //
1698 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1699 case QF_DATE_STORAGE_TIME:
1700 Status = gRT->GetTime (&EfiTime, NULL);
1701 break;
1702
1703 case QF_DATE_STORAGE_WAKEUP:
1704 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1705 break;
1706
1707 case QF_DATE_STORAGE_NORMAL:
1708 default:
1709 //
1710 // For date/time without storage
1711 //
1712 return EFI_SUCCESS;
1713 }
1714
1715 if (EFI_ERROR (Status)) {
1716 return Status;
1717 }
1718
1719 if (Question->Operand == EFI_IFR_DATE_OP) {
1720 EfiTime.Year = QuestionValue->date.Year;
1721 EfiTime.Month = QuestionValue->date.Month;
1722 EfiTime.Day = QuestionValue->date.Day;
1723 } else {
1724 EfiTime.Hour = QuestionValue->time.Hour;
1725 EfiTime.Minute = QuestionValue->time.Minute;
1726 EfiTime.Second = QuestionValue->time.Second;
1727 }
1728
1729 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
1730 Status = gRT->SetTime (&EfiTime);
1731 } else {
1732 Status = gRT->SetWakeupTime (TRUE, &EfiTime);
1733 }
1734 }
1735
1736 return Status;
1737 }
1738
1739 //
1740 // Question value is provided by EFI variable
1741 //
1742 StorageWidth = Question->StorageWidth;
1743 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1744 if (Question->BufferValue != NULL) {
1745 Src = Question->BufferValue;
1746 } else {
1747 Src = (UINT8 *) QuestionValue;
1748 }
1749
1750 Status = gRT->SetVariable (
1751 Question->VariableName,
1752 &Storage->Guid,
1753 Storage->Attributes,
1754 StorageWidth,
1755 Src
1756 );
1757 return Status;
1758 }
1759
1760 //
1761 // Question Value is provided by Buffer Storage or NameValue Storage
1762 //
1763 if (Question->BufferValue != NULL) {
1764 Src = Question->BufferValue;
1765 } else {
1766 Src = (UINT8 *) &Question->HiiValue.Value;
1767 }
1768
1769 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1770 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1771 IsBufferStorage = TRUE;
1772 } else {
1773 IsBufferStorage = FALSE;
1774 }
1775 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1776
1777 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
1778 if (IsBufferStorage) {
1779 if (SetValueTo == GetSetValueWithEditBuffer) {
1780 //
1781 // Copy to storage edit buffer
1782 //
1783 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1784 } else if (SetValueTo == GetSetValueWithBuffer) {
1785 //
1786 // Copy to storage edit buffer
1787 //
1788 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1789 }
1790 } else {
1791 if (IsString) {
1792 //
1793 // Allocate enough string buffer.
1794 //
1795 Value = NULL;
1796 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
1797 Value = AllocateZeroPool (BufferLen);
1798 ASSERT (Value != NULL);
1799 //
1800 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1801 //
1802 TemName = (CHAR16 *) Src;
1803 TemString = Value;
1804 for (; *TemName != L'\0'; TemName++) {
1805 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1806 }
1807 } else {
1808 BufferLen = StorageWidth * 2 + 1;
1809 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
1810 ASSERT (Value != NULL);
1811 //
1812 // Convert Buffer to Hex String
1813 //
1814 TemBuffer = Src + StorageWidth - 1;
1815 TemString = Value;
1816 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1817 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1818 }
1819 }
1820
1821 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
1822 FreePool (Value);
1823 if (EFI_ERROR (Status)) {
1824 return Status;
1825 }
1826 }
1827 } else if (SetValueTo == GetSetValueWithHiiDriver) {
1828 //
1829 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
1830 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
1831 //
1832 if (IsBufferStorage) {
1833 Length = StrLen (Question->BlockName) + 7;
1834 } else {
1835 Length = StrLen (Question->VariableName) + 2;
1836 }
1837 if (!IsBufferStorage && IsString) {
1838 Length += (StrLen ((CHAR16 *) Src) * 4);
1839 } else {
1840 Length += (StorageWidth * 2);
1841 }
1842 ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
1843 ASSERT (ConfigResp != NULL);
1844
1845 StrCpy (ConfigResp, Storage->ConfigHdr);
1846 if (IsBufferStorage) {
1847 StrCat (ConfigResp, Question->BlockName);
1848 StrCat (ConfigResp, L"&VALUE=");
1849 } else {
1850 StrCat (ConfigResp, L"&");
1851 StrCat (ConfigResp, Question->VariableName);
1852 StrCat (ConfigResp, L"=");
1853 }
1854
1855 Value = ConfigResp + StrLen (ConfigResp);
1856
1857 if (!IsBufferStorage && IsString) {
1858 //
1859 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1860 //
1861 TemName = (CHAR16 *) Src;
1862 TemString = Value;
1863 for (; *TemName != L'\0'; TemName++) {
1864 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1865 }
1866 } else {
1867 //
1868 // Convert Buffer to Hex String
1869 //
1870 TemBuffer = Src + StorageWidth - 1;
1871 TemString = Value;
1872 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1873 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1874 }
1875 }
1876
1877 //
1878 // Convert to lower char.
1879 //
1880 for (TemString = Value; *Value != L'\0'; Value++) {
1881 if (*Value >= L'A' && *Value <= L'Z') {
1882 *Value = (CHAR16) (*Value - L'A' + L'a');
1883 }
1884 }
1885
1886 //
1887 // Submit Question Value to Configuration Driver
1888 //
1889 Status = mHiiConfigRouting->RouteConfig (
1890 mHiiConfigRouting,
1891 ConfigResp,
1892 &Progress
1893 );
1894 if (EFI_ERROR (Status)) {
1895 FreePool (ConfigResp);
1896 return Status;
1897 }
1898 FreePool (ConfigResp);
1899
1900 //
1901 // Sync storage, from editbuffer to buffer.
1902 //
1903 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1904 }
1905
1906 return Status;
1907 }
1908
1909
1910 /**
1911 Perform nosubmitif check for a Form.
1912
1913 @param FormSet FormSet data structure.
1914 @param Form Form data structure.
1915 @param Question The Question to be validated.
1916 @param Type Validation type: NoSubmit
1917
1918 @retval EFI_SUCCESS Form validation pass.
1919 @retval other Form validation failed.
1920
1921 **/
1922 EFI_STATUS
1923 ValidateQuestion (
1924 IN FORM_BROWSER_FORMSET *FormSet,
1925 IN FORM_BROWSER_FORM *Form,
1926 IN FORM_BROWSER_STATEMENT *Question,
1927 IN UINTN Type
1928 )
1929 {
1930 EFI_STATUS Status;
1931 LIST_ENTRY *Link;
1932 LIST_ENTRY *ListHead;
1933 EFI_STRING PopUp;
1934 FORM_EXPRESSION *Expression;
1935
1936 if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
1937 ListHead = &Question->NoSubmitListHead;
1938 } else {
1939 return EFI_UNSUPPORTED;
1940 }
1941
1942 Link = GetFirstNode (ListHead);
1943 while (!IsNull (ListHead, Link)) {
1944 Expression = FORM_EXPRESSION_FROM_LINK (Link);
1945
1946 //
1947 // Evaluate the expression
1948 //
1949 Status = EvaluateExpression (FormSet, Form, Expression);
1950 if (EFI_ERROR (Status)) {
1951 return Status;
1952 }
1953
1954 if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {
1955 //
1956 // Condition meet, show up error message
1957 //
1958 if (Expression->Error != 0) {
1959 PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
1960 if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
1961 gBrowserStatus = BROWSER_NO_SUBMIT_IF;
1962 gErrorInfo = PopUp;
1963 }
1964 }
1965
1966 return EFI_NOT_READY;
1967 }
1968
1969 Link = GetNextNode (ListHead, Link);
1970 }
1971
1972 return EFI_SUCCESS;
1973 }
1974
1975
1976 /**
1977 Perform NoSubmit check for each Form in FormSet.
1978
1979 @param FormSet FormSet data structure.
1980 @param CurrentForm Current input form data structure.
1981
1982 @retval EFI_SUCCESS Form validation pass.
1983 @retval other Form validation failed.
1984
1985 **/
1986 EFI_STATUS
1987 NoSubmitCheck (
1988 IN FORM_BROWSER_FORMSET *FormSet,
1989 IN FORM_BROWSER_FORM *CurrentForm
1990 )
1991 {
1992 EFI_STATUS Status;
1993 LIST_ENTRY *Link;
1994 FORM_BROWSER_STATEMENT *Question;
1995 FORM_BROWSER_FORM *Form;
1996 LIST_ENTRY *LinkForm;
1997
1998 LinkForm = GetFirstNode (&FormSet->FormListHead);
1999 while (!IsNull (&FormSet->FormListHead, LinkForm)) {
2000 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
2001 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
2002
2003 if (CurrentForm != NULL && CurrentForm != Form) {
2004 continue;
2005 }
2006
2007 Link = GetFirstNode (&Form->StatementListHead);
2008 while (!IsNull (&Form->StatementListHead, Link)) {
2009 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2010
2011 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
2012 if (EFI_ERROR (Status)) {
2013 return Status;
2014 }
2015
2016 Link = GetNextNode (&Form->StatementListHead, Link);
2017 }
2018 }
2019
2020 return EFI_SUCCESS;
2021 }
2022
2023 /**
2024 Fill storage's edit copy with settings requested from Configuration Driver.
2025
2026 @param FormSet FormSet data structure.
2027 @param Storage The storage which need to sync.
2028 @param ConfigRequest The config request string which used to sync storage.
2029 @param SyncOrRestore Sync the buffer to editbuffer or Restore the
2030 editbuffer to buffer
2031 if TRUE, copy the editbuffer to the buffer.
2032 if FALSE, copy the buffer to the editbuffer.
2033
2034 @retval EFI_SUCCESS The function completed successfully.
2035
2036 **/
2037 EFI_STATUS
2038 SynchronizeStorage (
2039 IN FORM_BROWSER_FORMSET *FormSet,
2040 OUT BROWSER_STORAGE *Storage,
2041 IN CHAR16 *ConfigRequest,
2042 IN BOOLEAN SyncOrRestore
2043 )
2044 {
2045 EFI_STATUS Status;
2046 EFI_STRING Progress;
2047 EFI_STRING Result;
2048 UINTN BufferSize;
2049 LIST_ENTRY *Link;
2050 NAME_VALUE_NODE *Node;
2051 UINT8 *Src;
2052 UINT8 *Dst;
2053
2054 Status = EFI_SUCCESS;
2055 Result = NULL;
2056
2057 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2058 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2059 BufferSize = Storage->Size;
2060
2061 if (SyncOrRestore) {
2062 Src = Storage->EditBuffer;
2063 Dst = Storage->Buffer;
2064 } else {
2065 Src = Storage->Buffer;
2066 Dst = Storage->EditBuffer;
2067 }
2068
2069 if (ConfigRequest != NULL) {
2070 Status = mHiiConfigRouting->BlockToConfig(
2071 mHiiConfigRouting,
2072 ConfigRequest,
2073 Src,
2074 BufferSize,
2075 &Result,
2076 &Progress
2077 );
2078 if (EFI_ERROR (Status)) {
2079 return Status;
2080 }
2081
2082 Status = mHiiConfigRouting->ConfigToBlock (
2083 mHiiConfigRouting,
2084 Result,
2085 Dst,
2086 &BufferSize,
2087 &Progress
2088 );
2089 if (Result != NULL) {
2090 FreePool (Result);
2091 }
2092 } else {
2093 CopyMem (Dst, Src, BufferSize);
2094 }
2095 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2096 Link = GetFirstNode (&Storage->NameValueListHead);
2097 while (!IsNull (&Storage->NameValueListHead, Link)) {
2098 Node = NAME_VALUE_NODE_FROM_LINK (Link);
2099
2100 if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
2101 (ConfigRequest == NULL)) {
2102 if (SyncOrRestore) {
2103 NewStringCpy (&Node->Value, Node->EditValue);
2104 } else {
2105 NewStringCpy (&Node->EditValue, Node->Value);
2106 }
2107 }
2108
2109 Link = GetNextNode (&Storage->NameValueListHead, Link);
2110 }
2111 }
2112
2113 return Status;
2114 }
2115
2116 /**
2117 When discard the question value, call the callback function with Changed type
2118 to inform the hii driver.
2119
2120 @param FormSet FormSet data structure.
2121 @param Form Form data structure.
2122
2123 **/
2124 VOID
2125 SendDiscardInfoToDriver (
2126 IN FORM_BROWSER_FORMSET *FormSet,
2127 IN FORM_BROWSER_FORM *Form
2128 )
2129 {
2130 LIST_ENTRY *Link;
2131 FORM_BROWSER_STATEMENT *Question;
2132 EFI_IFR_TYPE_VALUE *TypeValue;
2133 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2134
2135 if (FormSet->ConfigAccess == NULL) {
2136 return;
2137 }
2138
2139 Link = GetFirstNode (&Form->StatementListHead);
2140 while (!IsNull (&Form->StatementListHead, Link)) {
2141 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2142 Link = GetNextNode (&Form->StatementListHead, Link);
2143
2144 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
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
3001 Status = EFI_NOT_FOUND;
3002 StrValue = NULL;
3003
3004 //
3005 // Statement don't have storage, skip them
3006 //
3007 if (Question->QuestionId == 0) {
3008 return Status;
3009 }
3010
3011 //
3012 // There are Five ways to specify default value for a Question:
3013 // 1, use call back function (highest priority)
3014 // 2, use ExtractConfig function
3015 // 3, use nested EFI_IFR_DEFAULT
3016 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
3017 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
3018 //
3019 HiiValue = &Question->HiiValue;
3020
3021 //
3022 // Get Question defaut value from call back function.
3023 //
3024 ConfigAccess = FormSet->ConfigAccess;
3025 Action = GetDefaultIdForCallBack (DefaultId);
3026 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
3027 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
3028 Status = ConfigAccess->Callback (
3029 ConfigAccess,
3030 Action,
3031 Question->QuestionId,
3032 HiiValue->Type,
3033 &HiiValue->Value,
3034 &ActionRequest
3035 );
3036 if (!EFI_ERROR (Status)) {
3037 return Status;
3038 }
3039 }
3040
3041 //
3042 // Get default value from altcfg string.
3043 //
3044 if (ConfigAccess != NULL) {
3045 Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);
3046 if (!EFI_ERROR (Status)) {
3047 return Status;
3048 }
3049 }
3050
3051 //
3052 // EFI_IFR_DEFAULT has highest priority
3053 //
3054 if (!IsListEmpty (&Question->DefaultListHead)) {
3055 Link = GetFirstNode (&Question->DefaultListHead);
3056 while (!IsNull (&Question->DefaultListHead, Link)) {
3057 Default = QUESTION_DEFAULT_FROM_LINK (Link);
3058
3059 if (Default->DefaultId == DefaultId) {
3060 if (Default->ValueExpression != NULL) {
3061 //
3062 // Default is provided by an Expression, evaluate it
3063 //
3064 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
3065 if (EFI_ERROR (Status)) {
3066 return Status;
3067 }
3068
3069 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
3070 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
3071 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
3072 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
3073 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
3074 } else {
3075 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
3076 Question->HiiValue.BufferLen = Question->StorageWidth;
3077 }
3078 FreePool (Default->ValueExpression->Result.Buffer);
3079 }
3080 HiiValue->Type = Default->ValueExpression->Result.Type;
3081 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
3082 } else {
3083 //
3084 // Default value is embedded in EFI_IFR_DEFAULT
3085 //
3086 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
3087 }
3088
3089 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
3090 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
3091 if (StrValue == NULL) {
3092 return EFI_NOT_FOUND;
3093 }
3094 if (Question->StorageWidth > StrSize (StrValue)) {
3095 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
3096 } else {
3097 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
3098 }
3099 }
3100
3101 return EFI_SUCCESS;
3102 }
3103
3104 Link = GetNextNode (&Question->DefaultListHead, Link);
3105 }
3106 }
3107
3108 //
3109 // EFI_ONE_OF_OPTION
3110 //
3111 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
3112 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3113 //
3114 // OneOfOption could only provide Standard and Manufacturing default
3115 //
3116 Link = GetFirstNode (&Question->OptionListHead);
3117 while (!IsNull (&Question->OptionListHead, Link)) {
3118 Option = QUESTION_OPTION_FROM_LINK (Link);
3119 Link = GetNextNode (&Question->OptionListHead, Link);
3120
3121 if ((Option->SuppressExpression != NULL) &&
3122 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3123 continue;
3124 }
3125
3126 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
3127 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
3128 ) {
3129 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3130
3131 return EFI_SUCCESS;
3132 }
3133 }
3134 }
3135 }
3136
3137 //
3138 // EFI_IFR_CHECKBOX - lowest priority
3139 //
3140 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
3141 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3142 //
3143 // Checkbox could only provide Standard and Manufacturing default
3144 //
3145 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
3146 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
3147 ) {
3148 HiiValue->Value.b = TRUE;
3149 } else {
3150 HiiValue->Value.b = FALSE;
3151 }
3152
3153 return EFI_SUCCESS;
3154 }
3155 }
3156
3157 //
3158 // For Questions without default
3159 //
3160 Status = EFI_NOT_FOUND;
3161 switch (Question->Operand) {
3162 case EFI_IFR_NUMERIC_OP:
3163 //
3164 // Take minimum value as numeric default value
3165 //
3166 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
3167 HiiValue->Value.u64 = Question->Minimum;
3168 Status = EFI_SUCCESS;
3169 }
3170 break;
3171
3172 case EFI_IFR_ONE_OF_OP:
3173 //
3174 // Take first oneof option as oneof's default value
3175 //
3176 if (ValueToOption (Question, HiiValue) == NULL) {
3177 Link = GetFirstNode (&Question->OptionListHead);
3178 while (!IsNull (&Question->OptionListHead, Link)) {
3179 Option = QUESTION_OPTION_FROM_LINK (Link);
3180 Link = GetNextNode (&Question->OptionListHead, Link);
3181
3182 if ((Option->SuppressExpression != NULL) &&
3183 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3184 continue;
3185 }
3186
3187 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3188 Status = EFI_SUCCESS;
3189 break;
3190 }
3191 }
3192 break;
3193
3194 case EFI_IFR_ORDERED_LIST_OP:
3195 //
3196 // Take option sequence in IFR as ordered list's default value
3197 //
3198 Index = 0;
3199 Link = GetFirstNode (&Question->OptionListHead);
3200 while (!IsNull (&Question->OptionListHead, Link)) {
3201 Status = EFI_SUCCESS;
3202 Option = QUESTION_OPTION_FROM_LINK (Link);
3203 Link = GetNextNode (&Question->OptionListHead, Link);
3204
3205 if ((Option->SuppressExpression != NULL) &&
3206 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3207 continue;
3208 }
3209
3210 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
3211
3212 Index++;
3213 if (Index >= Question->MaxContainers) {
3214 break;
3215 }
3216 }
3217 break;
3218
3219 default:
3220 break;
3221 }
3222
3223 return Status;
3224 }
3225
3226
3227 /**
3228 Reset Questions to their initial value or default value in a Form, Formset or System.
3229
3230 GetDefaultValueScope parameter decides which questions will reset
3231 to its default value.
3232
3233 @param FormSet FormSet data structure.
3234 @param Form Form data structure.
3235 @param DefaultId The Class of the default.
3236 @param SettingScope Setting Scope for Default action.
3237 @param GetDefaultValueScope Get default value scope.
3238 @param Storage Get default value only for this storage.
3239 @param RetrieveValueFirst Whether call the retrieve call back to
3240 get the initial value before get default
3241 value.
3242
3243 @retval EFI_SUCCESS The function completed successfully.
3244 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3245
3246 **/
3247 EFI_STATUS
3248 ExtractDefault (
3249 IN FORM_BROWSER_FORMSET *FormSet,
3250 IN FORM_BROWSER_FORM *Form,
3251 IN UINT16 DefaultId,
3252 IN BROWSER_SETTING_SCOPE SettingScope,
3253 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
3254 IN BROWSER_STORAGE *Storage OPTIONAL,
3255 IN BOOLEAN RetrieveValueFirst
3256 )
3257 {
3258 EFI_STATUS Status;
3259 LIST_ENTRY *FormLink;
3260 LIST_ENTRY *Link;
3261 FORM_BROWSER_STATEMENT *Question;
3262 FORM_BROWSER_FORMSET *LocalFormSet;
3263 FORM_BROWSER_FORMSET *OldFormSet;
3264
3265 Status = EFI_SUCCESS;
3266
3267 //
3268 // Check the supported setting level.
3269 //
3270 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
3271 return EFI_UNSUPPORTED;
3272 }
3273
3274 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
3275 return EFI_UNSUPPORTED;
3276 }
3277
3278 if (SettingScope == FormLevel) {
3279 //
3280 // Extract Form default
3281 //
3282 Link = GetFirstNode (&Form->StatementListHead);
3283 while (!IsNull (&Form->StatementListHead, Link)) {
3284 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3285 Link = GetNextNode (&Form->StatementListHead, Link);
3286
3287 //
3288 // If get default value only for this storage, check the storage first.
3289 //
3290 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
3291 continue;
3292 }
3293
3294 //
3295 // If get default value only for no storage question, just skip the question which has storage.
3296 //
3297 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
3298 continue;
3299 }
3300
3301 //
3302 // If Question is disabled, don't reset it to default
3303 //
3304 if (Question->Expression != NULL) {
3305 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
3306 continue;
3307 }
3308 }
3309
3310 if (RetrieveValueFirst) {
3311 //
3312 // Call the Retrieve call back to get the initial question value.
3313 //
3314 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);
3315 }
3316
3317 //
3318 // If not request to get the initial value or get initial value fail, then get default value.
3319 //
3320 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
3321 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
3322 if (EFI_ERROR (Status)) {
3323 continue;
3324 }
3325 }
3326
3327 //
3328 // Synchronize Buffer storage's Edit buffer
3329 //
3330 if ((Question->Storage != NULL) &&
3331 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
3332 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3333 }
3334 }
3335 } else if (SettingScope == FormSetLevel) {
3336 FormLink = GetFirstNode (&FormSet->FormListHead);
3337 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3338 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3339 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3340 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3341 }
3342 } else if (SettingScope == SystemLevel) {
3343 //
3344 // Preload all Hii formset.
3345 //
3346 LoadAllHiiFormset();
3347
3348 OldFormSet = mSystemLevelFormSet;
3349
3350 //
3351 // Set Default Value for each FormSet in the maintain list.
3352 //
3353 Link = GetFirstNode (&gBrowserFormSetList);
3354 while (!IsNull (&gBrowserFormSetList, Link)) {
3355 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3356 Link = GetNextNode (&gBrowserFormSetList, Link);
3357 if (!ValidateFormSet(LocalFormSet)) {
3358 continue;
3359 }
3360
3361 mSystemLevelFormSet = LocalFormSet;
3362
3363 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3364 }
3365
3366 mSystemLevelFormSet = OldFormSet;
3367 }
3368
3369 return EFI_SUCCESS;
3370 }
3371
3372
3373 /**
3374 Validate whether this question's value has changed.
3375
3376 @param FormSet FormSet data structure.
3377 @param Form Form data structure.
3378 @param Question Question to be initialized.
3379 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
3380
3381 @retval TRUE Question's value has changed.
3382 @retval FALSE Question's value has not changed
3383
3384 **/
3385 BOOLEAN
3386 IsQuestionValueChanged (
3387 IN FORM_BROWSER_FORMSET *FormSet,
3388 IN FORM_BROWSER_FORM *Form,
3389 IN OUT FORM_BROWSER_STATEMENT *Question,
3390 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
3391 )
3392 {
3393 EFI_HII_VALUE BackUpValue;
3394 CHAR8 *BackUpBuffer;
3395 EFI_STATUS Status;
3396 BOOLEAN ValueChanged;
3397 UINTN BufferWidth;
3398
3399 //
3400 // For quetion without storage, always mark it as data not changed.
3401 //
3402 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
3403 return FALSE;
3404 }
3405
3406 BackUpBuffer = NULL;
3407 ValueChanged = FALSE;
3408
3409 switch (Question->Operand) {
3410 case EFI_IFR_ORDERED_LIST_OP:
3411 BufferWidth = Question->StorageWidth;
3412 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
3413 ASSERT (BackUpBuffer != NULL);
3414 break;
3415
3416 case EFI_IFR_STRING_OP:
3417 case EFI_IFR_PASSWORD_OP:
3418 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
3419 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
3420 ASSERT (BackUpBuffer != NULL);
3421 break;
3422
3423 default:
3424 BufferWidth = 0;
3425 break;
3426 }
3427 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
3428
3429 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
3430 ASSERT_EFI_ERROR(Status);
3431
3432 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
3433 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
3434 ValueChanged = TRUE;
3435 }
3436
3437 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
3438 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
3439
3440 if (BackUpBuffer != NULL) {
3441 FreePool (BackUpBuffer);
3442 }
3443
3444 Question->ValueChanged = ValueChanged;
3445
3446 return ValueChanged;
3447 }
3448
3449 /**
3450 Initialize Question's Edit copy from Storage.
3451
3452 @param Selection Selection contains the information about
3453 the Selection, form and formset to be displayed.
3454 Selection action may be updated in retrieve callback.
3455 If Selection is NULL, only initialize Question value.
3456 @param FormSet FormSet data structure.
3457 @param Form Form data structure.
3458
3459 @retval EFI_SUCCESS The function completed successfully.
3460
3461 **/
3462 EFI_STATUS
3463 LoadFormConfig (
3464 IN OUT UI_MENU_SELECTION *Selection,
3465 IN FORM_BROWSER_FORMSET *FormSet,
3466 IN FORM_BROWSER_FORM *Form
3467 )
3468 {
3469 EFI_STATUS Status;
3470 LIST_ENTRY *Link;
3471 FORM_BROWSER_STATEMENT *Question;
3472 UINT8 *BufferValue;
3473 UINTN StorageWidth;
3474
3475 Link = GetFirstNode (&Form->StatementListHead);
3476 while (!IsNull (&Form->StatementListHead, Link)) {
3477 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3478
3479 //
3480 // Initialize local copy of Value for each Question
3481 //
3482 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
3483 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
3484 } else {
3485 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3486 }
3487 if (EFI_ERROR (Status)) {
3488 return Status;
3489 }
3490
3491 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
3492 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
3493 }
3494
3495 //
3496 // Call the Retrieve call back function for all questions.
3497 //
3498 if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&
3499 ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
3500 !gFinishRetrieveCall) {
3501 //
3502 // Check QuestionValue does exist.
3503 //
3504 StorageWidth = Question->StorageWidth;
3505 if (Question->BufferValue != NULL) {
3506 BufferValue = Question->BufferValue;
3507 } else {
3508 BufferValue = (UINT8 *) &Question->HiiValue.Value;
3509 }
3510
3511 //
3512 // For efivarstore storage, initial question value first.
3513 //
3514 if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
3515 Status = gRT->GetVariable (
3516 Question->VariableName,
3517 &Question->Storage->Guid,
3518 NULL,
3519 &StorageWidth,
3520 BufferValue
3521 );
3522 }
3523
3524 Status = ProcessCallBackFunction(Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
3525 }
3526
3527 Link = GetNextNode (&Form->StatementListHead, Link);
3528 }
3529
3530 return EFI_SUCCESS;
3531 }
3532
3533 /**
3534 Initialize Question's Edit copy from Storage for the whole Formset.
3535
3536 @param Selection Selection contains the information about
3537 the Selection, form and formset to be displayed.
3538 Selection action may be updated in retrieve callback.
3539 If Selection is NULL, only initialize Question value.
3540 @param FormSet FormSet data structure.
3541
3542 @retval EFI_SUCCESS The function completed successfully.
3543
3544 **/
3545 EFI_STATUS
3546 LoadFormSetConfig (
3547 IN OUT UI_MENU_SELECTION *Selection,
3548 IN FORM_BROWSER_FORMSET *FormSet
3549 )
3550 {
3551 EFI_STATUS Status;
3552 LIST_ENTRY *Link;
3553 FORM_BROWSER_FORM *Form;
3554
3555 Link = GetFirstNode (&FormSet->FormListHead);
3556 while (!IsNull (&FormSet->FormListHead, Link)) {
3557 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3558
3559 //
3560 // Initialize local copy of Value for each Form
3561 //
3562 Status = LoadFormConfig (Selection, FormSet, Form);
3563 if (EFI_ERROR (Status)) {
3564 return Status;
3565 }
3566
3567 Link = GetNextNode (&FormSet->FormListHead, Link);
3568 }
3569
3570 //
3571 // Finished question initialization.
3572 //
3573 FormSet->QuestionInited = TRUE;
3574
3575 return EFI_SUCCESS;
3576 }
3577
3578 /**
3579 Remove the Request element from the Config Request.
3580
3581 @param Storage Pointer to the browser storage.
3582 @param RequestElement The pointer to the Request element.
3583
3584 **/
3585 VOID
3586 RemoveElement (
3587 IN OUT BROWSER_STORAGE *Storage,
3588 IN CHAR16 *RequestElement
3589 )
3590 {
3591 CHAR16 *NewStr;
3592 CHAR16 *DestStr;
3593
3594 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
3595
3596 NewStr = StrStr (Storage->ConfigRequest, RequestElement);
3597
3598 if (NewStr == NULL) {
3599 return;
3600 }
3601
3602 //
3603 // Remove this element from this ConfigRequest.
3604 //
3605 DestStr = NewStr;
3606 NewStr += StrLen (RequestElement);
3607 CopyMem (DestStr, NewStr, StrSize (NewStr));
3608
3609 Storage->SpareStrLen += StrLen (RequestElement);
3610 }
3611
3612 /**
3613 Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
3614
3615 @param Storage Pointer to the browser storage.
3616 @param ConfigRequest The pointer to the Request element.
3617
3618 **/
3619 VOID
3620 RemoveConfigRequest (
3621 BROWSER_STORAGE *Storage,
3622 CHAR16 *ConfigRequest
3623 )
3624 {
3625 CHAR16 *RequestElement;
3626 CHAR16 *NextRequestElement;
3627 CHAR16 *SearchKey;
3628
3629 //
3630 // No request element in it, just return.
3631 //
3632 if (ConfigRequest == NULL) {
3633 return;
3634 }
3635
3636 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3637 //
3638 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
3639 //
3640 SearchKey = L"&";
3641 } else {
3642 //
3643 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
3644 //
3645 SearchKey = L"&OFFSET";
3646 }
3647
3648 //
3649 // Find SearchKey storage
3650 //
3651 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3652 RequestElement = StrStr (ConfigRequest, L"PATH");
3653 ASSERT (RequestElement != NULL);
3654 RequestElement = StrStr (RequestElement, SearchKey);
3655 } else {
3656 RequestElement = StrStr (ConfigRequest, SearchKey);
3657 }
3658
3659 while (RequestElement != NULL) {
3660 //
3661 // +1 to avoid find header itself.
3662 //
3663 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
3664
3665 //
3666 // The last Request element in configRequest string.
3667 //
3668 if (NextRequestElement != NULL) {
3669 //
3670 // Replace "&" with '\0'.
3671 //
3672 *NextRequestElement = L'\0';
3673 }
3674
3675 RemoveElement (Storage, RequestElement);
3676
3677 if (NextRequestElement != NULL) {
3678 //
3679 // Restore '&' with '\0' for later used.
3680 //
3681 *NextRequestElement = L'&';
3682 }
3683
3684 RequestElement = NextRequestElement;
3685 }
3686
3687 //
3688 // If no request element remain, just remove the ConfigRequest string.
3689 //
3690 if (StrCmp (Storage->ConfigRequest, Storage->ConfigHdr) == 0) {
3691 FreePool (Storage->ConfigRequest);
3692 Storage->ConfigRequest = NULL;
3693 Storage->SpareStrLen = 0;
3694 }
3695 }
3696
3697 /**
3698 Base on the current formset info, clean the ConfigRequest string in browser storage.
3699
3700 @param FormSet Pointer of the FormSet
3701
3702 **/
3703 VOID
3704 CleanBrowserStorage (
3705 IN OUT FORM_BROWSER_FORMSET *FormSet
3706 )
3707 {
3708 LIST_ENTRY *Link;
3709 FORMSET_STORAGE *Storage;
3710 CHAR16 *ConfigRequest;
3711
3712 Link = GetFirstNode (&FormSet->StorageListHead);
3713 while (!IsNull (&FormSet->StorageListHead, Link)) {
3714 Storage = FORMSET_STORAGE_FROM_LINK (Link);
3715 Link = GetNextNode (&FormSet->StorageListHead, Link);
3716
3717 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
3718 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
3719 continue;
3720 }
3721
3722 ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements;
3723 RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest);
3724 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
3725 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3726 if (Storage->BrowserStorage->ConfigRequest != NULL) {
3727 FreePool (Storage->BrowserStorage->ConfigRequest);
3728 Storage->BrowserStorage->ConfigRequest = NULL;
3729 }
3730 Storage->BrowserStorage->Initialized = FALSE;
3731 }
3732 }
3733 }
3734
3735 /**
3736 Check whether current element in the ConfigReqeust string.
3737
3738 @param BrowserStorage Storage which includes ConfigReqeust.
3739 @param RequestElement New element need to check.
3740
3741 @retval TRUE The Element is in the ConfigReqeust string.
3742 @retval FALSE The Element not in the configReqeust String.
3743
3744 **/
3745 BOOLEAN
3746 ElementValidation (
3747 BROWSER_STORAGE *BrowserStorage,
3748 CHAR16 *RequestElement
3749 )
3750 {
3751 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
3752 }
3753
3754 /**
3755 Append the Request element to the Config Request.
3756
3757 @param ConfigRequest Current ConfigRequest info.
3758 @param SpareStrLen Current remain free buffer for config reqeust.
3759 @param RequestElement New Request element.
3760
3761 **/
3762 VOID
3763 AppendConfigRequest (
3764 IN OUT CHAR16 **ConfigRequest,
3765 IN OUT UINTN *SpareStrLen,
3766 IN CHAR16 *RequestElement
3767 )
3768 {
3769 CHAR16 *NewStr;
3770 UINTN StringSize;
3771 UINTN StrLength;
3772
3773 StrLength = StrLen (RequestElement);
3774
3775 //
3776 // Append <RequestElement> to <ConfigRequest>
3777 //
3778 if (StrLength > *SpareStrLen) {
3779 //
3780 // Old String buffer is not sufficient for RequestElement, allocate a new one
3781 //
3782 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
3783 NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16));
3784 ASSERT (NewStr != NULL);
3785
3786 if (*ConfigRequest != NULL) {
3787 CopyMem (NewStr, *ConfigRequest, StringSize);
3788 FreePool (*ConfigRequest);
3789 }
3790 *ConfigRequest = NewStr;
3791 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
3792 }
3793
3794 StrCat (*ConfigRequest, RequestElement);
3795 *SpareStrLen -= StrLength;
3796 }
3797
3798 /**
3799 Adjust the config request info, remove the request elements which already in AllConfigRequest string.
3800
3801 @param Storage Form set Storage.
3802
3803 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
3804 @retval FALSE All elements covered by current used elements.
3805
3806 **/
3807 BOOLEAN
3808 ConfigRequestAdjust (
3809 IN FORMSET_STORAGE *Storage
3810 )
3811 {
3812 CHAR16 *RequestElement;
3813 CHAR16 *NextRequestElement;
3814 CHAR16 *RetBuf;
3815 UINTN SpareBufLen;
3816 CHAR16 *SearchKey;
3817 BOOLEAN RetVal;
3818
3819 SpareBufLen = 0;
3820 RetBuf = NULL;
3821 RetVal = FALSE;
3822
3823 if (Storage->BrowserStorage->ConfigRequest == NULL) {
3824 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
3825 if (Storage->ConfigElements != NULL) {
3826 FreePool (Storage->ConfigElements);
3827 }
3828 Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
3829 return TRUE;
3830 }
3831
3832 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3833 //
3834 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
3835 //
3836 SearchKey = L"&";
3837 } else {
3838 //
3839 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
3840 //
3841 SearchKey = L"&OFFSET";
3842 }
3843
3844 //
3845 // Prepare the config header.
3846 //
3847 RetBuf = AllocateCopyPool(StrSize (Storage->BrowserStorage->ConfigHdr), Storage->BrowserStorage->ConfigHdr);
3848 ASSERT (RetBuf != NULL);
3849
3850 //
3851 // Find SearchKey storage
3852 //
3853 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3854 RequestElement = StrStr (Storage->ConfigRequest, L"PATH");
3855 ASSERT (RequestElement != NULL);
3856 RequestElement = StrStr (RequestElement, SearchKey);
3857 } else {
3858 RequestElement = StrStr (Storage->ConfigRequest, SearchKey);
3859 }
3860
3861 while (RequestElement != NULL) {
3862 //
3863 // +1 to avoid find header itself.
3864 //
3865 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
3866
3867 //
3868 // The last Request element in configRequest string.
3869 //
3870 if (NextRequestElement != NULL) {
3871 //
3872 // Replace "&" with '\0'.
3873 //
3874 *NextRequestElement = L'\0';
3875 }
3876
3877 if (!ElementValidation (Storage->BrowserStorage, RequestElement)) {
3878 //
3879 // Add this element to the Storage->BrowserStorage->AllRequestElement.
3880 //
3881 AppendConfigRequest(&Storage->BrowserStorage->ConfigRequest, &Storage->BrowserStorage->SpareStrLen, RequestElement);
3882 AppendConfigRequest (&RetBuf, &SpareBufLen, RequestElement);
3883 RetVal = TRUE;
3884 }
3885
3886 if (NextRequestElement != NULL) {
3887 //
3888 // Restore '&' with '\0' for later used.
3889 //
3890 *NextRequestElement = L'&';
3891 }
3892
3893 RequestElement = NextRequestElement;
3894 }
3895
3896 if (RetVal) {
3897 if (Storage->ConfigElements != NULL) {
3898 FreePool (Storage->ConfigElements);
3899 }
3900 Storage->ConfigElements = RetBuf;
3901 } else {
3902 FreePool (RetBuf);
3903 }
3904
3905 return RetVal;
3906 }
3907
3908 /**
3909
3910 Base on ConfigRequest info to get default value for current formset.
3911
3912 ConfigRequest info include the info about which questions in current formset need to
3913 get default value. This function only get these questions default value.
3914
3915 @param FormSet FormSet data structure.
3916 @param Storage Storage need to update value.
3917 @param ConfigRequest The config request string.
3918
3919 **/
3920 VOID
3921 GetDefaultForFormset (
3922 IN FORM_BROWSER_FORMSET *FormSet,
3923 IN BROWSER_STORAGE *Storage,
3924 IN CHAR16 *ConfigRequest
3925 )
3926 {
3927 UINT8 *BackUpBuf;
3928 UINTN BufferSize;
3929 LIST_ENTRY BackUpList;
3930 NAME_VALUE_NODE *Node;
3931 LIST_ENTRY *Link;
3932 LIST_ENTRY *NodeLink;
3933 NAME_VALUE_NODE *TmpNode;
3934 EFI_STATUS Status;
3935 EFI_STRING Progress;
3936 EFI_STRING Result;
3937
3938 BackUpBuf = NULL;
3939 InitializeListHead(&BackUpList);
3940
3941 //
3942 // Back update the edit buffer.
3943 //
3944 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
3945 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
3946 BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);
3947 ASSERT (BackUpBuf != NULL);
3948 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3949 Link = GetFirstNode (&Storage->NameValueListHead);
3950 while (!IsNull (&Storage->NameValueListHead, Link)) {
3951 Node = NAME_VALUE_NODE_FROM_LINK (Link);
3952 Link = GetNextNode (&Storage->NameValueListHead, Link);
3953
3954 //
3955 // Only back Node belong to this formset.
3956 //
3957 if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {
3958 continue;
3959 }
3960
3961 TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);
3962 TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);
3963 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
3964
3965 InsertTailList(&BackUpList, &TmpNode->Link);
3966 }
3967 }
3968
3969 //
3970 // Get default value.
3971 //
3972 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);
3973
3974 //
3975 // Update the question value based on the input ConfigRequest.
3976 //
3977 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
3978 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
3979 ASSERT (BackUpBuf != NULL);
3980 BufferSize = Storage->Size;
3981 Status = mHiiConfigRouting->BlockToConfig(
3982 mHiiConfigRouting,
3983 ConfigRequest,
3984 Storage->EditBuffer,
3985 BufferSize,
3986 &Result,
3987 &Progress
3988 );
3989 ASSERT_EFI_ERROR (Status);
3990
3991 Status = mHiiConfigRouting->ConfigToBlock (
3992 mHiiConfigRouting,
3993 Result,
3994 BackUpBuf,
3995 &BufferSize,
3996 &Progress
3997 );
3998 ASSERT_EFI_ERROR (Status);
3999
4000 if (Result != NULL) {
4001 FreePool (Result);
4002 }
4003
4004 CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);
4005 FreePool (BackUpBuf);
4006 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4007 //
4008 // Update question value, only element in ConfigReqeust will be update.
4009 //
4010 Link = GetFirstNode (&BackUpList);
4011 while (!IsNull (&BackUpList, Link)) {
4012 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4013 Link = GetNextNode (&BackUpList, Link);
4014
4015 if (StrStr (ConfigRequest, Node->Name) != NULL) {
4016 continue;
4017 }
4018
4019 NodeLink = GetFirstNode (&Storage->NameValueListHead);
4020 while (!IsNull (&Storage->NameValueListHead, NodeLink)) {
4021 TmpNode = NAME_VALUE_NODE_FROM_LINK (NodeLink);
4022 NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);
4023
4024 if (StrCmp (Node->Name, TmpNode->Name) != 0) {
4025 continue;
4026 }
4027
4028 FreePool (TmpNode->EditValue);
4029 TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);
4030
4031 RemoveEntryList (&Node->Link);
4032 FreePool (Node->EditValue);
4033 FreePool (Node->Name);
4034 FreePool (Node);
4035 }
4036 }
4037
4038 //
4039 // Restore the Name/Value node.
4040 //
4041 Link = GetFirstNode (&BackUpList);
4042 while (!IsNull (&BackUpList, Link)) {
4043 Node = NAME_VALUE_NODE_FROM_LINK (Link);
4044 Link = GetNextNode (&BackUpList, Link);
4045
4046 //
4047 // Free this node.
4048 //
4049 RemoveEntryList (&Node->Link);
4050 FreePool (Node->EditValue);
4051 FreePool (Node->Name);
4052 FreePool (Node);
4053 }
4054 }
4055 }
4056
4057 /**
4058 Fill storage's edit copy with settings requested from Configuration Driver.
4059
4060 @param FormSet FormSet data structure.
4061 @param Storage Buffer Storage.
4062
4063 **/
4064 VOID
4065 LoadStorage (
4066 IN FORM_BROWSER_FORMSET *FormSet,
4067 IN FORMSET_STORAGE *Storage
4068 )
4069 {
4070 EFI_STATUS Status;
4071 EFI_STRING Progress;
4072 EFI_STRING Result;
4073 CHAR16 *StrPtr;
4074 EFI_STRING ConfigRequest;
4075 UINTN StrLen;
4076
4077 ConfigRequest = NULL;
4078
4079 switch (Storage->BrowserStorage->Type) {
4080 case EFI_HII_VARSTORE_EFI_VARIABLE:
4081 return;
4082
4083 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
4084 if (Storage->BrowserStorage->ConfigRequest != NULL) {
4085 ConfigRequestAdjust(Storage);
4086 return;
4087 }
4088 break;
4089
4090 case EFI_HII_VARSTORE_BUFFER:
4091 case EFI_HII_VARSTORE_NAME_VALUE:
4092 //
4093 // Skip if there is no RequestElement.
4094 //
4095 if (Storage->ElementCount == 0) {
4096 return;
4097 }
4098
4099 //
4100 // Just update the ConfigRequest, if storage already initialized.
4101 //
4102 if (Storage->BrowserStorage->Initialized) {
4103 ConfigRequestAdjust(Storage);
4104 return;
4105 }
4106
4107 Storage->BrowserStorage->Initialized = TRUE;
4108 break;
4109
4110 default:
4111 return;
4112 }
4113
4114 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
4115 //
4116 // Create the config request string to get all fields for this storage.
4117 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
4118 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
4119 //
4120 StrLen = StrSize (Storage->BrowserStorage->ConfigHdr) + 20 * sizeof (CHAR16);
4121 ConfigRequest = AllocateZeroPool (StrLen);
4122 ASSERT (ConfigRequest != NULL);
4123 UnicodeSPrint (
4124 ConfigRequest,
4125 StrLen,
4126 L"%s&OFFSET=0&WIDTH=%04x",
4127 Storage->BrowserStorage->ConfigHdr,
4128 Storage->BrowserStorage->Size);
4129 } else {
4130 ConfigRequest = Storage->ConfigRequest;
4131 }
4132
4133 //
4134 // Request current settings from Configuration Driver
4135 //
4136 Status = mHiiConfigRouting->ExtractConfig (
4137 mHiiConfigRouting,
4138 ConfigRequest,
4139 &Progress,
4140 &Result
4141 );
4142
4143 //
4144 // If get value fail, extract default from IFR binary
4145 //
4146 if (EFI_ERROR (Status)) {
4147 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);
4148 } else {
4149 //
4150 // Convert Result from <ConfigAltResp> to <ConfigResp>
4151 //
4152 StrPtr = StrStr (Result, L"&GUID=");
4153 if (StrPtr != NULL) {
4154 *StrPtr = L'\0';
4155 }
4156
4157 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
4158 FreePool (Result);
4159 }
4160
4161 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
4162
4163 //
4164 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
4165 //
4166 SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE);
4167
4168 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
4169 if (ConfigRequest != NULL) {
4170 FreePool (ConfigRequest);
4171 }
4172 }
4173 }
4174
4175 /**
4176 Get Value changed status from old question.
4177
4178 @param NewFormSet FormSet data structure.
4179 @param OldQuestion Old question which has value changed.
4180
4181 **/
4182 VOID
4183 SyncStatusForQuestion (
4184 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
4185 IN FORM_BROWSER_STATEMENT *OldQuestion
4186 )
4187 {
4188 LIST_ENTRY *Link;
4189 LIST_ENTRY *QuestionLink;
4190 FORM_BROWSER_FORM *Form;
4191 FORM_BROWSER_STATEMENT *Question;
4192
4193 //
4194 // For each form in one formset.
4195 //
4196 Link = GetFirstNode (&NewFormSet->FormListHead);
4197 while (!IsNull (&NewFormSet->FormListHead, Link)) {
4198 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4199 Link = GetNextNode (&NewFormSet->FormListHead, Link);
4200
4201 //
4202 // for each question in one form.
4203 //
4204 QuestionLink = GetFirstNode (&Form->StatementListHead);
4205 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
4206 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
4207 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
4208
4209 if (Question->QuestionId == OldQuestion->QuestionId) {
4210 Question->ValueChanged = TRUE;
4211 return;
4212 }
4213 }
4214 }
4215 }
4216
4217 /**
4218 Get Value changed status from old formset.
4219
4220 @param NewFormSet FormSet data structure.
4221 @param OldFormSet FormSet data structure.
4222
4223 **/
4224 VOID
4225 SyncStatusForFormSet (
4226 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
4227 IN FORM_BROWSER_FORMSET *OldFormSet
4228 )
4229 {
4230 LIST_ENTRY *Link;
4231 LIST_ENTRY *QuestionLink;
4232 FORM_BROWSER_FORM *Form;
4233 FORM_BROWSER_STATEMENT *Question;
4234
4235 //
4236 // For each form in one formset.
4237 //
4238 Link = GetFirstNode (&OldFormSet->FormListHead);
4239 while (!IsNull (&OldFormSet->FormListHead, Link)) {
4240 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
4241 Link = GetNextNode (&OldFormSet->FormListHead, Link);
4242
4243 //
4244 // for each question in one form.
4245 //
4246 QuestionLink = GetFirstNode (&Form->StatementListHead);
4247 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
4248 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
4249 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
4250
4251 if (!Question->ValueChanged) {
4252 continue;
4253 }
4254
4255 //
4256 // Find the same question in new formset and update the value changed flag.
4257 //
4258 SyncStatusForQuestion (NewFormSet, Question);
4259 }
4260 }
4261 }
4262
4263 /**
4264 Get current setting of Questions.
4265
4266 @param FormSet FormSet data structure.
4267
4268 **/
4269 VOID
4270 InitializeCurrentSetting (
4271 IN OUT FORM_BROWSER_FORMSET *FormSet
4272 )
4273 {
4274 LIST_ENTRY *Link;
4275 FORMSET_STORAGE *Storage;
4276 FORM_BROWSER_FORMSET *OldFormSet;
4277
4278 //
4279 // Try to find pre FormSet in the maintain backup list.
4280 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
4281 //
4282 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
4283 if (OldFormSet != NULL) {
4284 SyncStatusForFormSet (FormSet, OldFormSet);
4285 RemoveEntryList (&OldFormSet->Link);
4286 DestroyFormSet (OldFormSet);
4287 }
4288 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
4289
4290 //
4291 // Extract default from IFR binary for no storage questions.
4292 //
4293 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);
4294
4295 //
4296 // Request current settings from Configuration Driver
4297 //
4298 Link = GetFirstNode (&FormSet->StorageListHead);
4299 while (!IsNull (&FormSet->StorageListHead, Link)) {
4300 Storage = FORMSET_STORAGE_FROM_LINK (Link);
4301
4302 LoadStorage (FormSet, Storage);
4303
4304 Link = GetNextNode (&FormSet->StorageListHead, Link);
4305 }
4306 }
4307
4308
4309 /**
4310 Fetch the Ifr binary data of a FormSet.
4311
4312 @param Handle PackageList Handle
4313 @param FormSetGuid On input, GUID or class GUID of a formset. If not
4314 specified (NULL or zero GUID), take the first
4315 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
4316 found in package list.
4317 On output, GUID of the formset found(if not NULL).
4318 @param BinaryLength The length of the FormSet IFR binary.
4319 @param BinaryData The buffer designed to receive the FormSet.
4320
4321 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
4322 BufferLength was updated.
4323 @retval EFI_INVALID_PARAMETER The handle is unknown.
4324 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
4325 be found with the requested FormId.
4326
4327 **/
4328 EFI_STATUS
4329 GetIfrBinaryData (
4330 IN EFI_HII_HANDLE Handle,
4331 IN OUT EFI_GUID *FormSetGuid,
4332 OUT UINTN *BinaryLength,
4333 OUT UINT8 **BinaryData
4334 )
4335 {
4336 EFI_STATUS Status;
4337 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
4338 UINTN BufferSize;
4339 UINT8 *Package;
4340 UINT8 *OpCodeData;
4341 UINT32 Offset;
4342 UINT32 Offset2;
4343 UINT32 PackageListLength;
4344 EFI_HII_PACKAGE_HEADER PackageHeader;
4345 UINT8 Index;
4346 UINT8 NumberOfClassGuid;
4347 BOOLEAN ClassGuidMatch;
4348 EFI_GUID *ClassGuid;
4349 EFI_GUID *ComparingGuid;
4350
4351 OpCodeData = NULL;
4352 Package = NULL;
4353 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
4354
4355 //
4356 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
4357 //
4358 if (FormSetGuid == NULL) {
4359 ComparingGuid = &gZeroGuid;
4360 } else {
4361 ComparingGuid = FormSetGuid;
4362 }
4363
4364 //
4365 // Get HII PackageList
4366 //
4367 BufferSize = 0;
4368 HiiPackageList = NULL;
4369 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
4370 if (Status == EFI_BUFFER_TOO_SMALL) {
4371 HiiPackageList = AllocatePool (BufferSize);
4372 ASSERT (HiiPackageList != NULL);
4373
4374 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
4375 }
4376 if (EFI_ERROR (Status)) {
4377 return Status;
4378 }
4379 ASSERT (HiiPackageList != NULL);
4380
4381 //
4382 // Get Form package from this HII package List
4383 //
4384 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
4385 Offset2 = 0;
4386 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
4387
4388 ClassGuidMatch = FALSE;
4389 while (Offset < PackageListLength) {
4390 Package = ((UINT8 *) HiiPackageList) + Offset;
4391 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4392
4393 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
4394 //
4395 // Search FormSet in this Form Package
4396 //
4397 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
4398 while (Offset2 < PackageHeader.Length) {
4399 OpCodeData = Package + Offset2;
4400
4401 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
4402 //
4403 // Try to compare against formset GUID
4404 //
4405 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
4406 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
4407 break;
4408 }
4409
4410 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
4411 //
4412 // Try to compare against formset class GUID
4413 //
4414 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
4415 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
4416 for (Index = 0; Index < NumberOfClassGuid; Index++) {
4417 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
4418 ClassGuidMatch = TRUE;
4419 break;
4420 }
4421 }
4422 if (ClassGuidMatch) {
4423 break;
4424 }
4425 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
4426 ClassGuidMatch = TRUE;
4427 break;
4428 }
4429 }
4430
4431 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
4432 }
4433
4434 if (Offset2 < PackageHeader.Length) {
4435 //
4436 // Target formset found
4437 //
4438 break;
4439 }
4440 }
4441
4442 Offset += PackageHeader.Length;
4443 }
4444
4445 if (Offset >= PackageListLength) {
4446 //
4447 // Form package not found in this Package List
4448 //
4449 FreePool (HiiPackageList);
4450 return EFI_NOT_FOUND;
4451 }
4452
4453 if (FormSetGuid != NULL) {
4454 //
4455 // Return the FormSet GUID
4456 //
4457 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
4458 }
4459
4460 //
4461 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
4462 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
4463 // of the Form Package.
4464 //
4465 *BinaryLength = PackageHeader.Length - Offset2;
4466 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
4467
4468 FreePool (HiiPackageList);
4469
4470 if (*BinaryData == NULL) {
4471 return EFI_OUT_OF_RESOURCES;
4472 }
4473
4474 return EFI_SUCCESS;
4475 }
4476
4477
4478 /**
4479 Initialize the internal data structure of a FormSet.
4480
4481 @param Handle PackageList Handle
4482 @param FormSetGuid On input, GUID or class GUID of a formset. If not
4483 specified (NULL or zero GUID), take the first
4484 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
4485 found in package list.
4486 On output, GUID of the formset found(if not NULL).
4487 @param FormSet FormSet data structure.
4488
4489 @retval EFI_SUCCESS The function completed successfully.
4490 @retval EFI_NOT_FOUND The specified FormSet could not be found.
4491
4492 **/
4493 EFI_STATUS
4494 InitializeFormSet (
4495 IN EFI_HII_HANDLE Handle,
4496 IN OUT EFI_GUID *FormSetGuid,
4497 OUT FORM_BROWSER_FORMSET *FormSet
4498 )
4499 {
4500 EFI_STATUS Status;
4501 EFI_HANDLE DriverHandle;
4502
4503 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
4504 if (EFI_ERROR (Status)) {
4505 return Status;
4506 }
4507
4508 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
4509 FormSet->HiiHandle = Handle;
4510 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
4511 FormSet->QuestionInited = FALSE;
4512
4513 //
4514 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
4515 //
4516 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
4517 if (EFI_ERROR (Status)) {
4518 return Status;
4519 }
4520 FormSet->DriverHandle = DriverHandle;
4521 Status = gBS->HandleProtocol (
4522 DriverHandle,
4523 &gEfiHiiConfigAccessProtocolGuid,
4524 (VOID **) &FormSet->ConfigAccess
4525 );
4526 if (EFI_ERROR (Status)) {
4527 //
4528 // Configuration Driver don't attach ConfigAccess protocol to its HII package
4529 // list, then there will be no configuration action required
4530 //
4531 FormSet->ConfigAccess = NULL;
4532 }
4533
4534 //
4535 // Parse the IFR binary OpCodes
4536 //
4537 Status = ParseOpCodes (FormSet);
4538
4539 return Status;
4540 }
4541
4542
4543 /**
4544 Save globals used by previous call to SendForm(). SendForm() may be called from
4545 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
4546 So, save globals of previous call to SendForm() and restore them upon exit.
4547
4548 **/
4549 VOID
4550 SaveBrowserContext (
4551 VOID
4552 )
4553 {
4554 BROWSER_CONTEXT *Context;
4555 FORM_ENTRY_INFO *MenuList;
4556
4557 gBrowserContextCount++;
4558 if (gBrowserContextCount == 1) {
4559 //
4560 // This is not reentry of SendForm(), no context to save
4561 //
4562 return;
4563 }
4564
4565 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
4566 ASSERT (Context != NULL);
4567
4568 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
4569
4570 //
4571 // Save FormBrowser context
4572 //
4573 Context->Selection = gCurrentSelection;
4574 Context->ResetRequired = gResetRequired;
4575 Context->ExitRequired = gExitRequired;
4576 Context->HiiHandle = mCurrentHiiHandle;
4577 Context->FormId = mCurrentFormId;
4578 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
4579
4580 //
4581 // Save the menu history data.
4582 //
4583 InitializeListHead(&Context->FormHistoryList);
4584 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
4585 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
4586 RemoveEntryList (&MenuList->Link);
4587
4588 InsertTailList(&Context->FormHistoryList, &MenuList->Link);
4589 }
4590
4591 //
4592 // Insert to FormBrowser context list
4593 //
4594 InsertHeadList (&gBrowserContextList, &Context->Link);
4595 }
4596
4597
4598 /**
4599 Restore globals used by previous call to SendForm().
4600
4601 **/
4602 VOID
4603 RestoreBrowserContext (
4604 VOID
4605 )
4606 {
4607 LIST_ENTRY *Link;
4608 BROWSER_CONTEXT *Context;
4609 FORM_ENTRY_INFO *MenuList;
4610
4611 ASSERT (gBrowserContextCount != 0);
4612 gBrowserContextCount--;
4613 if (gBrowserContextCount == 0) {
4614 //
4615 // This is not reentry of SendForm(), no context to restore
4616 //
4617 return;
4618 }
4619
4620 ASSERT (!IsListEmpty (&gBrowserContextList));
4621
4622 Link = GetFirstNode (&gBrowserContextList);
4623 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4624
4625 //
4626 // Restore FormBrowser context
4627 //
4628 gCurrentSelection = Context->Selection;
4629 gResetRequired = Context->ResetRequired;
4630 gExitRequired = Context->ExitRequired;
4631 mCurrentHiiHandle = Context->HiiHandle;
4632 mCurrentFormId = Context->FormId;
4633 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
4634
4635 //
4636 // Restore the menu history data.
4637 //
4638 while (!IsListEmpty (&Context->FormHistoryList)) {
4639 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
4640 RemoveEntryList (&MenuList->Link);
4641
4642 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
4643 }
4644
4645 //
4646 // Remove from FormBrowser context list
4647 //
4648 RemoveEntryList (&Context->Link);
4649 gBS->FreePool (Context);
4650 }
4651
4652 /**
4653 Find the matched FormSet context in the backup maintain list based on HiiHandle.
4654
4655 @param Handle The Hii Handle.
4656
4657 @return the found FormSet context. If no found, NULL will return.
4658
4659 **/
4660 FORM_BROWSER_FORMSET *
4661 GetFormSetFromHiiHandle (
4662 EFI_HII_HANDLE Handle
4663 )
4664 {
4665 LIST_ENTRY *Link;
4666 FORM_BROWSER_FORMSET *FormSet;
4667
4668 Link = GetFirstNode (&gBrowserFormSetList);
4669 while (!IsNull (&gBrowserFormSetList, Link)) {
4670 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4671 Link = GetNextNode (&gBrowserFormSetList, Link);
4672 if (!ValidateFormSet(FormSet)) {
4673 continue;
4674 }
4675 if (FormSet->HiiHandle == Handle) {
4676 return FormSet;
4677 }
4678 }
4679
4680 return NULL;
4681 }
4682
4683 /**
4684 Check whether the input HII handle is the FormSet that is being used.
4685
4686 @param Handle The Hii Handle.
4687
4688 @retval TRUE HII handle is being used.
4689 @retval FALSE HII handle is not being used.
4690
4691 **/
4692 BOOLEAN
4693 IsHiiHandleInBrowserContext (
4694 EFI_HII_HANDLE Handle
4695 )
4696 {
4697 LIST_ENTRY *Link;
4698 BROWSER_CONTEXT *Context;
4699
4700 //
4701 // HiiHandle is Current FormSet.
4702 //
4703 if (mCurrentHiiHandle == Handle) {
4704 return TRUE;
4705 }
4706
4707 //
4708 // Check whether HiiHandle is in BrowserContext.
4709 //
4710 Link = GetFirstNode (&gBrowserContextList);
4711 while (!IsNull (&gBrowserContextList, Link)) {
4712 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4713 if (Context->HiiHandle == Handle) {
4714 //
4715 // HiiHandle is in BrowserContext
4716 //
4717 return TRUE;
4718 }
4719 Link = GetNextNode (&gBrowserContextList, Link);
4720 }
4721
4722 return FALSE;
4723 }
4724
4725 /**
4726 Perform Password check.
4727 Passwork may be encrypted by driver that requires the specific check.
4728
4729 @param Form Form where Password Statement is in.
4730 @param Statement Password statement
4731 @param PasswordString Password string to be checked. It may be NULL.
4732 NULL means to restore password.
4733 "" string can be used to checked whether old password does exist.
4734
4735 @return Status Status of Password check.
4736 **/
4737 EFI_STATUS
4738 EFIAPI
4739 PasswordCheck (
4740 IN FORM_DISPLAY_ENGINE_FORM *Form,
4741 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
4742 IN EFI_STRING PasswordString OPTIONAL
4743 )
4744 {
4745 EFI_STATUS Status;
4746 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
4747 EFI_BROWSER_ACTION_REQUEST ActionRequest;
4748 EFI_IFR_TYPE_VALUE IfrTypeValue;
4749 FORM_BROWSER_STATEMENT *Question;
4750
4751 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
4752 Question = GetBrowserStatement(Statement);
4753 ASSERT (Question != NULL);
4754
4755 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
4756 if (ConfigAccess == NULL) {
4757 return EFI_UNSUPPORTED;
4758 }
4759 } else {
4760 if (PasswordString == NULL) {
4761 return EFI_SUCCESS;
4762 }
4763
4764 //
4765 // Check whether has preexisted password.
4766 //
4767 if (PasswordString[0] == 0) {
4768 if (*((CHAR16 *) Question->BufferValue) == 0) {
4769 return EFI_SUCCESS;
4770 } else {
4771 return EFI_NOT_READY;
4772 }
4773 }
4774
4775 //
4776 // Check whether the input password is same as preexisted password.
4777 //
4778 if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {
4779 return EFI_SUCCESS;
4780 } else {
4781 return EFI_NOT_READY;
4782 }
4783 }
4784
4785 //
4786 // Prepare password string in HII database
4787 //
4788 if (PasswordString != NULL) {
4789 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
4790 } else {
4791 IfrTypeValue.string = 0;
4792 }
4793
4794 //
4795 // Send password to Configuration Driver for validation
4796 //
4797 Status = ConfigAccess->Callback (
4798 ConfigAccess,
4799 EFI_BROWSER_ACTION_CHANGING,
4800 Question->QuestionId,
4801 Question->HiiValue.Type,
4802 &IfrTypeValue,
4803 &ActionRequest
4804 );
4805
4806 //
4807 // Remove password string from HII database
4808 //
4809 if (PasswordString != NULL) {
4810 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
4811 }
4812
4813 return Status;
4814 }
4815
4816 /**
4817 Find the registered HotKey based on KeyData.
4818
4819 @param[in] KeyData A pointer to a buffer that describes the keystroke
4820 information for the hot key.
4821
4822 @return The registered HotKey context. If no found, NULL will return.
4823 **/
4824 BROWSER_HOT_KEY *
4825 GetHotKeyFromRegisterList (
4826 IN EFI_INPUT_KEY *KeyData
4827 )
4828 {
4829 LIST_ENTRY *Link;
4830 BROWSER_HOT_KEY *HotKey;
4831
4832 Link = GetFirstNode (&gBrowserHotKeyList);
4833 while (!IsNull (&gBrowserHotKeyList, Link)) {
4834 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
4835 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
4836 return HotKey;
4837 }
4838 Link = GetNextNode (&gBrowserHotKeyList, Link);
4839 }
4840
4841 return NULL;
4842 }
4843
4844 /**
4845 Configure what scope the hot key will impact.
4846 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
4847 If no scope is set, the default scope will be FormSet level.
4848 After all registered hot keys are removed, previous Scope can reset to another level.
4849
4850 @param[in] Scope Scope level to be set.
4851
4852 @retval EFI_SUCCESS Scope is set correctly.
4853 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
4854 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
4855
4856 **/
4857 EFI_STATUS
4858 EFIAPI
4859 SetScope (
4860 IN BROWSER_SETTING_SCOPE Scope
4861 )
4862 {
4863 if (Scope >= MaxLevel) {
4864 return EFI_INVALID_PARAMETER;
4865 }
4866
4867 //
4868 // When no hot key registered in system or on the first setting,
4869 // Scope can be set.
4870 //
4871 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
4872 gBrowserSettingScope = Scope;
4873 mBrowserScopeFirstSet = FALSE;
4874 } else if (Scope != gBrowserSettingScope) {
4875 return EFI_UNSUPPORTED;
4876 }
4877
4878 return EFI_SUCCESS;
4879 }
4880
4881 /**
4882 Register the hot key with its browser action, or unregistered the hot key.
4883 Only support hot key that is not printable character (control key, function key, etc.).
4884 If the action value is zero, the hot key will be unregistered if it has been registered.
4885 If the same hot key has been registered, the new action and help string will override the previous ones.
4886
4887 @param[in] KeyData A pointer to a buffer that describes the keystroke
4888 information for the hot key. Its type is EFI_INPUT_KEY to
4889 be supported by all ConsoleIn devices.
4890 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
4891 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
4892 @param[in] HelpString Help string that describes the hot key information.
4893 Its value may be NULL for the unregistered hot key.
4894
4895 @retval EFI_SUCCESS Hot key is registered or unregistered.
4896 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
4897 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
4898 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
4899 **/
4900 EFI_STATUS
4901 EFIAPI
4902 RegisterHotKey (
4903 IN EFI_INPUT_KEY *KeyData,
4904 IN UINT32 Action,
4905 IN UINT16 DefaultId,
4906 IN EFI_STRING HelpString OPTIONAL
4907 )
4908 {
4909 BROWSER_HOT_KEY *HotKey;
4910
4911 //
4912 // Check input parameters.
4913 //
4914 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
4915 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
4916 return EFI_INVALID_PARAMETER;
4917 }
4918
4919 //
4920 // Check whether the input KeyData is in BrowserHotKeyList.
4921 //
4922 HotKey = GetHotKeyFromRegisterList (KeyData);
4923
4924 //
4925 // Unregister HotKey
4926 //
4927 if (Action == BROWSER_ACTION_UNREGISTER) {
4928 if (HotKey != NULL) {
4929 //
4930 // The registered HotKey is found.
4931 // Remove it from List, and free its resource.
4932 //
4933 RemoveEntryList (&HotKey->Link);
4934 FreePool (HotKey->KeyData);
4935 FreePool (HotKey->HelpString);
4936 return EFI_SUCCESS;
4937 } else {
4938 //
4939 // The registered HotKey is not found.
4940 //
4941 return EFI_NOT_FOUND;
4942 }
4943 }
4944
4945 //
4946 // Register HotKey into List.
4947 //
4948 if (HotKey == NULL) {
4949 //
4950 // Create new Key, and add it into List.
4951 //
4952 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
4953 ASSERT (HotKey != NULL);
4954 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
4955 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
4956 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
4957 }
4958
4959 //
4960 // Fill HotKey information.
4961 //
4962 HotKey->Action = Action;
4963 HotKey->DefaultId = DefaultId;
4964 if (HotKey->HelpString != NULL) {
4965 FreePool (HotKey->HelpString);
4966 }
4967 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
4968
4969 return EFI_SUCCESS;
4970 }
4971
4972 /**
4973 Register Exit handler function.
4974 When more than one handler function is registered, the latter one will override the previous one.
4975 When NULL handler is specified, the previous Exit handler will be unregistered.
4976
4977 @param[in] Handler Pointer to handler function.
4978
4979 **/
4980 VOID
4981 EFIAPI
4982 RegiserExitHandler (
4983 IN EXIT_HANDLER Handler
4984 )
4985 {
4986 ExitHandlerFunction = Handler;
4987 return;
4988 }
4989
4990 /**
4991 Check whether the browser data has been modified.
4992
4993 @retval TRUE Browser data is modified.
4994 @retval FALSE No browser data is modified.
4995
4996 **/
4997 BOOLEAN
4998 EFIAPI
4999 IsBrowserDataModified (
5000 VOID
5001 )
5002 {
5003 LIST_ENTRY *Link;
5004 FORM_BROWSER_FORMSET *FormSet;
5005
5006 switch (gBrowserSettingScope) {
5007 case FormLevel:
5008 if (gCurrentSelection == NULL) {
5009 return FALSE;
5010 }
5011 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
5012
5013 case FormSetLevel:
5014 if (gCurrentSelection == NULL) {
5015 return FALSE;
5016 }
5017 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
5018
5019 case SystemLevel:
5020 Link = GetFirstNode (&gBrowserFormSetList);
5021 while (!IsNull (&gBrowserFormSetList, Link)) {
5022 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5023 if (!ValidateFormSet(FormSet)) {
5024 continue;
5025 }
5026
5027 if (IsNvUpdateRequiredForFormSet (FormSet)) {
5028 return TRUE;
5029 }
5030 Link = GetNextNode (&gBrowserFormSetList, Link);
5031 }
5032 return FALSE;
5033
5034 default:
5035 return FALSE;
5036 }
5037 }
5038
5039 /**
5040 Execute the action requested by the Action parameter.
5041
5042 @param[in] Action Execute the request action.
5043 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
5044
5045 @retval EFI_SUCCESS Execute the request action succss.
5046 @retval EFI_INVALID_PARAMETER The input action value is invalid.
5047
5048 **/
5049 EFI_STATUS
5050 EFIAPI
5051 ExecuteAction (
5052 IN UINT32 Action,
5053 IN UINT16 DefaultId
5054 )
5055 {
5056 EFI_STATUS Status;
5057 FORM_BROWSER_FORMSET *FormSet;
5058 FORM_BROWSER_FORM *Form;
5059
5060 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
5061 return EFI_NOT_READY;
5062 }
5063
5064 Status = EFI_SUCCESS;
5065 FormSet = NULL;
5066 Form = NULL;
5067 if (gBrowserSettingScope < SystemLevel) {
5068 FormSet = gCurrentSelection->FormSet;
5069 Form = gCurrentSelection->Form;
5070 }
5071
5072 //
5073 // Executet the discard action.
5074 //
5075 if ((Action & BROWSER_ACTION_DISCARD) != 0) {
5076 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
5077 if (EFI_ERROR (Status)) {
5078 return Status;
5079 }
5080 }
5081
5082 //
5083 // Executet the difault action.
5084 //
5085 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
5086 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);
5087 if (EFI_ERROR (Status)) {
5088 return Status;
5089 }
5090 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
5091 }
5092
5093 //
5094 // Executet the submit action.
5095 //
5096 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
5097 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
5098 if (EFI_ERROR (Status)) {
5099 return Status;
5100 }
5101 }
5102
5103 //
5104 // Executet the reset action.
5105 //
5106 if ((Action & BROWSER_ACTION_RESET) != 0) {
5107 gResetRequired = TRUE;
5108 }
5109
5110 //
5111 // Executet the exit action.
5112 //
5113 if ((Action & BROWSER_ACTION_EXIT) != 0) {
5114 DiscardForm (FormSet, Form, gBrowserSettingScope);
5115 if (gBrowserSettingScope == SystemLevel) {
5116 if (ExitHandlerFunction != NULL) {
5117 ExitHandlerFunction ();
5118 }
5119 }
5120
5121 gExitRequired = TRUE;
5122 }
5123
5124 return Status;
5125 }
5126
5127 /**
5128 Create reminder to let user to choose save or discard the changed browser data.
5129 Caller can use it to actively check the changed browser data.
5130
5131 @retval BROWSER_NO_CHANGES No browser data is changed.
5132 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
5133 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
5134 @retval BROWSER_KEEP_CURRENT Browser keep current changes.
5135
5136 **/
5137 UINT32
5138 EFIAPI
5139 SaveReminder (
5140 VOID
5141 )
5142 {
5143 LIST_ENTRY *Link;
5144 FORM_BROWSER_FORMSET *FormSet;
5145 BOOLEAN IsDataChanged;
5146 UINT32 DataSavedAction;
5147 UINT32 ConfirmRet;
5148
5149 DataSavedAction = BROWSER_NO_CHANGES;
5150 IsDataChanged = FALSE;
5151 Link = GetFirstNode (&gBrowserFormSetList);
5152 while (!IsNull (&gBrowserFormSetList, Link)) {
5153 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
5154 Link = GetNextNode (&gBrowserFormSetList, Link);
5155 if (!ValidateFormSet(FormSet)) {
5156 continue;
5157 }
5158 if (IsNvUpdateRequiredForFormSet (FormSet)) {
5159 IsDataChanged = TRUE;
5160 break;
5161 }
5162 }
5163
5164 //
5165 // No data is changed. No save is required.
5166 //
5167 if (!IsDataChanged) {
5168 return DataSavedAction;
5169 }
5170
5171 //
5172 // If data is changed, prompt user to save or discard it.
5173 //
5174 do {
5175 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
5176
5177 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
5178 SubmitForm (NULL, NULL, SystemLevel);
5179 DataSavedAction = BROWSER_SAVE_CHANGES;
5180 break;
5181 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
5182 DiscardForm (NULL, NULL, SystemLevel);
5183 DataSavedAction = BROWSER_DISCARD_CHANGES;
5184 break;
5185 } else if (ConfirmRet == BROWSER_ACTION_NONE) {
5186 DataSavedAction = BROWSER_KEEP_CURRENT;
5187 break;
5188 }
5189 } while (1);
5190
5191 return DataSavedAction;
5192 }