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