]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
MdeModulePkg: Replace [Ascii|Unicode]ValueToString
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Setup.c
1 /** @file
2 Entry and initialization module for the browser.
3
4 Copyright (c) 2007 - 2017, 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_1,
32 SetScope,
33 RegisterHotKey,
34 RegiserExitHandler,
35 IsBrowserDataModified,
36 ExecuteAction,
37 {NULL,NULL},
38 {NULL,NULL},
39 IsResetRequired
40 }
41 };
42
43 EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
44 EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting;
45 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
46 EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;
47
48 UINTN gBrowserContextCount = 0;
49 LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
50 LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
51 LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
52 LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);
53 LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList);
54
55 BOOLEAN mSystemSubmit = FALSE;
56 BOOLEAN gResetRequired;
57 BOOLEAN gExitRequired;
58 BOOLEAN gFlagReconnect;
59 BOOLEAN gCallbackReconnect;
60 BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
61 BOOLEAN mBrowserScopeFirstSet = TRUE;
62 EXIT_HANDLER ExitHandlerFunction = NULL;
63 FORM_BROWSER_FORMSET *mSystemLevelFormSet;
64
65 //
66 // Browser Global Strings
67 //
68 CHAR16 *gEmptyString;
69 CHAR16 *mUnknownString = L"!";
70
71 extern EFI_GUID mCurrentFormSetGuid;
72 extern EFI_HII_HANDLE mCurrentHiiHandle;
73 extern UINT16 mCurrentFormId;
74 extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
75
76 /**
77 Create a menu with specified formset GUID and form ID, and add it as a child
78 of the given parent menu.
79
80 @param HiiHandle Hii handle related to this formset.
81 @param FormSetGuid The Formset Guid of menu to be added.
82 @param FormId The Form ID of menu to be added.
83 @param QuestionId The question id of this menu to be added.
84
85 @return A pointer to the newly added menu or NULL if memory is insufficient.
86
87 **/
88 FORM_ENTRY_INFO *
89 UiAddMenuList (
90 IN EFI_HII_HANDLE HiiHandle,
91 IN EFI_GUID *FormSetGuid,
92 IN UINT16 FormId,
93 IN UINT16 QuestionId
94 )
95 {
96 FORM_ENTRY_INFO *MenuList;
97
98 MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
99 if (MenuList == NULL) {
100 return NULL;
101 }
102
103 MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;
104
105 MenuList->HiiHandle = HiiHandle;
106 CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
107 MenuList->FormId = FormId;
108 MenuList->QuestionId = QuestionId;
109
110 //
111 // If parent is not specified, it is the root Form of a Formset
112 //
113 InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
114
115 return MenuList;
116 }
117
118 /**
119 Return the form id for the input hiihandle and formset.
120
121 @param HiiHandle HiiHandle for FormSet.
122 @param FormSetGuid The Formset GUID of the menu to search.
123
124 @return First form's id for this form set.
125
126 **/
127 EFI_FORM_ID
128 GetFirstFormId (
129 IN EFI_HII_HANDLE HiiHandle,
130 IN EFI_GUID *FormSetGuid
131 )
132 {
133 LIST_ENTRY *Link;
134 FORM_BROWSER_FORM *Form;
135
136 Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);
137 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
138
139 return Form->FormId;
140 }
141
142 /**
143 Search Menu with given FormSetGuid and FormId in all cached menu list.
144
145 @param HiiHandle HiiHandle for FormSet.
146 @param FormSetGuid The Formset GUID of the menu to search.
147 @param FormId The Form ID of menu to search.
148
149 @return A pointer to menu found or NULL if not found.
150
151 **/
152 FORM_ENTRY_INFO *
153 UiFindMenuList (
154 IN EFI_HII_HANDLE HiiHandle,
155 IN EFI_GUID *FormSetGuid,
156 IN UINT16 FormId
157 )
158 {
159 LIST_ENTRY *Link;
160 FORM_ENTRY_INFO *MenuList;
161 FORM_ENTRY_INFO *RetMenu;
162 EFI_FORM_ID FirstFormId;
163
164 RetMenu = NULL;
165
166 Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
167 while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {
168 MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
169 Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);
170
171 //
172 // If already find the menu, free the menus behind it.
173 //
174 if (RetMenu != NULL) {
175 RemoveEntryList (&MenuList->Link);
176 FreePool (MenuList);
177 continue;
178 }
179
180 //
181 // Find the same FromSet.
182 //
183 if (MenuList->HiiHandle == HiiHandle) {
184 if (IsZeroGuid (&MenuList->FormSetGuid)) {
185 //
186 // FormSetGuid is not specified.
187 //
188 RetMenu = MenuList;
189 } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {
190 if (MenuList->FormId == FormId) {
191 RetMenu = MenuList;
192 } else if (FormId == 0 || MenuList->FormId == 0 ) {
193 FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);
194 if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {
195 RetMenu = MenuList;
196 }
197 }
198 }
199 }
200 }
201
202 return RetMenu;
203 }
204
205 /**
206 Find parent menu for current menu.
207
208 @param CurrentMenu Current Menu
209 @param SettingLevel Whether find parent menu in Form Level or Formset level.
210 In form level, just find the parent menu;
211 In formset level, find the parent menu which has different
212 formset guid value.
213
214 @retval The parent menu for current menu.
215 **/
216 FORM_ENTRY_INFO *
217 UiFindParentMenu (
218 IN FORM_ENTRY_INFO *CurrentMenu,
219 IN BROWSER_SETTING_SCOPE SettingLevel
220 )
221 {
222 FORM_ENTRY_INFO *ParentMenu;
223 LIST_ENTRY *Link;
224
225 ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel);
226
227 if (CurrentMenu == NULL) {
228 return NULL;
229 }
230
231 ParentMenu = NULL;
232 Link = &CurrentMenu->Link;
233
234 while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
235 ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink);
236
237 if (SettingLevel == FormLevel) {
238 //
239 // For FormLevel, just find the parent menu, return.
240 //
241 break;
242 }
243
244 if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
245 //
246 // For SystemLevel, must find the menu which has different formset.
247 //
248 break;
249 }
250
251 Link = Link->BackLink;
252 }
253
254 //
255 // Not find the parent menu, just return NULL.
256 //
257 if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {
258 return NULL;
259 }
260
261 return ParentMenu;
262 }
263
264 /**
265 Free Menu list linked list.
266
267 @param MenuListHead One Menu list point in the menu list.
268
269 **/
270 VOID
271 UiFreeMenuList (
272 LIST_ENTRY *MenuListHead
273 )
274 {
275 FORM_ENTRY_INFO *MenuList;
276
277 while (!IsListEmpty (MenuListHead)) {
278 MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);
279 RemoveEntryList (&MenuList->Link);
280
281 FreePool (MenuList);
282 }
283 }
284
285 /**
286 Copy current Menu list to the new menu list.
287
288 @param NewMenuListHead New create Menu list.
289 @param CurrentMenuListHead Current Menu list.
290
291 **/
292 VOID
293 UiCopyMenuList (
294 OUT LIST_ENTRY *NewMenuListHead,
295 IN LIST_ENTRY *CurrentMenuListHead
296 )
297 {
298 LIST_ENTRY *Link;
299 FORM_ENTRY_INFO *MenuList;
300 FORM_ENTRY_INFO *NewMenuEntry;
301
302 //
303 // If new menu list not empty, free it first.
304 //
305 UiFreeMenuList (NewMenuListHead);
306
307 Link = GetFirstNode (CurrentMenuListHead);
308 while (!IsNull (CurrentMenuListHead, Link)) {
309 MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);
310 Link = GetNextNode (CurrentMenuListHead, Link);
311
312 NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));
313 ASSERT (NewMenuEntry != NULL);
314 NewMenuEntry->Signature = FORM_ENTRY_INFO_SIGNATURE;
315 NewMenuEntry->HiiHandle = MenuList->HiiHandle;
316 CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID));
317 NewMenuEntry->FormId = MenuList->FormId;
318 NewMenuEntry->QuestionId = MenuList->QuestionId;
319
320 InsertTailList (NewMenuListHead, &NewMenuEntry->Link);
321 }
322 }
323
324 /**
325 Load all hii formset to the browser.
326
327 **/
328 VOID
329 LoadAllHiiFormset (
330 VOID
331 )
332 {
333 FORM_BROWSER_FORMSET *LocalFormSet;
334 EFI_HII_HANDLE *HiiHandles;
335 UINTN Index;
336 EFI_GUID ZeroGuid;
337 EFI_STATUS Status;
338 FORM_BROWSER_FORMSET *OldFormset;
339
340 OldFormset = mSystemLevelFormSet;
341
342 //
343 // Get all the Hii handles
344 //
345 HiiHandles = HiiGetHiiHandles (NULL);
346 ASSERT (HiiHandles != NULL);
347
348 //
349 // Search for formset of each class type
350 //
351 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
352 //
353 // Check HiiHandles[Index] does exist in global maintain list.
354 //
355 if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
356 continue;
357 }
358
359 //
360 // Initilize FormSet Setting
361 //
362 LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
363 ASSERT (LocalFormSet != NULL);
364 mSystemLevelFormSet = LocalFormSet;
365
366 ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
367 Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);
368 if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
369 DestroyFormSet (LocalFormSet);
370 continue;
371 }
372 InitializeCurrentSetting (LocalFormSet);
373
374 //
375 // Initilize Questions' Value
376 //
377 Status = LoadFormSetConfig (NULL, LocalFormSet);
378 if (EFI_ERROR (Status)) {
379 DestroyFormSet (LocalFormSet);
380 continue;
381 }
382 }
383
384 //
385 // Free resources, and restore gOldFormSet and gClassOfVfr
386 //
387 FreePool (HiiHandles);
388
389 mSystemLevelFormSet = OldFormset;
390 }
391
392 /**
393 Pop up the error info.
394
395 @param BrowserStatus The input browser status.
396 @param HiiHandle The Hiihandle for this opcode.
397 @param OpCode The opcode use to get the erro info and timeout value.
398 @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF.
399
400 **/
401 UINT32
402 PopupErrorMessage (
403 IN UINT32 BrowserStatus,
404 IN EFI_HII_HANDLE HiiHandle,
405 IN EFI_IFR_OP_HEADER *OpCode, OPTIONAL
406 IN CHAR16 *ErrorString
407 )
408 {
409 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
410 USER_INPUT UserInputData;
411
412 Statement = NULL;
413
414 if (OpCode != NULL) {
415 Statement = AllocateZeroPool (sizeof(FORM_DISPLAY_ENGINE_STATEMENT));
416 ASSERT (Statement != NULL);
417 Statement->OpCode = OpCode;
418 gDisplayFormData.HighLightedStatement = Statement;
419 }
420
421 //
422 // Used to compatible with old display engine.
423 // New display engine not use this field.
424 //
425 gDisplayFormData.ErrorString = ErrorString;
426 gDisplayFormData.BrowserStatus = BrowserStatus;
427
428 if (HiiHandle != NULL) {
429 gDisplayFormData.HiiHandle = HiiHandle;
430 }
431
432 mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData);
433
434 gDisplayFormData.BrowserStatus = BROWSER_SUCCESS;
435 gDisplayFormData.ErrorString = NULL;
436
437 if (OpCode != NULL) {
438 FreePool (Statement);
439 }
440
441 return UserInputData.Action;
442 }
443
444 /**
445 This is the routine which an external caller uses to direct the browser
446 where to obtain it's information.
447
448
449 @param This The Form Browser protocol instanse.
450 @param Handles A pointer to an array of Handles. If HandleCount > 1 we
451 display a list of the formsets for the handles specified.
452 @param HandleCount The number of Handles specified in Handle.
453 @param FormSetGuid This field points to the EFI_GUID which must match the Guid
454 field in the EFI_IFR_FORM_SET op-code for the specified
455 forms-based package. If FormSetGuid is NULL, then this
456 function will display the first found forms package.
457 @param FormId This field specifies which EFI_IFR_FORM to render as the first
458 displayable page. If this field has a value of 0x0000, then
459 the forms browser will render the specified forms in their encoded order.
460 @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
461 characters.
462 @param ActionRequest Points to the action recommended by the form.
463
464 @retval EFI_SUCCESS The function completed successfully.
465 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
466 @retval EFI_NOT_FOUND No valid forms could be found to display.
467
468 **/
469 EFI_STATUS
470 EFIAPI
471 SendForm (
472 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
473 IN EFI_HII_HANDLE *Handles,
474 IN UINTN HandleCount,
475 IN EFI_GUID *FormSetGuid, OPTIONAL
476 IN UINT16 FormId, OPTIONAL
477 IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL
478 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL
479 )
480 {
481 EFI_STATUS Status;
482 UI_MENU_SELECTION *Selection;
483 UINTN Index;
484 FORM_BROWSER_FORMSET *FormSet;
485 FORM_ENTRY_INFO *MenuList;
486 BOOLEAN RetVal;
487
488 //
489 // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.
490 //
491 if (mFormDisplay == NULL) {
492 DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!"));
493 return EFI_UNSUPPORTED;
494 }
495
496 //
497 // Save globals used by SendForm()
498 //
499 SaveBrowserContext ();
500
501 gFlagReconnect = FALSE;
502 gResetRequired = FALSE;
503 gExitRequired = FALSE;
504 gCallbackReconnect = FALSE;
505 Status = EFI_SUCCESS;
506 gEmptyString = L"";
507 gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;
508
509 for (Index = 0; Index < HandleCount; Index++) {
510 Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
511 ASSERT (Selection != NULL);
512
513 Selection->Handle = Handles[Index];
514 if (FormSetGuid != NULL) {
515 CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
516 Selection->FormId = FormId;
517 } else {
518 CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));
519 }
520
521 do {
522 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
523 ASSERT (FormSet != NULL);
524
525 //
526 // Validate the HiiHandle
527 // if validate failed, find the first validate parent HiiHandle.
528 //
529 if (!ValidateHiiHandle(Selection->Handle)) {
530 FindNextMenu (Selection, FormSetLevel);
531 }
532
533 //
534 // Initialize internal data structures of FormSet
535 //
536 Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
537 if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
538 DestroyFormSet (FormSet);
539 break;
540 }
541 Selection->FormSet = FormSet;
542 mSystemLevelFormSet = FormSet;
543
544 //
545 // Display this formset
546 //
547 gCurrentSelection = Selection;
548
549 Status = SetupBrowser (Selection);
550
551 gCurrentSelection = NULL;
552 mSystemLevelFormSet = NULL;
553
554 if (gFlagReconnect || gCallbackReconnect) {
555 RetVal = ReconnectController (FormSet->DriverHandle);
556 if (!RetVal) {
557 PopupErrorMessage(BROWSER_RECONNECT_FAIL, NULL, NULL, NULL);
558 }
559 gFlagReconnect = FALSE;
560 gCallbackReconnect = FALSE;
561 }
562
563 //
564 // If no data is changed, don't need to save current FormSet into the maintain list.
565 //
566 if (!IsNvUpdateRequiredForFormSet (FormSet)) {
567 CleanBrowserStorage(FormSet);
568 RemoveEntryList (&FormSet->Link);
569 DestroyFormSet (FormSet);
570 }
571
572 if (EFI_ERROR (Status)) {
573 break;
574 }
575 } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
576
577 FreePool (Selection);
578 }
579
580 if (ActionRequest != NULL) {
581 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
582 if (gResetRequired) {
583 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
584 }
585 }
586
587 mFormDisplay->ExitDisplay();
588
589 //
590 // Clear the menu history data.
591 //
592 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
593 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
594 RemoveEntryList (&MenuList->Link);
595 FreePool (MenuList);
596 }
597
598 //
599 // Restore globals used by SendForm()
600 //
601 RestoreBrowserContext ();
602
603 return Status;
604 }
605
606 /**
607 Get or set data to the storage.
608
609 @param ResultsDataSize The size of the buffer associatedwith ResultsData.
610 @param ResultsData A string returned from an IFR browser or
611 equivalent. The results string will have no
612 routing information in them.
613 @param RetrieveData A BOOLEAN field which allows an agent to retrieve
614 (if RetrieveData = TRUE) data from the uncommitted
615 browser state information or set (if RetrieveData
616 = FALSE) data in the uncommitted browser state
617 information.
618 @param Storage The pointer to the storage.
619
620 @retval EFI_SUCCESS The results have been distributed or are awaiting
621 distribution.
622
623 **/
624 EFI_STATUS
625 ProcessStorage (
626 IN OUT UINTN *ResultsDataSize,
627 IN OUT EFI_STRING *ResultsData,
628 IN BOOLEAN RetrieveData,
629 IN BROWSER_STORAGE *Storage
630 )
631 {
632 CHAR16 *ConfigResp;
633 EFI_STATUS Status;
634 CHAR16 *StrPtr;
635 UINTN BufferSize;
636 UINTN TmpSize;
637 UINTN MaxLen;
638 FORMSET_STORAGE *BrowserStorage;
639
640 if (RetrieveData) {
641 //
642 // Generate <ConfigResp>
643 //
644 Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);
645 if (EFI_ERROR (Status)) {
646 return Status;
647 }
648
649 //
650 // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.
651 // Also need to consider add "\0" at first time.
652 //
653 StrPtr = StrStr (ConfigResp, L"PATH");
654 ASSERT (StrPtr != NULL);
655 StrPtr = StrStr (StrPtr, L"&");
656 StrPtr += 1;
657 BufferSize = StrSize (StrPtr);
658
659 //
660 // Copy the data if the input buffer is bigger enough.
661 //
662 if (*ResultsDataSize >= BufferSize) {
663 StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr);
664 }
665
666 *ResultsDataSize = BufferSize;
667 FreePool (ConfigResp);
668 } else {
669 //
670 // Prepare <ConfigResp>
671 //
672 BrowserStorage = GetFstStgFromBrsStg (Storage);
673 ASSERT (BrowserStorage != NULL);
674 TmpSize = StrLen (*ResultsData);
675 BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);
676 MaxLen = BufferSize / sizeof (CHAR16);
677 ConfigResp = AllocateZeroPool (BufferSize);
678 ASSERT (ConfigResp != NULL);
679
680 StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr);
681 StrCatS (ConfigResp, MaxLen, L"&");
682 StrCatS (ConfigResp, MaxLen, *ResultsData);
683
684 //
685 // Update Browser uncommited data
686 //
687 Status = ConfigRespToStorage (Storage, ConfigResp);
688 FreePool (ConfigResp);
689 if (EFI_ERROR (Status)) {
690 return Status;
691 }
692 }
693
694 return EFI_SUCCESS;
695 }
696
697 /**
698 This routine called this service in the browser to retrieve or set certain uncommitted
699 state information that resides in the open formsets.
700
701 @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
702 instance.
703 @param ResultsDataSize A pointer to the size of the buffer associated
704 with ResultsData.
705 @param ResultsData A string returned from an IFR browser or
706 equivalent. The results string will have no
707 routing information in them.
708 @param RetrieveData A BOOLEAN field which allows an agent to retrieve
709 (if RetrieveData = TRUE) data from the uncommitted
710 browser state information or set (if RetrieveData
711 = FALSE) data in the uncommitted browser state
712 information.
713 @param VariableGuid An optional field to indicate the target variable
714 GUID name to use.
715 @param VariableName An optional field to indicate the target
716 human-readable variable name.
717
718 @retval EFI_SUCCESS The results have been distributed or are awaiting
719 distribution.
720 @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
721 contain the results data.
722
723 **/
724 EFI_STATUS
725 EFIAPI
726 BrowserCallback (
727 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
728 IN OUT UINTN *ResultsDataSize,
729 IN OUT EFI_STRING ResultsData,
730 IN BOOLEAN RetrieveData,
731 IN CONST EFI_GUID *VariableGuid, OPTIONAL
732 IN CONST CHAR16 *VariableName OPTIONAL
733 )
734 {
735 EFI_STATUS Status;
736 LIST_ENTRY *Link;
737 BROWSER_STORAGE *Storage;
738 FORMSET_STORAGE *FormsetStorage;
739 UINTN TotalSize;
740 BOOLEAN Found;
741
742 if (ResultsDataSize == NULL || ResultsData == NULL) {
743 return EFI_INVALID_PARAMETER;
744 }
745
746 TotalSize = *ResultsDataSize;
747 Storage = NULL;
748 Found = FALSE;
749 Status = EFI_SUCCESS;
750
751 if (VariableGuid != NULL) {
752 //
753 // Try to find target storage in the current formset.
754 //
755 Link = GetFirstNode (&gBrowserStorageList);
756 while (!IsNull (&gBrowserStorageList, Link)) {
757 Storage = BROWSER_STORAGE_FROM_LINK (Link);
758 Link = GetNextNode (&gBrowserStorageList, Link);
759 //
760 // Check the current storage.
761 //
762 if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
763 continue;
764 }
765
766 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
767 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
768 //
769 // Buffer storage require both GUID and Name
770 //
771 if (VariableName == NULL) {
772 return EFI_NOT_FOUND;
773 }
774
775 if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
776 continue;
777 }
778 }
779
780 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE ||
781 Storage->Type == EFI_HII_VARSTORE_BUFFER) {
782 if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) {
783 return EFI_NOT_FOUND;
784 }
785
786 if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) {
787 continue;
788 }
789 }
790
791 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);
792 if (EFI_ERROR (Status)) {
793 return Status;
794 }
795
796 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
797 ConfigRequestAdjust (Storage, ResultsData, TRUE);
798 }
799
800 //
801 // Different formsets may have same varstore, so here just set the flag
802 // not exit the circle.
803 //
804 Found = TRUE;
805 break;
806 }
807
808 if (!Found) {
809 return EFI_NOT_FOUND;
810 }
811 } else {
812 //
813 // GUID/Name is not specified, take the first storage in FormSet
814 //
815 if (mSystemLevelFormSet == NULL) {
816 return EFI_NOT_READY;
817 }
818
819 //
820 // Generate <ConfigResp>
821 //
822 Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead);
823 if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) {
824 return EFI_UNSUPPORTED;
825 }
826
827 FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);
828
829 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);
830 if (EFI_ERROR (Status)) {
831 return Status;
832 }
833 }
834
835 if (RetrieveData) {
836 Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
837 *ResultsDataSize = TotalSize;
838 }
839
840 return Status;
841
842 }
843
844
845 /**
846 Callback function for SimpleTextInEx protocol install events
847
848 @param Event the event that is signaled.
849 @param Context not used here.
850
851 **/
852 VOID
853 EFIAPI
854 FormDisplayCallback (
855 IN EFI_EVENT Event,
856 IN VOID *Context
857 )
858 {
859 if (mFormDisplay != NULL) {
860 return;
861 }
862
863 gBS->LocateProtocol (
864 &gEdkiiFormDisplayEngineProtocolGuid,
865 NULL,
866 (VOID **) &mFormDisplay
867 );
868 }
869
870 /**
871 Initialize Setup Browser driver.
872
873 @param ImageHandle The image handle.
874 @param SystemTable The system table.
875
876 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
877 @return Other value if failed to initialize the Setup Browser module.
878
879 **/
880 EFI_STATUS
881 EFIAPI
882 InitializeSetup (
883 IN EFI_HANDLE ImageHandle,
884 IN EFI_SYSTEM_TABLE *SystemTable
885 )
886 {
887 EFI_STATUS Status;
888 VOID *Registration;
889
890 //
891 // Locate required Hii relative protocols
892 //
893 Status = gBS->LocateProtocol (
894 &gEfiHiiDatabaseProtocolGuid,
895 NULL,
896 (VOID **) &mHiiDatabase
897 );
898 ASSERT_EFI_ERROR (Status);
899
900 Status = gBS->LocateProtocol (
901 &gEfiHiiConfigRoutingProtocolGuid,
902 NULL,
903 (VOID **) &mHiiConfigRouting
904 );
905 ASSERT_EFI_ERROR (Status);
906
907 Status = gBS->LocateProtocol (
908 &gEfiDevicePathFromTextProtocolGuid,
909 NULL,
910 (VOID **) &mPathFromText
911 );
912
913 //
914 // Install FormBrowser2 protocol
915 //
916 mPrivateData.Handle = NULL;
917 Status = gBS->InstallProtocolInterface (
918 &mPrivateData.Handle,
919 &gEfiFormBrowser2ProtocolGuid,
920 EFI_NATIVE_INTERFACE,
921 &mPrivateData.FormBrowser2
922 );
923 ASSERT_EFI_ERROR (Status);
924
925 //
926 // Install FormBrowserEx2 protocol
927 //
928 InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);
929 InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
930 mPrivateData.Handle = NULL;
931 Status = gBS->InstallProtocolInterface (
932 &mPrivateData.Handle,
933 &gEdkiiFormBrowserEx2ProtocolGuid,
934 EFI_NATIVE_INTERFACE,
935 &mPrivateData.FormBrowserEx2
936 );
937 ASSERT_EFI_ERROR (Status);
938
939 Status = gBS->InstallProtocolInterface (
940 &mPrivateData.Handle,
941 &gEdkiiFormBrowserExProtocolGuid,
942 EFI_NATIVE_INTERFACE,
943 &mPrivateData.FormBrowserEx
944 );
945 ASSERT_EFI_ERROR (Status);
946
947 InitializeDisplayFormData ();
948
949 Status = gBS->LocateProtocol (
950 &gEdkiiFormDisplayEngineProtocolGuid,
951 NULL,
952 (VOID **) &mFormDisplay
953 );
954
955 if (EFI_ERROR (Status)) {
956 EfiCreateProtocolNotifyEvent (
957 &gEdkiiFormDisplayEngineProtocolGuid,
958 TPL_CALLBACK,
959 FormDisplayCallback,
960 NULL,
961 &Registration
962 );
963 }
964
965 return EFI_SUCCESS;
966 }
967
968
969 /**
970 Create a new string in HII Package List.
971
972 @param String The String to be added
973 @param HiiHandle The package list in the HII database to insert the
974 specified string.
975
976 @return The output string.
977
978 **/
979 EFI_STRING_ID
980 NewString (
981 IN CHAR16 *String,
982 IN EFI_HII_HANDLE HiiHandle
983 )
984 {
985 EFI_STRING_ID StringId;
986
987 StringId = HiiSetString (HiiHandle, 0, String, NULL);
988 ASSERT (StringId != 0);
989
990 return StringId;
991 }
992
993
994 /**
995 Delete a string from HII Package List.
996
997 @param StringId Id of the string in HII database.
998 @param HiiHandle The HII package list handle.
999
1000 @retval EFI_SUCCESS The string was deleted successfully.
1001
1002 **/
1003 EFI_STATUS
1004 DeleteString (
1005 IN EFI_STRING_ID StringId,
1006 IN EFI_HII_HANDLE HiiHandle
1007 )
1008 {
1009 CHAR16 NullChar;
1010
1011 NullChar = CHAR_NULL;
1012 HiiSetString (HiiHandle, StringId, &NullChar, NULL);
1013 return EFI_SUCCESS;
1014 }
1015
1016
1017 /**
1018 Get the string based on the StringId and HII Package List Handle.
1019
1020 @param Token The String's ID.
1021 @param HiiHandle The package list in the HII database to search for
1022 the specified string.
1023
1024 @return The output string.
1025
1026 **/
1027 CHAR16 *
1028 GetToken (
1029 IN EFI_STRING_ID Token,
1030 IN EFI_HII_HANDLE HiiHandle
1031 )
1032 {
1033 EFI_STRING String;
1034
1035 if (HiiHandle == NULL) {
1036 return NULL;
1037 }
1038
1039 String = HiiGetString (HiiHandle, Token, NULL);
1040 if (String == NULL) {
1041 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
1042 ASSERT (String != NULL);
1043 }
1044 return (CHAR16 *) String;
1045 }
1046
1047
1048 /**
1049 Allocate new memory and then copy the Unicode string Source to Destination.
1050
1051 @param Dest Location to copy string
1052 @param Src String to copy
1053
1054 **/
1055 VOID
1056 NewStringCpy (
1057 IN OUT CHAR16 **Dest,
1058 IN CHAR16 *Src
1059 )
1060 {
1061 if (*Dest != NULL) {
1062 FreePool (*Dest);
1063 }
1064 *Dest = AllocateCopyPool (StrSize (Src), Src);
1065 ASSERT (*Dest != NULL);
1066 }
1067
1068
1069 /**
1070 Allocate new memory and concatinate Source on the end of Destination.
1071
1072 @param Dest String to added to the end of.
1073 @param Src String to concatinate.
1074
1075 **/
1076 VOID
1077 NewStringCat (
1078 IN OUT CHAR16 **Dest,
1079 IN CHAR16 *Src
1080 )
1081 {
1082 CHAR16 *NewString;
1083 UINTN MaxLen;
1084
1085 if (*Dest == NULL) {
1086 NewStringCpy (Dest, Src);
1087 return;
1088 }
1089
1090 MaxLen = ( StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16);
1091 NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1092 ASSERT (NewString != NULL);
1093
1094 StrCpyS (NewString, MaxLen, *Dest);
1095 StrCatS (NewString, MaxLen, Src);
1096
1097 FreePool (*Dest);
1098 *Dest = NewString;
1099 }
1100
1101 /**
1102 Get Value for given Name from a NameValue Storage.
1103
1104 @param Storage The NameValue Storage.
1105 @param Name The Name.
1106 @param Value The retured Value.
1107 @param GetValueFrom Where to get source value, from EditValue or Value.
1108
1109 @retval EFI_SUCCESS Value found for given Name.
1110 @retval EFI_NOT_FOUND No such Name found in NameValue storage.
1111
1112 **/
1113 EFI_STATUS
1114 GetValueByName (
1115 IN BROWSER_STORAGE *Storage,
1116 IN CHAR16 *Name,
1117 IN OUT CHAR16 **Value,
1118 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
1119 )
1120 {
1121 LIST_ENTRY *Link;
1122 NAME_VALUE_NODE *Node;
1123
1124 if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {
1125 return EFI_INVALID_PARAMETER;
1126 }
1127
1128 *Value = NULL;
1129
1130 Link = GetFirstNode (&Storage->NameValueListHead);
1131 while (!IsNull (&Storage->NameValueListHead, Link)) {
1132 Node = NAME_VALUE_NODE_FROM_LINK (Link);
1133
1134 if (StrCmp (Name, Node->Name) == 0) {
1135 if (GetValueFrom == GetSetValueWithEditBuffer) {
1136 NewStringCpy (Value, Node->EditValue);
1137 } else {
1138 NewStringCpy (Value, Node->Value);
1139 }
1140 return EFI_SUCCESS;
1141 }
1142
1143 Link = GetNextNode (&Storage->NameValueListHead, Link);
1144 }
1145
1146 return EFI_NOT_FOUND;
1147 }
1148
1149
1150 /**
1151 Set Value of given Name in a NameValue Storage.
1152
1153 @param Storage The NameValue Storage.
1154 @param Name The Name.
1155 @param Value The Value to set.
1156 @param SetValueTo Whether update editValue or Value.
1157 @param ReturnNode The node use the input name.
1158
1159 @retval EFI_SUCCESS Value found for given Name.
1160 @retval EFI_NOT_FOUND No such Name found in NameValue storage.
1161
1162 **/
1163 EFI_STATUS
1164 SetValueByName (
1165 IN BROWSER_STORAGE *Storage,
1166 IN CHAR16 *Name,
1167 IN CHAR16 *Value,
1168 IN GET_SET_QUESTION_VALUE_WITH SetValueTo,
1169 OUT NAME_VALUE_NODE **ReturnNode
1170 )
1171 {
1172 LIST_ENTRY *Link;
1173 NAME_VALUE_NODE *Node;
1174 CHAR16 *Buffer;
1175
1176 if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {
1177 return EFI_INVALID_PARAMETER;
1178 }
1179
1180 Link = GetFirstNode (&Storage->NameValueListHead);
1181 while (!IsNull (&Storage->NameValueListHead, Link)) {
1182 Node = NAME_VALUE_NODE_FROM_LINK (Link);
1183
1184 if (StrCmp (Name, Node->Name) == 0) {
1185 if (SetValueTo == GetSetValueWithEditBuffer) {
1186 Buffer = Node->EditValue;
1187 } else {
1188 Buffer = Node->Value;
1189 }
1190 if (Buffer != NULL) {
1191 FreePool (Buffer);
1192 }
1193 Buffer = AllocateCopyPool (StrSize (Value), Value);
1194 ASSERT (Buffer != NULL);
1195 if (SetValueTo == GetSetValueWithEditBuffer) {
1196 Node->EditValue = Buffer;
1197 } else {
1198 Node->Value = Buffer;
1199 }
1200
1201 if (ReturnNode != NULL) {
1202 *ReturnNode = Node;
1203 }
1204
1205 return EFI_SUCCESS;
1206 }
1207
1208 Link = GetNextNode (&Storage->NameValueListHead, Link);
1209 }
1210
1211 return EFI_NOT_FOUND;
1212 }
1213
1214
1215 /**
1216 Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
1217
1218 @param Storage The Storage to be conveted.
1219 @param ConfigResp The returned <ConfigResp>.
1220 @param ConfigRequest The ConfigRequest string.
1221 @param GetEditBuf Get the data from editbuffer or buffer.
1222
1223 @retval EFI_SUCCESS Convert success.
1224 @retval EFI_INVALID_PARAMETER Incorrect storage type.
1225
1226 **/
1227 EFI_STATUS
1228 StorageToConfigResp (
1229 IN BROWSER_STORAGE *Storage,
1230 IN CHAR16 **ConfigResp,
1231 IN CHAR16 *ConfigRequest,
1232 IN BOOLEAN GetEditBuf
1233 )
1234 {
1235 EFI_STATUS Status;
1236 EFI_STRING Progress;
1237 LIST_ENTRY *Link;
1238 NAME_VALUE_NODE *Node;
1239 UINT8 *SourceBuf;
1240 FORMSET_STORAGE *FormsetStorage;
1241
1242 Status = EFI_SUCCESS;
1243
1244 switch (Storage->Type) {
1245 case EFI_HII_VARSTORE_BUFFER:
1246 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
1247 SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;
1248 Status = mHiiConfigRouting->BlockToConfig (
1249 mHiiConfigRouting,
1250 ConfigRequest,
1251 SourceBuf,
1252 Storage->Size,
1253 ConfigResp,
1254 &Progress
1255 );
1256 break;
1257
1258 case EFI_HII_VARSTORE_NAME_VALUE:
1259 *ConfigResp = NULL;
1260 FormsetStorage = GetFstStgFromBrsStg(Storage);
1261 ASSERT (FormsetStorage != NULL);
1262 NewStringCat (ConfigResp, FormsetStorage->ConfigHdr);
1263
1264 Link = GetFirstNode (&Storage->NameValueListHead);
1265 while (!IsNull (&Storage->NameValueListHead, Link)) {
1266 Node = NAME_VALUE_NODE_FROM_LINK (Link);
1267
1268 if (StrStr (ConfigRequest, Node->Name) != NULL) {
1269 NewStringCat (ConfigResp, L"&");
1270 NewStringCat (ConfigResp, Node->Name);
1271 NewStringCat (ConfigResp, L"=");
1272 if (GetEditBuf) {
1273 NewStringCat (ConfigResp, Node->EditValue);
1274 } else {
1275 NewStringCat (ConfigResp, Node->Value);
1276 }
1277 }
1278 Link = GetNextNode (&Storage->NameValueListHead, Link);
1279 }
1280 break;
1281
1282 case EFI_HII_VARSTORE_EFI_VARIABLE:
1283 default:
1284 Status = EFI_INVALID_PARAMETER;
1285 break;
1286 }
1287
1288 return Status;
1289 }
1290
1291
1292 /**
1293 Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
1294
1295 @param Storage The Storage to receive the settings.
1296 @param ConfigResp The <ConfigResp> to be converted.
1297
1298 @retval EFI_SUCCESS Convert success.
1299 @retval EFI_INVALID_PARAMETER Incorrect storage type.
1300
1301 **/
1302 EFI_STATUS
1303 ConfigRespToStorage (
1304 IN BROWSER_STORAGE *Storage,
1305 IN CHAR16 *ConfigResp
1306 )
1307 {
1308 EFI_STATUS Status;
1309 EFI_STRING Progress;
1310 UINTN BufferSize;
1311 CHAR16 *StrPtr;
1312 CHAR16 *Name;
1313 CHAR16 *Value;
1314
1315 Status = EFI_SUCCESS;
1316
1317 switch (Storage->Type) {
1318 case EFI_HII_VARSTORE_BUFFER:
1319 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
1320 BufferSize = Storage->Size;
1321 Status = mHiiConfigRouting->ConfigToBlock (
1322 mHiiConfigRouting,
1323 ConfigResp,
1324 Storage->EditBuffer,
1325 &BufferSize,
1326 &Progress
1327 );
1328 break;
1329
1330 case EFI_HII_VARSTORE_NAME_VALUE:
1331 StrPtr = StrStr (ConfigResp, L"PATH");
1332 if (StrPtr == NULL) {
1333 break;
1334 }
1335 StrPtr = StrStr (ConfigResp, L"&");
1336 while (StrPtr != NULL) {
1337 //
1338 // Skip '&'
1339 //
1340 StrPtr = StrPtr + 1;
1341 Name = StrPtr;
1342 StrPtr = StrStr (StrPtr, L"=");
1343 if (StrPtr == NULL) {
1344 break;
1345 }
1346 *StrPtr = 0;
1347
1348 //
1349 // Skip '='
1350 //
1351 StrPtr = StrPtr + 1;
1352 Value = StrPtr;
1353 StrPtr = StrStr (StrPtr, L"&");
1354 if (StrPtr != NULL) {
1355 *StrPtr = 0;
1356 }
1357 SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);
1358 }
1359 break;
1360
1361 case EFI_HII_VARSTORE_EFI_VARIABLE:
1362 default:
1363 Status = EFI_INVALID_PARAMETER;
1364 break;
1365 }
1366
1367 return Status;
1368 }
1369
1370 /**
1371 Convert the buffer value to HiiValue.
1372
1373 @param Question The question.
1374 @param Value Unicode buffer save the question value.
1375
1376 @retval Status whether convert the value success.
1377
1378 **/
1379 EFI_STATUS
1380 BufferToValue (
1381 IN OUT FORM_BROWSER_STATEMENT *Question,
1382 IN CHAR16 *Value
1383 )
1384 {
1385 CHAR16 *StringPtr;
1386 BOOLEAN IsBufferStorage;
1387 CHAR16 *DstBuf;
1388 CHAR16 TempChar;
1389 UINTN LengthStr;
1390 UINT8 *Dst;
1391 CHAR16 TemStr[5];
1392 UINTN Index;
1393 UINT8 DigitUint8;
1394 BOOLEAN IsString;
1395 UINTN Length;
1396 EFI_STATUS Status;
1397
1398 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1399 if (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1400 Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1401 IsBufferStorage = TRUE;
1402 } else {
1403 IsBufferStorage = FALSE;
1404 }
1405
1406 //
1407 // Question Value is provided by Buffer Storage or NameValue Storage
1408 //
1409 if (Question->BufferValue != NULL) {
1410 //
1411 // This Question is password or orderedlist
1412 //
1413 Dst = Question->BufferValue;
1414 } else {
1415 //
1416 // Other type of Questions
1417 //
1418 Dst = (UINT8 *) &Question->HiiValue.Value;
1419 }
1420
1421 //
1422 // Temp cut at the end of this section, end with '\0' or '&'.
1423 //
1424 StringPtr = Value;
1425 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1426 StringPtr++;
1427 }
1428 TempChar = *StringPtr;
1429 *StringPtr = L'\0';
1430
1431 LengthStr = StrLen (Value);
1432
1433 //
1434 // Value points to a Unicode hexadecimal string, we need to convert the string to the value with CHAR16/UINT8...type.
1435 // When generating the Value string, we follow this rule: 1 byte -> 2 Unicode characters (for string: 2 byte(CHAR16) ->4 Unicode characters).
1436 // So the maximum value string length of a question is : Question->StorageWidth * 2.
1437 // If the value string length > Question->StorageWidth * 2, only set the string length as Question->StorageWidth * 2, then convert.
1438 //
1439 if (LengthStr > (UINTN) Question->StorageWidth * 2) {
1440 Length = (UINTN) Question->StorageWidth * 2;
1441 } else {
1442 Length = LengthStr;
1443 }
1444
1445 Status = EFI_SUCCESS;
1446 if (!IsBufferStorage && IsString) {
1447 //
1448 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1449 // Add string tail char L'\0' into Length
1450 //
1451 DstBuf = (CHAR16 *) Dst;
1452 ZeroMem (TemStr, sizeof (TemStr));
1453 for (Index = 0; Index < Length; Index += 4) {
1454 StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4);
1455 DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1456 }
1457 //
1458 // Add tailing L'\0' character
1459 //
1460 DstBuf[Index/4] = L'\0';
1461 } else {
1462 ZeroMem (TemStr, sizeof (TemStr));
1463 for (Index = 0; Index < Length; Index ++) {
1464 TemStr[0] = Value[LengthStr - Index - 1];
1465 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1466 if ((Index & 1) == 0) {
1467 Dst [Index/2] = DigitUint8;
1468 } else {
1469 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1470 }
1471 }
1472 }
1473
1474 *StringPtr = TempChar;
1475
1476 return Status;
1477 }
1478
1479 /**
1480 Get Question's current Value.
1481
1482 @param FormSet FormSet data structure.
1483 @param Form Form data structure.
1484 @param Question Question to be initialized.
1485 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
1486
1487 @retval EFI_SUCCESS The function completed successfully.
1488
1489 **/
1490 EFI_STATUS
1491 GetQuestionValue (
1492 IN FORM_BROWSER_FORMSET *FormSet,
1493 IN FORM_BROWSER_FORM *Form,
1494 IN OUT FORM_BROWSER_STATEMENT *Question,
1495 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
1496 )
1497 {
1498 EFI_STATUS Status;
1499 BOOLEAN Enabled;
1500 BOOLEAN Pending;
1501 UINT8 *Dst;
1502 UINTN StorageWidth;
1503 EFI_TIME EfiTime;
1504 BROWSER_STORAGE *Storage;
1505 FORMSET_STORAGE *FormsetStorage;
1506 EFI_IFR_TYPE_VALUE *QuestionValue;
1507 CHAR16 *ConfigRequest;
1508 CHAR16 *Progress;
1509 CHAR16 *Result;
1510 CHAR16 *Value;
1511 UINTN Length;
1512 BOOLEAN IsBufferStorage;
1513 UINTN MaxLen;
1514
1515 Status = EFI_SUCCESS;
1516 Value = NULL;
1517 Result = NULL;
1518
1519 if (GetValueFrom >= GetSetValueWithMax) {
1520 return EFI_INVALID_PARAMETER;
1521 }
1522
1523 //
1524 // Question value is provided by an Expression, evaluate it
1525 //
1526 if (Question->ValueExpression != NULL) {
1527 Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
1528 if (!EFI_ERROR (Status)) {
1529 if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
1530 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
1531 if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
1532 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
1533 Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
1534 } else {
1535 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
1536 Question->HiiValue.BufferLen = Question->StorageWidth;
1537 }
1538 FreePool (Question->ValueExpression->Result.Buffer);
1539 }
1540 Question->HiiValue.Type = Question->ValueExpression->Result.Type;
1541 CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
1542 }
1543 return Status;
1544 }
1545
1546 //
1547 // Get question value by read expression.
1548 //
1549 if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1550 Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
1551 if (!EFI_ERROR (Status) &&
1552 ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
1553 //
1554 // Only update question value to the valid result.
1555 //
1556 if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
1557 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
1558 if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
1559 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
1560 Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
1561 } else {
1562 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
1563 Question->HiiValue.BufferLen = Question->StorageWidth;
1564 }
1565 FreePool (Question->ReadExpression->Result.Buffer);
1566 }
1567 Question->HiiValue.Type = Question->ReadExpression->Result.Type;
1568 CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
1569 return EFI_SUCCESS;
1570 }
1571 }
1572
1573 //
1574 // Question value is provided by RTC
1575 //
1576 Storage = Question->Storage;
1577 QuestionValue = &Question->HiiValue.Value;
1578 if (Storage == NULL) {
1579 //
1580 // It's a Question without storage, or RTC date/time
1581 //
1582 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1583 //
1584 // Date and time define the same Flags bit
1585 //
1586 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1587 case QF_DATE_STORAGE_TIME:
1588 Status = gRT->GetTime (&EfiTime, NULL);
1589 break;
1590
1591 case QF_DATE_STORAGE_WAKEUP:
1592 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1593 break;
1594
1595 case QF_DATE_STORAGE_NORMAL:
1596 default:
1597 //
1598 // For date/time without storage
1599 //
1600 return EFI_SUCCESS;
1601 }
1602
1603 if (EFI_ERROR (Status)) {
1604 if (Question->Operand == EFI_IFR_DATE_OP){
1605 QuestionValue->date.Year = 0xff;
1606 QuestionValue->date.Month = 0xff;
1607 QuestionValue->date.Day = 0xff;
1608 } else {
1609 QuestionValue->time.Hour = 0xff;
1610 QuestionValue->time.Minute = 0xff;
1611 QuestionValue->time.Second = 0xff;
1612 }
1613 return EFI_SUCCESS;
1614 }
1615
1616 if (Question->Operand == EFI_IFR_DATE_OP) {
1617 QuestionValue->date.Year = EfiTime.Year;
1618 QuestionValue->date.Month = EfiTime.Month;
1619 QuestionValue->date.Day = EfiTime.Day;
1620 } else {
1621 QuestionValue->time.Hour = EfiTime.Hour;
1622 QuestionValue->time.Minute = EfiTime.Minute;
1623 QuestionValue->time.Second = EfiTime.Second;
1624 }
1625 }
1626
1627 return EFI_SUCCESS;
1628 }
1629
1630 //
1631 // Question value is provided by EFI variable
1632 //
1633 StorageWidth = Question->StorageWidth;
1634 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1635 if (Question->BufferValue != NULL) {
1636 Dst = Question->BufferValue;
1637 } else {
1638 Dst = (UINT8 *) QuestionValue;
1639 }
1640
1641 Status = gRT->GetVariable (
1642 Question->VariableName,
1643 &Storage->Guid,
1644 NULL,
1645 &StorageWidth,
1646 Dst
1647 );
1648 //
1649 // Always return success, even this EFI variable doesn't exist
1650 //
1651 return EFI_SUCCESS;
1652 }
1653
1654 //
1655 // Question Value is provided by Buffer Storage or NameValue Storage
1656 //
1657 if (Question->BufferValue != NULL) {
1658 //
1659 // This Question is password or orderedlist
1660 //
1661 Dst = Question->BufferValue;
1662 } else {
1663 //
1664 // Other type of Questions
1665 //
1666 Dst = (UINT8 *) &Question->HiiValue.Value;
1667 }
1668
1669 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1670 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1671 IsBufferStorage = TRUE;
1672 } else {
1673 IsBufferStorage = FALSE;
1674 }
1675 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
1676 if (IsBufferStorage) {
1677 if (GetValueFrom == GetSetValueWithEditBuffer) {
1678 //
1679 // Copy from storage Edit buffer
1680 //
1681 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1682 } else {
1683 //
1684 // Copy from storage Edit buffer
1685 //
1686 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1687 }
1688 } else {
1689 Value = NULL;
1690 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
1691 if (EFI_ERROR (Status)) {
1692 return Status;
1693 }
1694
1695 ASSERT (Value != NULL);
1696 Status = BufferToValue (Question, Value);
1697 FreePool (Value);
1698 }
1699 } else {
1700 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
1701 ASSERT (FormsetStorage != NULL);
1702 //
1703 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
1704 // <ConfigHdr> + "&" + <VariableName>
1705 //
1706 if (IsBufferStorage) {
1707 Length = StrLen (FormsetStorage->ConfigHdr);
1708 Length += StrLen (Question->BlockName);
1709 } else {
1710 Length = StrLen (FormsetStorage->ConfigHdr);
1711 Length += StrLen (Question->VariableName) + 1;
1712 }
1713 // Allocate buffer include '\0'
1714 MaxLen = Length + 1;
1715 ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1716 ASSERT (ConfigRequest != NULL);
1717
1718 StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr);
1719 if (IsBufferStorage) {
1720 StrCatS (ConfigRequest, MaxLen, Question->BlockName);
1721 } else {
1722 StrCatS (ConfigRequest, MaxLen, L"&");
1723 StrCatS (ConfigRequest, MaxLen, Question->VariableName);
1724 }
1725
1726 //
1727 // Request current settings from Configuration Driver
1728 //
1729 Status = mHiiConfigRouting->ExtractConfig (
1730 mHiiConfigRouting,
1731 ConfigRequest,
1732 &Progress,
1733 &Result
1734 );
1735 FreePool (ConfigRequest);
1736 if (EFI_ERROR (Status)) {
1737 return Status;
1738 }
1739
1740 //
1741 // Skip <ConfigRequest>
1742 //
1743 if (IsBufferStorage) {
1744 Value = StrStr (Result, L"&VALUE");
1745 if (Value == NULL) {
1746 FreePool (Result);
1747 return EFI_NOT_FOUND;
1748 }
1749 //
1750 // Skip "&VALUE"
1751 //
1752 Value = Value + 6;
1753 } else {
1754 Value = Result + Length;
1755 }
1756 if (*Value != '=') {
1757 FreePool (Result);
1758 return EFI_NOT_FOUND;
1759 }
1760 //
1761 // Skip '=', point to value
1762 //
1763 Value = Value + 1;
1764
1765 Status = BufferToValue (Question, Value);
1766 if (EFI_ERROR (Status)) {
1767 FreePool (Result);
1768 return Status;
1769 }
1770
1771 //
1772 // Synchronize Edit Buffer
1773 //
1774 if (IsBufferStorage) {
1775 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
1776 } else {
1777 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);
1778 }
1779
1780 if (Result != NULL) {
1781 FreePool (Result);
1782 }
1783 }
1784
1785 return Status;
1786 }
1787
1788
1789 /**
1790 Save Question Value to edit copy(cached) or Storage(uncached).
1791
1792 @param FormSet FormSet data structure.
1793 @param Form Form data structure.
1794 @param Question Pointer to the Question.
1795 @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
1796
1797 @retval EFI_SUCCESS The function completed successfully.
1798
1799 **/
1800 EFI_STATUS
1801 SetQuestionValue (
1802 IN FORM_BROWSER_FORMSET *FormSet,
1803 IN FORM_BROWSER_FORM *Form,
1804 IN OUT FORM_BROWSER_STATEMENT *Question,
1805 IN GET_SET_QUESTION_VALUE_WITH SetValueTo
1806 )
1807 {
1808 EFI_STATUS Status;
1809 BOOLEAN Enabled;
1810 BOOLEAN Pending;
1811 UINT8 *Src;
1812 EFI_TIME EfiTime;
1813 UINTN BufferLen;
1814 UINTN StorageWidth;
1815 BROWSER_STORAGE *Storage;
1816 FORMSET_STORAGE *FormsetStorage;
1817 EFI_IFR_TYPE_VALUE *QuestionValue;
1818 CHAR16 *ConfigResp;
1819 CHAR16 *Progress;
1820 CHAR16 *Value;
1821 UINTN Length;
1822 BOOLEAN IsBufferStorage;
1823 BOOLEAN IsString;
1824 UINT8 *TemBuffer;
1825 CHAR16 *TemName;
1826 CHAR16 *TemString;
1827 UINTN Index;
1828 NAME_VALUE_NODE *Node;
1829 UINTN MaxLen;
1830
1831 Status = EFI_SUCCESS;
1832 Node = NULL;
1833
1834 if (SetValueTo >= GetSetValueWithMax) {
1835 return EFI_INVALID_PARAMETER;
1836 }
1837
1838 //
1839 // If Question value is provided by an Expression, then it is read only
1840 //
1841 if (Question->ValueExpression != NULL) {
1842 return Status;
1843 }
1844
1845 //
1846 // Before set question value, evaluate its write expression.
1847 //
1848 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1849 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
1850 if (EFI_ERROR (Status)) {
1851 return Status;
1852 }
1853 }
1854
1855 //
1856 // Question value is provided by RTC
1857 //
1858 Storage = Question->Storage;
1859 QuestionValue = &Question->HiiValue.Value;
1860 if (Storage == NULL) {
1861 //
1862 // It's a Question without storage, or RTC date/time
1863 //
1864 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1865 //
1866 // Date and time define the same Flags bit
1867 //
1868 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1869 case QF_DATE_STORAGE_TIME:
1870 Status = gRT->GetTime (&EfiTime, NULL);
1871 break;
1872
1873 case QF_DATE_STORAGE_WAKEUP:
1874 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1875 break;
1876
1877 case QF_DATE_STORAGE_NORMAL:
1878 default:
1879 //
1880 // For date/time without storage
1881 //
1882 return EFI_SUCCESS;
1883 }
1884
1885 if (EFI_ERROR (Status)) {
1886 return Status;
1887 }
1888
1889 if (Question->Operand == EFI_IFR_DATE_OP) {
1890 EfiTime.Year = QuestionValue->date.Year;
1891 EfiTime.Month = QuestionValue->date.Month;
1892 EfiTime.Day = QuestionValue->date.Day;
1893 } else {
1894 EfiTime.Hour = QuestionValue->time.Hour;
1895 EfiTime.Minute = QuestionValue->time.Minute;
1896 EfiTime.Second = QuestionValue->time.Second;
1897 }
1898
1899 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
1900 Status = gRT->SetTime (&EfiTime);
1901 } else {
1902 Status = gRT->SetWakeupTime (TRUE, &EfiTime);
1903 }
1904 }
1905
1906 return Status;
1907 }
1908
1909 //
1910 // Question value is provided by EFI variable
1911 //
1912 StorageWidth = Question->StorageWidth;
1913 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1914 if (Question->BufferValue != NULL) {
1915 Src = Question->BufferValue;
1916 } else {
1917 Src = (UINT8 *) QuestionValue;
1918 }
1919
1920 Status = gRT->SetVariable (
1921 Question->VariableName,
1922 &Storage->Guid,
1923 Storage->Attributes,
1924 StorageWidth,
1925 Src
1926 );
1927 return Status;
1928 }
1929
1930 //
1931 // Question Value is provided by Buffer Storage or NameValue Storage
1932 //
1933 if (Question->BufferValue != NULL) {
1934 Src = Question->BufferValue;
1935 } else {
1936 Src = (UINT8 *) &Question->HiiValue.Value;
1937 }
1938
1939 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1940 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1941 IsBufferStorage = TRUE;
1942 } else {
1943 IsBufferStorage = FALSE;
1944 }
1945 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1946
1947 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
1948 if (IsBufferStorage) {
1949 if (SetValueTo == GetSetValueWithEditBuffer) {
1950 //
1951 // Copy to storage edit buffer
1952 //
1953 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1954 } else if (SetValueTo == GetSetValueWithBuffer) {
1955 //
1956 // Copy to storage edit buffer
1957 //
1958 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1959 }
1960 } else {
1961 if (IsString) {
1962 //
1963 // Allocate enough string buffer.
1964 //
1965 Value = NULL;
1966 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
1967 Value = AllocateZeroPool (BufferLen);
1968 ASSERT (Value != NULL);
1969 //
1970 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1971 //
1972 TemName = (CHAR16 *) Src;
1973 TemString = Value;
1974 for (; *TemName != L'\0'; TemName++) {
1975 UnicodeValueToStringS (
1976 TemString,
1977 BufferLen - ((UINTN)TemString - (UINTN)Value),
1978 PREFIX_ZERO | RADIX_HEX,
1979 *TemName,
1980 4
1981 );
1982 TemString += StrnLenS (TemString, (BufferLen - ((UINTN)TemString - (UINTN)Value)) / sizeof (CHAR16));
1983 }
1984 } else {
1985 BufferLen = StorageWidth * 2 + 1;
1986 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
1987 ASSERT (Value != NULL);
1988 //
1989 // Convert Buffer to Hex String
1990 //
1991 TemBuffer = Src + StorageWidth - 1;
1992 TemString = Value;
1993 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1994 UnicodeValueToStringS (
1995 TemString,
1996 BufferLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)Value),
1997 PREFIX_ZERO | RADIX_HEX,
1998 *TemBuffer,
1999 2
2000 );
2001 TemString += StrnLenS (TemString, BufferLen - ((UINTN)TemString - (UINTN)Value) / sizeof (CHAR16));
2002 }
2003 }
2004
2005 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);
2006 FreePool (Value);
2007 if (EFI_ERROR (Status)) {
2008 return Status;
2009 }
2010 }
2011 } else if (SetValueTo == GetSetValueWithHiiDriver) {
2012 //
2013 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
2014 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
2015 //
2016 if (IsBufferStorage) {
2017 Length = StrLen (Question->BlockName) + 7;
2018 } else {
2019 Length = StrLen (Question->VariableName) + 2;
2020 }
2021 if (!IsBufferStorage && IsString) {
2022 Length += (StrLen ((CHAR16 *) Src) * 4);
2023 } else {
2024 Length += (StorageWidth * 2);
2025 }
2026 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId);
2027 ASSERT (FormsetStorage != NULL);
2028 MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1;
2029 ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16));
2030 ASSERT (ConfigResp != NULL);
2031
2032 StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr);
2033 if (IsBufferStorage) {
2034 StrCatS (ConfigResp, MaxLen, Question->BlockName);
2035 StrCatS (ConfigResp, MaxLen, L"&VALUE=");
2036 } else {
2037 StrCatS (ConfigResp, MaxLen, L"&");
2038 StrCatS (ConfigResp, MaxLen, Question->VariableName);
2039 StrCatS (ConfigResp, MaxLen, L"=");
2040 }
2041
2042 Value = ConfigResp + StrLen (ConfigResp);
2043
2044 if (!IsBufferStorage && IsString) {
2045 //
2046 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
2047 //
2048 TemName = (CHAR16 *) Src;
2049 TemString = Value;
2050 for (; *TemName != L'\0'; TemName++) {
2051 UnicodeValueToStringS (
2052 TemString,
2053 MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp),
2054 PREFIX_ZERO | RADIX_HEX,
2055 *TemName,
2056 4
2057 );
2058 TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16));
2059 }
2060 } else {
2061 //
2062 // Convert Buffer to Hex String
2063 //
2064 TemBuffer = Src + StorageWidth - 1;
2065 TemString = Value;
2066 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
2067 UnicodeValueToStringS (
2068 TemString,
2069 MaxLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ConfigResp),
2070 PREFIX_ZERO | RADIX_HEX,
2071 *TemBuffer,
2072 2
2073 );
2074 TemString += StrnLenS (TemString, MaxLen - ((UINTN)TemString - (UINTN)ConfigResp) / sizeof (CHAR16));
2075 }
2076 }
2077
2078 //
2079 // Convert to lower char.
2080 //
2081 for (TemString = Value; *Value != L'\0'; Value++) {
2082 if (*Value >= L'A' && *Value <= L'Z') {
2083 *Value = (CHAR16) (*Value - L'A' + L'a');
2084 }
2085 }
2086
2087 //
2088 // Submit Question Value to Configuration Driver
2089 //
2090 Status = mHiiConfigRouting->RouteConfig (
2091 mHiiConfigRouting,
2092 ConfigResp,
2093 &Progress
2094 );
2095 if (EFI_ERROR (Status)) {
2096 FreePool (ConfigResp);
2097 return Status;
2098 }
2099 FreePool (ConfigResp);
2100
2101 //
2102 // Sync storage, from editbuffer to buffer.
2103 //
2104 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
2105 }
2106
2107 return Status;
2108 }
2109
2110
2111 /**
2112 Perform nosubmitif check for a Form.
2113
2114 @param FormSet FormSet data structure.
2115 @param Form Form data structure.
2116 @param Question The Question to be validated.
2117 @param Type Validation type: NoSubmit
2118
2119 @retval EFI_SUCCESS Form validation pass.
2120 @retval other Form validation failed.
2121
2122 **/
2123 EFI_STATUS
2124 ValidateQuestion (
2125 IN FORM_BROWSER_FORMSET *FormSet,
2126 IN FORM_BROWSER_FORM *Form,
2127 IN FORM_BROWSER_STATEMENT *Question,
2128 IN UINTN Type
2129 )
2130 {
2131 EFI_STATUS Status;
2132 LIST_ENTRY *Link;
2133 LIST_ENTRY *ListHead;
2134 FORM_EXPRESSION *Expression;
2135 UINT32 BrowserStatus;
2136 CHAR16 *ErrorStr;
2137
2138 BrowserStatus = BROWSER_SUCCESS;
2139 ErrorStr = NULL;
2140
2141 switch (Type) {
2142 case EFI_HII_EXPRESSION_INCONSISTENT_IF:
2143 ListHead = &Question->InconsistentListHead;
2144 break;
2145
2146 case EFI_HII_EXPRESSION_WARNING_IF:
2147 ListHead = &Question->WarningListHead;
2148 break;
2149
2150 case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
2151 ListHead = &Question->NoSubmitListHead;
2152 break;
2153
2154 default:
2155 ASSERT (FALSE);
2156 return EFI_UNSUPPORTED;
2157 }
2158
2159 Link = GetFirstNode (ListHead);
2160 while (!IsNull (ListHead, Link)) {
2161 Expression = FORM_EXPRESSION_FROM_LINK (Link);
2162
2163 //
2164 // Evaluate the expression
2165 //
2166 Status = EvaluateExpression (FormSet, Form, Expression);
2167 if (EFI_ERROR (Status)) {
2168 return Status;
2169 }
2170
2171 if (IsTrue (&Expression->Result)) {
2172 switch (Type) {
2173 case EFI_HII_EXPRESSION_INCONSISTENT_IF:
2174 BrowserStatus = BROWSER_INCONSISTENT_IF;
2175 break;
2176
2177 case EFI_HII_EXPRESSION_WARNING_IF:
2178 BrowserStatus = BROWSER_WARNING_IF;
2179 break;
2180
2181 case EFI_HII_EXPRESSION_NO_SUBMIT_IF:
2182 BrowserStatus = BROWSER_NO_SUBMIT_IF;
2183 //
2184 // This code only used to compatible with old display engine,
2185 // New display engine will not use this field.
2186 //
2187 if (Expression->Error != 0) {
2188 ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle);
2189 }
2190 break;
2191
2192 default:
2193 ASSERT (FALSE);
2194 break;
2195 }
2196
2197 if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) {
2198 //
2199 // If in system submit process and for no_submit_if check, not popup this error message.
2200 // Will process this fail again later in not system submit process.
2201 //
2202 PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr);
2203 }
2204
2205 if (ErrorStr != NULL) {
2206 FreePool (ErrorStr);
2207 }
2208
2209 if (Type == EFI_HII_EXPRESSION_WARNING_IF) {
2210 return EFI_SUCCESS;
2211 } else {
2212 return EFI_NOT_READY;
2213 }
2214 }
2215
2216 Link = GetNextNode (ListHead, Link);
2217 }
2218
2219 return EFI_SUCCESS;
2220 }
2221
2222 /**
2223 Perform question check.
2224
2225 If one question has more than one check, process form high priority to low.
2226 Only one error info will be popup.
2227
2228 @param FormSet FormSet data structure.
2229 @param Form Form data structure.
2230 @param Question The Question to be validated.
2231
2232 @retval EFI_SUCCESS Form validation pass.
2233 @retval other Form validation failed.
2234
2235 **/
2236 EFI_STATUS
2237 ValueChangedValidation (
2238 IN FORM_BROWSER_FORMSET *FormSet,
2239 IN FORM_BROWSER_FORM *Form,
2240 IN FORM_BROWSER_STATEMENT *Question
2241 )
2242 {
2243 EFI_STATUS Status;
2244
2245 Status = EFI_SUCCESS;
2246
2247 //
2248 // Do the inconsistentif check.
2249 //
2250 if (!IsListEmpty (&Question->InconsistentListHead)) {
2251 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
2252 if (EFI_ERROR (Status)) {
2253 return Status;
2254 }
2255 }
2256
2257 //
2258 // Do the warningif check.
2259 //
2260 if (!IsListEmpty (&Question->WarningListHead)) {
2261 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF);
2262 }
2263
2264 return Status;
2265 }
2266
2267 /**
2268 Perform NoSubmit check for each Form in FormSet.
2269
2270 @param FormSet FormSet data structure.
2271 @param CurrentForm Current input form data structure.
2272 @param Statement The statement for this check.
2273
2274 @retval EFI_SUCCESS Form validation pass.
2275 @retval other Form validation failed.
2276
2277 **/
2278 EFI_STATUS
2279 NoSubmitCheck (
2280 IN FORM_BROWSER_FORMSET *FormSet,
2281 IN OUT FORM_BROWSER_FORM **CurrentForm,
2282 OUT FORM_BROWSER_STATEMENT **Statement
2283 )
2284 {
2285 EFI_STATUS Status;
2286 LIST_ENTRY *Link;
2287 FORM_BROWSER_STATEMENT *Question;
2288 FORM_BROWSER_FORM *Form;
2289 LIST_ENTRY *LinkForm;
2290
2291 LinkForm = GetFirstNode (&FormSet->FormListHead);
2292 while (!IsNull (&FormSet->FormListHead, LinkForm)) {
2293 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
2294 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
2295
2296 if (*CurrentForm != NULL && *CurrentForm != Form) {
2297 continue;
2298 }
2299
2300 Link = GetFirstNode (&Form->StatementListHead);
2301 while (!IsNull (&Form->StatementListHead, Link)) {
2302 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2303 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
2304 if (EFI_ERROR (Status)) {
2305 if (*CurrentForm == NULL) {
2306 *CurrentForm = Form;
2307 }
2308 if (Statement != NULL) {
2309 *Statement = Question;
2310 }
2311 return Status;
2312 }
2313
2314 Link = GetNextNode (&Form->StatementListHead, Link);
2315 }
2316 }
2317
2318 return EFI_SUCCESS;
2319 }
2320
2321 /**
2322 Fill storage's edit copy with settings requested from Configuration Driver.
2323
2324 @param Storage The storage which need to sync.
2325 @param ConfigRequest The config request string which used to sync storage.
2326 @param SyncOrRestore Sync the buffer to editbuffer or Restore the
2327 editbuffer to buffer
2328 if TRUE, copy the editbuffer to the buffer.
2329 if FALSE, copy the buffer to the editbuffer.
2330
2331 @retval EFI_SUCCESS The function completed successfully.
2332
2333 **/
2334 EFI_STATUS
2335 SynchronizeStorage (
2336 OUT BROWSER_STORAGE *Storage,
2337 IN CHAR16 *ConfigRequest,
2338 IN BOOLEAN SyncOrRestore
2339 )
2340 {
2341 EFI_STATUS Status;
2342 EFI_STRING Progress;
2343 EFI_STRING Result;
2344 UINTN BufferSize;
2345 LIST_ENTRY *Link;
2346 NAME_VALUE_NODE *Node;
2347 UINT8 *Src;
2348 UINT8 *Dst;
2349
2350 Status = EFI_SUCCESS;
2351 Result = NULL;
2352
2353 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2354 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2355 BufferSize = Storage->Size;
2356
2357 if (SyncOrRestore) {
2358 Src = Storage->EditBuffer;
2359 Dst = Storage->Buffer;
2360 } else {
2361 Src = Storage->Buffer;
2362 Dst = Storage->EditBuffer;
2363 }
2364
2365 if (ConfigRequest != NULL) {
2366 Status = mHiiConfigRouting->BlockToConfig(
2367 mHiiConfigRouting,
2368 ConfigRequest,
2369 Src,
2370 BufferSize,
2371 &Result,
2372 &Progress
2373 );
2374 if (EFI_ERROR (Status)) {
2375 return Status;
2376 }
2377
2378 Status = mHiiConfigRouting->ConfigToBlock (
2379 mHiiConfigRouting,
2380 Result,
2381 Dst,
2382 &BufferSize,
2383 &Progress
2384 );
2385 if (Result != NULL) {
2386 FreePool (Result);
2387 }
2388 } else {
2389 CopyMem (Dst, Src, BufferSize);
2390 }
2391 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2392 Link = GetFirstNode (&Storage->NameValueListHead);
2393 while (!IsNull (&Storage->NameValueListHead, Link)) {
2394 Node = NAME_VALUE_NODE_FROM_LINK (Link);
2395
2396 if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||
2397 (ConfigRequest == NULL)) {
2398 if (SyncOrRestore) {
2399 NewStringCpy (&Node->Value, Node->EditValue);
2400 } else {
2401 NewStringCpy (&Node->EditValue, Node->Value);
2402 }
2403 }
2404
2405 Link = GetNextNode (&Storage->NameValueListHead, Link);
2406 }
2407 }
2408
2409 return Status;
2410 }
2411
2412 /**
2413 When discard the question value, call the callback function with Changed type
2414 to inform the hii driver.
2415
2416 @param FormSet FormSet data structure.
2417 @param Form Form data structure.
2418
2419 **/
2420 VOID
2421 SendDiscardInfoToDriver (
2422 IN FORM_BROWSER_FORMSET *FormSet,
2423 IN FORM_BROWSER_FORM *Form
2424 )
2425 {
2426 LIST_ENTRY *Link;
2427 FORM_BROWSER_STATEMENT *Question;
2428 EFI_IFR_TYPE_VALUE *TypeValue;
2429 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2430
2431 if (FormSet->ConfigAccess == NULL) {
2432 return;
2433 }
2434
2435 Link = GetFirstNode (&Form->StatementListHead);
2436 while (!IsNull (&Form->StatementListHead, Link)) {
2437 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2438 Link = GetNextNode (&Form->StatementListHead, Link);
2439
2440 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2441 continue;
2442 }
2443
2444 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2445 continue;
2446 }
2447
2448 if (Question->Operand == EFI_IFR_PASSWORD_OP) {
2449 continue;
2450 }
2451
2452 if (!Question->ValueChanged) {
2453 continue;
2454 }
2455
2456 //
2457 // Restore the question value before call the CHANGED callback type.
2458 //
2459 GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
2460
2461 if (Question->Operand == EFI_IFR_STRING_OP){
2462 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
2463 }
2464
2465 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
2466 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
2467 } else {
2468 TypeValue = &Question->HiiValue.Value;
2469 }
2470
2471 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2472 FormSet->ConfigAccess->Callback (
2473 FormSet->ConfigAccess,
2474 EFI_BROWSER_ACTION_CHANGED,
2475 Question->QuestionId,
2476 Question->HiiValue.Type,
2477 TypeValue,
2478 &ActionRequest
2479 );
2480 }
2481 }
2482
2483 /**
2484 When submit the question value, call the callback function with Submitted type
2485 to inform the hii driver.
2486
2487 @param FormSet FormSet data structure.
2488 @param Form Form data structure.
2489
2490 **/
2491 VOID
2492 SubmitCallbackForForm (
2493 IN FORM_BROWSER_FORMSET *FormSet,
2494 IN FORM_BROWSER_FORM *Form
2495 )
2496 {
2497 LIST_ENTRY *Link;
2498 FORM_BROWSER_STATEMENT *Question;
2499 EFI_IFR_TYPE_VALUE *TypeValue;
2500 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2501
2502 if (FormSet->ConfigAccess == NULL) {
2503 return;
2504 }
2505
2506 Link = GetFirstNode (&Form->StatementListHead);
2507 while (!IsNull (&Form->StatementListHead, Link)) {
2508 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2509 Link = GetNextNode (&Form->StatementListHead, Link);
2510
2511 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2512 continue;
2513 }
2514
2515 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
2516 continue;
2517 }
2518
2519 if (Question->Operand == EFI_IFR_PASSWORD_OP) {
2520 continue;
2521 }
2522
2523 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
2524 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
2525 } else {
2526 TypeValue = &Question->HiiValue.Value;
2527 }
2528
2529 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2530 FormSet->ConfigAccess->Callback (
2531 FormSet->ConfigAccess,
2532 EFI_BROWSER_ACTION_SUBMITTED,
2533 Question->QuestionId,
2534 Question->HiiValue.Type,
2535 TypeValue,
2536 &ActionRequest
2537 );
2538 }
2539 }
2540
2541 /**
2542 When value set Success, call the submit callback function.
2543
2544 @param FormSet FormSet data structure.
2545 @param Form Form data structure.
2546
2547 **/
2548 VOID
2549 SubmitCallback (
2550 IN FORM_BROWSER_FORMSET *FormSet,
2551 IN FORM_BROWSER_FORM *Form
2552 )
2553 {
2554 FORM_BROWSER_FORM *CurrentForm;
2555 LIST_ENTRY *Link;
2556
2557 if (Form != NULL) {
2558 SubmitCallbackForForm(FormSet, Form);
2559 return;
2560 }
2561
2562 Link = GetFirstNode (&FormSet->FormListHead);
2563 while (!IsNull (&FormSet->FormListHead, Link)) {
2564 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
2565 Link = GetNextNode (&FormSet->FormListHead, Link);
2566
2567 SubmitCallbackForForm(FormSet, CurrentForm);
2568 }
2569 }
2570
2571 /**
2572 Validate the HiiHandle.
2573
2574 @param HiiHandle The input HiiHandle which need to validate.
2575
2576 @retval TRUE The handle is validate.
2577 @retval FALSE The handle is invalidate.
2578
2579 **/
2580 BOOLEAN
2581 ValidateHiiHandle (
2582 EFI_HII_HANDLE HiiHandle
2583 )
2584 {
2585 EFI_HII_HANDLE *HiiHandles;
2586 UINTN Index;
2587 BOOLEAN Find;
2588
2589 if (HiiHandle == NULL) {
2590 return FALSE;
2591 }
2592
2593 Find = FALSE;
2594
2595 HiiHandles = HiiGetHiiHandles (NULL);
2596 ASSERT (HiiHandles != NULL);
2597
2598 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
2599 if (HiiHandles[Index] == HiiHandle) {
2600 Find = TRUE;
2601 break;
2602 }
2603 }
2604
2605 FreePool (HiiHandles);
2606
2607 return Find;
2608 }
2609
2610 /**
2611 Validate the FormSet. If the formset is not validate, remove it from the list.
2612
2613 @param FormSet The input FormSet which need to validate.
2614
2615 @retval TRUE The handle is validate.
2616 @retval FALSE The handle is invalidate.
2617
2618 **/
2619 BOOLEAN
2620 ValidateFormSet (
2621 FORM_BROWSER_FORMSET *FormSet
2622 )
2623 {
2624 BOOLEAN Find;
2625
2626 ASSERT (FormSet != NULL);
2627
2628 Find = ValidateHiiHandle(FormSet->HiiHandle);
2629 //
2630 // Should not remove the formset which is being used.
2631 //
2632 if (!Find && (FormSet != gCurrentSelection->FormSet)) {
2633 CleanBrowserStorage(FormSet);
2634 RemoveEntryList (&FormSet->Link);
2635 DestroyFormSet (FormSet);
2636 }
2637
2638 return Find;
2639 }
2640 /**
2641 Check whether need to enable the reset flag in form level.
2642 Also clean all ValueChanged flag in question.
2643
2644 @param SetFlag Whether need to set the Reset Flag.
2645 @param FormSet FormSet data structure.
2646 @param Form Form data structure.
2647
2648 **/
2649 VOID
2650 UpdateFlagForForm (
2651 IN BOOLEAN SetFlag,
2652 IN FORM_BROWSER_FORMSET *FormSet,
2653 IN FORM_BROWSER_FORM *Form
2654 )
2655 {
2656 LIST_ENTRY *Link;
2657 FORM_BROWSER_STATEMENT *Question;
2658 BOOLEAN OldValue;
2659
2660 Link = GetFirstNode (&Form->StatementListHead);
2661 while (!IsNull (&Form->StatementListHead, Link)) {
2662 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2663 Link = GetNextNode (&Form->StatementListHead, Link);
2664
2665 if (!Question->ValueChanged) {
2666 continue;
2667 }
2668
2669 OldValue = Question->ValueChanged;
2670
2671 //
2672 // Compare the buffer and editbuffer data to see whether the data has been saved.
2673 //
2674 Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer);
2675
2676 //
2677 // Only the changed data has been saved, then need to set the reset flag.
2678 //
2679 if (SetFlag && OldValue && !Question->ValueChanged) {
2680 if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
2681 gResetRequired = TRUE;
2682 }
2683
2684 if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
2685 gFlagReconnect = TRUE;
2686 }
2687 }
2688 }
2689 }
2690
2691 /**
2692 Check whether need to enable the reset flag.
2693 Also clean ValueChanged flag for all statements.
2694
2695 Form level or formset level, only one.
2696
2697 @param SetFlag Whether need to set the Reset Flag.
2698 @param FormSet FormSet data structure.
2699 @param Form Form data structure.
2700
2701 **/
2702 VOID
2703 ValueChangeResetFlagUpdate (
2704 IN BOOLEAN SetFlag,
2705 IN FORM_BROWSER_FORMSET *FormSet,
2706 IN FORM_BROWSER_FORM *Form
2707 )
2708 {
2709 FORM_BROWSER_FORM *CurrentForm;
2710 LIST_ENTRY *Link;
2711
2712 if (Form != NULL) {
2713 UpdateFlagForForm(SetFlag, FormSet, Form);
2714 return;
2715 }
2716
2717 Link = GetFirstNode (&FormSet->FormListHead);
2718 while (!IsNull (&FormSet->FormListHead, Link)) {
2719 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);
2720 Link = GetNextNode (&FormSet->FormListHead, Link);
2721
2722 UpdateFlagForForm(SetFlag, FormSet, CurrentForm);
2723 }
2724 }
2725
2726 /**
2727 Base on the return Progress string to find the form.
2728
2729 Base on the first return Offset/Width (Name) string to find the form
2730 which keep this string.
2731
2732 @param FormSet FormSet data structure.
2733 @param Storage Storage which has this Progress string.
2734 @param Progress The Progress string which has the first fail string.
2735 @param RetForm The return form for this progress string.
2736 @param RetQuestion The return question for the error progress string.
2737
2738 @retval TRUE Find the error form and statement for this error progress string.
2739 @retval FALSE Not find the error form.
2740
2741 **/
2742 BOOLEAN
2743 FindQuestionFromProgress (
2744 IN FORM_BROWSER_FORMSET *FormSet,
2745 IN BROWSER_STORAGE *Storage,
2746 IN EFI_STRING Progress,
2747 OUT FORM_BROWSER_FORM **RetForm,
2748 OUT FORM_BROWSER_STATEMENT **RetQuestion
2749 )
2750 {
2751 LIST_ENTRY *Link;
2752 LIST_ENTRY *LinkStorage;
2753 LIST_ENTRY *LinkStatement;
2754 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2755 FORM_BROWSER_FORM *Form;
2756 EFI_STRING EndStr;
2757 FORM_BROWSER_STATEMENT *Statement;
2758
2759 ASSERT ((*Progress == '&') || (*Progress == 'G'));
2760
2761 ConfigInfo = NULL;
2762 *RetForm = NULL;
2763 *RetQuestion = NULL;
2764
2765 //
2766 // Skip the first "&" or the ConfigHdr part.
2767 //
2768 if (*Progress == '&') {
2769 Progress++;
2770 } else {
2771 //
2772 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2773 //
2774 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2775 //
2776 // For Name/Value type, Skip the ConfigHdr part.
2777 //
2778 EndStr = StrStr (Progress, L"PATH=");
2779 ASSERT (EndStr != NULL);
2780 while (*EndStr != '&') {
2781 EndStr++;
2782 }
2783
2784 *EndStr = '\0';
2785 } else {
2786 //
2787 // For Buffer type, Skip the ConfigHdr part.
2788 //
2789 EndStr = StrStr (Progress, L"&OFFSET=");
2790 ASSERT (EndStr != NULL);
2791 *EndStr = '\0';
2792 }
2793
2794 Progress = EndStr + 1;
2795 }
2796
2797 //
2798 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2799 //
2800 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2801 //
2802 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
2803 // here, just keep the "Fred" string.
2804 //
2805 EndStr = StrStr (Progress, L"=");
2806 ASSERT (EndStr != NULL);
2807 *EndStr = '\0';
2808 } else {
2809 //
2810 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
2811 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
2812 //
2813 EndStr = StrStr (Progress, L"&VALUE=");
2814 ASSERT (EndStr != NULL);
2815 *EndStr = '\0';
2816 }
2817
2818 //
2819 // Search in the form list.
2820 //
2821 Link = GetFirstNode (&FormSet->FormListHead);
2822 while (!IsNull (&FormSet->FormListHead, Link)) {
2823 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2824 Link = GetNextNode (&FormSet->FormListHead, Link);
2825
2826 //
2827 // Search in the ConfigReqeust list in this form.
2828 //
2829 LinkStorage = GetFirstNode (&Form->ConfigRequestHead);
2830 while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) {
2831 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage);
2832 LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage);
2833
2834 if (Storage != ConfigInfo->Storage) {
2835 continue;
2836 }
2837
2838 if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) {
2839 //
2840 // Find the OffsetWidth string in this form.
2841 //
2842 *RetForm = Form;
2843 break;
2844 }
2845 }
2846
2847 if (*RetForm != NULL) {
2848 LinkStatement = GetFirstNode (&Form->StatementListHead);
2849 while (!IsNull (&Form->StatementListHead, LinkStatement)) {
2850 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement);
2851 LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement);
2852
2853 if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) {
2854 *RetQuestion = Statement;
2855 break;
2856 }
2857
2858 if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) {
2859 *RetQuestion = Statement;
2860 break;
2861 }
2862 }
2863 }
2864
2865 if (*RetForm != NULL) {
2866 break;
2867 }
2868 }
2869
2870 //
2871 // restore the OffsetWidth string to the original format.
2872 //
2873 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2874 *EndStr = '=';
2875 } else {
2876 *EndStr = '&';
2877 }
2878
2879 return (BOOLEAN) (*RetForm != NULL);
2880 }
2881
2882 /**
2883 Base on the return Progress string to get the SyncConfigRequest and RestoreConfigRequest
2884 for form and formset.
2885
2886 @param Storage Storage which has this Progress string.
2887 @param ConfigRequest The ConfigRequest string.
2888 @param Progress The Progress string which has the first fail string.
2889 @param RestoreConfigRequest Return the RestoreConfigRequest string.
2890 @param SyncConfigRequest Return the SyncConfigRequest string.
2891
2892 **/
2893 VOID
2894 GetSyncRestoreConfigRequest(
2895 IN BROWSER_STORAGE *Storage,
2896 IN EFI_STRING ConfigRequest,
2897 IN EFI_STRING Progress,
2898 OUT EFI_STRING *RestoreConfigRequest,
2899 OUT EFI_STRING *SyncConfigRequest
2900 )
2901 {
2902 EFI_STRING EndStr;
2903 EFI_STRING ConfigHdrEndStr;
2904 EFI_STRING ElementStr;
2905 UINTN TotalSize;
2906 UINTN RestoreEleSize;
2907 UINTN SyncSize;
2908
2909 ASSERT ((*Progress == L'&') || (*Progress == L'G'));
2910 //
2911 // If the Progress starts with ConfigHdr, means the failure is in the first name / value pair.
2912 // Need to restore all the fields in the ConfigRequest.
2913 //
2914 if (*Progress == L'G') {
2915 *RestoreConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
2916 ASSERT (*RestoreConfigRequest != NULL);
2917 return;
2918 }
2919
2920 //
2921 // Find the first fail "NAME" or "OFFSET=0x####&WIDTH=0x####" string.
2922 //
2923 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2924 //
2925 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset,
2926 // here, just keep the "Fred" string.
2927 //
2928 EndStr = StrStr (Progress, L"=");
2929 ASSERT (EndStr != NULL);
2930 *EndStr = L'\0';
2931 //
2932 // Find the ConfigHdr in ConfigRequest.
2933 //
2934 ConfigHdrEndStr = StrStr (ConfigRequest, L"PATH=");
2935 ASSERT (ConfigHdrEndStr != NULL);
2936 while (*ConfigHdrEndStr != L'&') {
2937 ConfigHdrEndStr++;
2938 }
2939 } else {
2940 //
2941 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####",
2942 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string.
2943 //
2944 EndStr = StrStr (Progress, L"&VALUE=");
2945 ASSERT (EndStr != NULL);
2946 *EndStr = L'\0';
2947 //
2948 // Find the ConfigHdr in ConfigRequest.
2949 //
2950 ConfigHdrEndStr = StrStr (ConfigRequest, L"&OFFSET=");
2951 }
2952 //
2953 // Find the first fail pair in the ConfigRequest.
2954 //
2955 ElementStr = StrStr (ConfigRequest, Progress);
2956 ASSERT (ElementStr != NULL);
2957 //
2958 // To get the RestoreConfigRequest.
2959 //
2960 RestoreEleSize = StrSize (ElementStr);
2961 TotalSize = (ConfigHdrEndStr - ConfigRequest) * sizeof (CHAR16) + RestoreEleSize + sizeof (CHAR16);
2962 *RestoreConfigRequest = AllocateZeroPool (TotalSize);
2963 ASSERT (*RestoreConfigRequest != NULL);
2964 StrnCpyS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ConfigRequest, ConfigHdrEndStr - ConfigRequest);
2965 StrCatS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ElementStr);
2966 //
2967 // To get the SyncConfigRequest.
2968 //
2969 SyncSize = StrSize (ConfigRequest) - RestoreEleSize + sizeof (CHAR16);
2970 *SyncConfigRequest = AllocateZeroPool (SyncSize);
2971 ASSERT (*SyncConfigRequest != NULL);
2972 StrnCpyS (*SyncConfigRequest, SyncSize / sizeof (CHAR16), ConfigRequest, SyncSize / sizeof (CHAR16) - 1);
2973
2974 //
2975 // restore the Progress string to the original format.
2976 //
2977 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2978 *EndStr = L'=';
2979 } else {
2980 *EndStr = L'&';
2981 }
2982 }
2983
2984 /**
2985 Popup an save error info and get user input.
2986
2987 @param TitleId The form title id.
2988 @param HiiHandle The hii handle for this package.
2989
2990 @retval UINT32 The user select option for the save fail.
2991 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
2992 **/
2993 UINT32
2994 ConfirmSaveFail (
2995 IN EFI_STRING_ID TitleId,
2996 IN EFI_HII_HANDLE HiiHandle
2997 )
2998 {
2999 CHAR16 *FormTitle;
3000 CHAR16 *StringBuffer;
3001 UINT32 RetVal;
3002
3003 FormTitle = GetToken (TitleId, HiiHandle);
3004
3005 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
3006 ASSERT (StringBuffer != NULL);
3007
3008 UnicodeSPrint (
3009 StringBuffer,
3010 24 * sizeof (CHAR16) + StrSize (FormTitle),
3011 L"Submit Fail For Form: %s.",
3012 FormTitle
3013 );
3014
3015 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer);
3016
3017 FreePool (StringBuffer);
3018 FreePool (FormTitle);
3019
3020 return RetVal;
3021 }
3022
3023 /**
3024 Popup an NO_SUBMIT_IF error info and get user input.
3025
3026 @param TitleId The form title id.
3027 @param HiiHandle The hii handle for this package.
3028
3029 @retval UINT32 The user select option for the save fail.
3030 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET
3031 **/
3032 UINT32
3033 ConfirmNoSubmitFail (
3034 IN EFI_STRING_ID TitleId,
3035 IN EFI_HII_HANDLE HiiHandle
3036 )
3037 {
3038 CHAR16 *FormTitle;
3039 CHAR16 *StringBuffer;
3040 UINT32 RetVal;
3041
3042 FormTitle = GetToken (TitleId, HiiHandle);
3043
3044 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16));
3045 ASSERT (StringBuffer != NULL);
3046
3047 UnicodeSPrint (
3048 StringBuffer,
3049 24 * sizeof (CHAR16) + StrSize (FormTitle),
3050 L"NO_SUBMIT_IF error For Form: %s.",
3051 FormTitle
3052 );
3053
3054 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer);
3055
3056 FreePool (StringBuffer);
3057 FreePool (FormTitle);
3058
3059 return RetVal;
3060 }
3061
3062 /**
3063 Discard data based on the input setting scope (Form, FormSet or System).
3064
3065 @param FormSet FormSet data structure.
3066 @param Form Form data structure.
3067 @param SettingScope Setting Scope for Discard action.
3068
3069 @retval EFI_SUCCESS The function completed successfully.
3070 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3071
3072 **/
3073 EFI_STATUS
3074 DiscardForm (
3075 IN FORM_BROWSER_FORMSET *FormSet,
3076 IN FORM_BROWSER_FORM *Form,
3077 IN BROWSER_SETTING_SCOPE SettingScope
3078 )
3079 {
3080 LIST_ENTRY *Link;
3081 FORMSET_STORAGE *Storage;
3082 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
3083 FORM_BROWSER_FORMSET *LocalFormSet;
3084 FORM_BROWSER_FORMSET *OldFormSet;
3085
3086 //
3087 // Check the supported setting level.
3088 //
3089 if (SettingScope >= MaxLevel) {
3090 return EFI_UNSUPPORTED;
3091 }
3092
3093 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {
3094 ConfigInfo = NULL;
3095 Link = GetFirstNode (&Form->ConfigRequestHead);
3096 while (!IsNull (&Form->ConfigRequestHead, Link)) {
3097 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
3098 Link = GetNextNode (&Form->ConfigRequestHead, Link);
3099
3100 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3101 continue;
3102 }
3103
3104 //
3105 // Skip if there is no RequestElement
3106 //
3107 if (ConfigInfo->ElementCount == 0) {
3108 continue;
3109 }
3110
3111 //
3112 // Prepare <ConfigResp>
3113 //
3114 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);
3115
3116 //
3117 // Call callback with Changed type to inform the driver.
3118 //
3119 SendDiscardInfoToDriver (FormSet, Form);
3120 }
3121
3122 ValueChangeResetFlagUpdate (FALSE, FormSet, Form);
3123 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {
3124
3125 //
3126 // Discard Buffer storage or Name/Value storage
3127 //
3128 Link = GetFirstNode (&FormSet->StorageListHead);
3129 while (!IsNull (&FormSet->StorageListHead, Link)) {
3130 Storage = FORMSET_STORAGE_FROM_LINK (Link);
3131 Link = GetNextNode (&FormSet->StorageListHead, Link);
3132
3133 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3134 continue;
3135 }
3136
3137 //
3138 // Skip if there is no RequestElement
3139 //
3140 if (Storage->ElementCount == 0) {
3141 continue;
3142 }
3143
3144 SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
3145 }
3146
3147 Link = GetFirstNode (&FormSet->FormListHead);
3148 while (!IsNull (&FormSet->FormListHead, Link)) {
3149 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3150 Link = GetNextNode (&FormSet->FormListHead, Link);
3151
3152 //
3153 // Call callback with Changed type to inform the driver.
3154 //
3155 SendDiscardInfoToDriver (FormSet, Form);
3156 }
3157
3158 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);
3159 } else if (SettingScope == SystemLevel) {
3160 //
3161 // System Level Discard.
3162 //
3163 OldFormSet = mSystemLevelFormSet;
3164
3165 //
3166 // Discard changed value for each FormSet in the maintain list.
3167 //
3168 Link = GetFirstNode (&gBrowserFormSetList);
3169 while (!IsNull (&gBrowserFormSetList, Link)) {
3170 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3171 Link = GetNextNode (&gBrowserFormSetList, Link);
3172 if (!ValidateFormSet(LocalFormSet)) {
3173 continue;
3174 }
3175
3176 mSystemLevelFormSet = LocalFormSet;
3177
3178 DiscardForm (LocalFormSet, NULL, FormSetLevel);
3179 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3180 //
3181 // Remove maintain backup list after discard except for the current using FormSet.
3182 //
3183 CleanBrowserStorage(LocalFormSet);
3184 RemoveEntryList (&LocalFormSet->Link);
3185 DestroyFormSet (LocalFormSet);
3186 }
3187 }
3188
3189 mSystemLevelFormSet = OldFormSet;
3190 }
3191
3192 return EFI_SUCCESS;
3193 }
3194
3195 /**
3196 Submit data for a form.
3197
3198 @param FormSet FormSet data structure.
3199 @param Form Form data structure.
3200
3201 @retval EFI_SUCCESS The function completed successfully.
3202 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3203
3204 **/
3205 EFI_STATUS
3206 SubmitForForm (
3207 IN FORM_BROWSER_FORMSET *FormSet,
3208 IN FORM_BROWSER_FORM *Form
3209 )
3210 {
3211 EFI_STATUS Status;
3212 LIST_ENTRY *Link;
3213 EFI_STRING ConfigResp;
3214 EFI_STRING Progress;
3215 BROWSER_STORAGE *Storage;
3216 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
3217 BOOLEAN SubmitFormFail;
3218
3219 SubmitFormFail = FALSE;
3220
3221 if (!IsNvUpdateRequiredForForm (Form)) {
3222 return EFI_SUCCESS;
3223 }
3224
3225 Status = NoSubmitCheck (FormSet, &Form, NULL);
3226 if (EFI_ERROR (Status)) {
3227 return Status;
3228 }
3229
3230 Link = GetFirstNode (&Form->ConfigRequestHead);
3231 while (!IsNull (&Form->ConfigRequestHead, Link)) {
3232 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
3233 Link = GetNextNode (&Form->ConfigRequestHead, Link);
3234
3235 Storage = ConfigInfo->Storage;
3236 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3237 continue;
3238 }
3239
3240 //
3241 // Skip if there is no RequestElement
3242 //
3243 if (ConfigInfo->ElementCount == 0) {
3244 continue;
3245 }
3246
3247 //
3248 // 1. Prepare <ConfigResp>
3249 //
3250 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);
3251 if (EFI_ERROR (Status)) {
3252 return Status;
3253 }
3254
3255 //
3256 // 2. Set value to hii config routine protocol.
3257 //
3258 Status = mHiiConfigRouting->RouteConfig (
3259 mHiiConfigRouting,
3260 ConfigResp,
3261 &Progress
3262 );
3263
3264 if (EFI_ERROR (Status)) {
3265 //
3266 // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
3267 //
3268 SubmitFormFail = TRUE;
3269 GetSyncRestoreConfigRequest (ConfigInfo->Storage, ConfigInfo->ConfigRequest, Progress, &ConfigInfo->RestoreConfigRequest, &ConfigInfo->SyncConfigRequest);
3270 InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink);
3271 FreePool (ConfigResp);
3272 continue;
3273 }
3274
3275 FreePool (ConfigResp);
3276 //
3277 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
3278 //
3279 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);
3280 }
3281
3282 //
3283 // 4. Process the save failed storage.
3284 //
3285 if (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3286 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
3287 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3288 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
3289 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
3290 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
3291 //
3292 // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
3293 // base on the SyncConfigRequest to Sync the buffer.
3294 //
3295 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->RestoreConfigRequest, FALSE);
3296 FreePool (ConfigInfo->RestoreConfigRequest);
3297 ConfigInfo->RestoreConfigRequest = NULL;
3298 if (ConfigInfo->SyncConfigRequest != NULL) {
3299 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->SyncConfigRequest, TRUE);
3300 FreePool (ConfigInfo->SyncConfigRequest);
3301 ConfigInfo->SyncConfigRequest = NULL;
3302 }
3303
3304 Status = EFI_SUCCESS;
3305 }
3306 SendDiscardInfoToDriver (FormSet,Form);
3307 } else {
3308 Status = EFI_UNSUPPORTED;
3309 }
3310
3311 //
3312 // Free Form save fail list.
3313 //
3314 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3315 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3316 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link);
3317 RemoveEntryList (&ConfigInfo->SaveFailLink);
3318 }
3319 }
3320
3321 //
3322 // 5. Update the NV flag.
3323 //
3324 ValueChangeResetFlagUpdate(TRUE, FormSet, Form);
3325
3326 //
3327 // 6 Call callback with Submitted type to inform the driver.
3328 //
3329 if (!SubmitFormFail) {
3330 SubmitCallback (FormSet, Form);
3331 }
3332
3333 return Status;
3334 }
3335
3336 /**
3337 Submit data for a formset.
3338
3339 @param FormSet FormSet data structure.
3340 @param SkipProcessFail Whether skip to process the save failed storage.
3341 If submit formset is called when do system level save,
3342 set this value to true and process the failed formset
3343 together.
3344 if submit formset is called when do formset level save,
3345 set the value to false and process the failed storage
3346 right after process all storages for this formset.
3347
3348 @retval EFI_SUCCESS The function completed successfully.
3349 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3350
3351 **/
3352 EFI_STATUS
3353 SubmitForFormSet (
3354 IN FORM_BROWSER_FORMSET *FormSet,
3355 IN BOOLEAN SkipProcessFail
3356 )
3357 {
3358 EFI_STATUS Status;
3359 LIST_ENTRY *Link;
3360 EFI_STRING ConfigResp;
3361 EFI_STRING Progress;
3362 BROWSER_STORAGE *Storage;
3363 FORMSET_STORAGE *FormSetStorage;
3364 FORM_BROWSER_FORM *Form;
3365 BOOLEAN HasInserted;
3366 FORM_BROWSER_STATEMENT *Question;
3367 BOOLEAN SubmitFormSetFail;
3368 BOOLEAN DiscardChange;
3369
3370 HasInserted = FALSE;
3371 SubmitFormSetFail = FALSE;
3372 DiscardChange = FALSE;
3373
3374 if (!IsNvUpdateRequiredForFormSet (FormSet)) {
3375 return EFI_SUCCESS;
3376 }
3377
3378 Form = NULL;
3379 Status = NoSubmitCheck (FormSet, &Form, &Question);
3380 if (EFI_ERROR (Status)) {
3381 if (SkipProcessFail) {
3382 //
3383 // Process NO_SUBMIT check first, so insert it at head.
3384 //
3385 FormSet->SaveFailForm = Form;
3386 FormSet->SaveFailStatement = Question;
3387 InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
3388 }
3389
3390 return Status;
3391 }
3392
3393 Form = NULL;
3394 Question = NULL;
3395 //
3396 // Submit Buffer storage or Name/Value storage
3397 //
3398 Link = GetFirstNode (&FormSet->StorageListHead);
3399 while (!IsNull (&FormSet->StorageListHead, Link)) {
3400 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
3401 Storage = FormSetStorage->BrowserStorage;
3402 Link = GetNextNode (&FormSet->StorageListHead, Link);
3403
3404 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3405 continue;
3406 }
3407
3408 //
3409 // Skip if there is no RequestElement
3410 //
3411 if (FormSetStorage->ElementCount == 0) {
3412 continue;
3413 }
3414
3415 //
3416 // 1. Prepare <ConfigResp>
3417 //
3418 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);
3419 if (EFI_ERROR (Status)) {
3420 return Status;
3421 }
3422
3423 //
3424 // 2. Send <ConfigResp> to Routine config Protocol.
3425 //
3426 Status = mHiiConfigRouting->RouteConfig (
3427 mHiiConfigRouting,
3428 ConfigResp,
3429 &Progress
3430 );
3431 if (EFI_ERROR (Status)) {
3432 //
3433 // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest.
3434 //
3435 SubmitFormSetFail = TRUE;
3436 GetSyncRestoreConfigRequest (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, Progress, &FormSetStorage->RestoreConfigRequest, &FormSetStorage->SyncConfigRequest);
3437 InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink);
3438 if (!HasInserted) {
3439 //
3440 // Call submit formset for system level, save the formset info
3441 // and process later.
3442 //
3443 FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question);
3444 ASSERT (Form != NULL && Question != NULL);
3445 FormSet->SaveFailForm = Form;
3446 FormSet->SaveFailStatement = Question;
3447 if (SkipProcessFail) {
3448 InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink);
3449 }
3450 HasInserted = TRUE;
3451 }
3452
3453 FreePool (ConfigResp);
3454 continue;
3455 }
3456
3457 FreePool (ConfigResp);
3458 //
3459 // 3. Config success, update storage shadow Buffer
3460 //
3461 SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE);
3462 }
3463
3464 //
3465 // 4. Has save fail storage need to handle.
3466 //
3467 if (Form != NULL) {
3468 if (!SkipProcessFail) {
3469 //
3470 // If not in system level, just handl the save failed storage here.
3471 //
3472 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) {
3473 DiscardChange = TRUE;
3474 Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
3475 while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) {
3476 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
3477 Storage = FormSetStorage->BrowserStorage;
3478 Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link);
3479 //
3480 // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
3481 // base on the SyncConfigRequest to Sync the buffer.
3482 //
3483 SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
3484 FreePool (FormSetStorage->RestoreConfigRequest);
3485 FormSetStorage->RestoreConfigRequest = NULL;
3486 if (FormSetStorage->SyncConfigRequest != NULL) {
3487 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
3488 FreePool (FormSetStorage->SyncConfigRequest);
3489 FormSetStorage->SyncConfigRequest = NULL;
3490 }
3491
3492 Status = EFI_SUCCESS;
3493 }
3494 } else {
3495 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
3496
3497 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
3498 gCurrentSelection->Handle = FormSet->HiiHandle;
3499 CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid);
3500 gCurrentSelection->FormId = Form->FormId;
3501 gCurrentSelection->QuestionId = Question->QuestionId;
3502
3503 Status = EFI_UNSUPPORTED;
3504 }
3505
3506 //
3507 // Free FormSet save fail list.
3508 //
3509 while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) {
3510 Link = GetFirstNode (&FormSet->SaveFailStorageListHead);
3511 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link);
3512 RemoveEntryList (&FormSetStorage->SaveFailLink);
3513 }
3514 } else {
3515 //
3516 // If in system level, just return error and handle the failed formset later.
3517 //
3518 Status = EFI_UNSUPPORTED;
3519 }
3520 }
3521
3522 //
3523 // If user discard the change, send the discard info to driver.
3524 //
3525 if (DiscardChange) {
3526 Link = GetFirstNode (&FormSet->FormListHead);
3527 while (!IsNull (&FormSet->FormListHead, Link)) {
3528 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3529 Link = GetNextNode (&FormSet->FormListHead, Link);
3530 //
3531 // Call callback with Changed type to inform the driver.
3532 //
3533 SendDiscardInfoToDriver (FormSet, Form);
3534 }
3535 }
3536
3537 //
3538 // 5. Update the NV flag.
3539 //
3540 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);
3541
3542 //
3543 // 6. Call callback with Submitted type to inform the driver.
3544 //
3545 if (!SubmitFormSetFail) {
3546 SubmitCallback (FormSet, NULL);
3547 }
3548
3549 return Status;
3550 }
3551
3552 /**
3553 Submit data for all formsets.
3554
3555 @retval EFI_SUCCESS The function completed successfully.
3556 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3557
3558 **/
3559 EFI_STATUS
3560 SubmitForSystem (
3561 VOID
3562 )
3563 {
3564 EFI_STATUS Status;
3565 LIST_ENTRY *Link;
3566 LIST_ENTRY *FormLink;
3567 LIST_ENTRY *StorageLink;
3568 FORMSET_STORAGE *FormSetStorage;
3569 FORM_BROWSER_FORM *Form;
3570 FORM_BROWSER_FORMSET *LocalFormSet;
3571 UINT32 UserSelection;
3572 FORM_BROWSER_STATEMENT *Question;
3573
3574 mSystemSubmit = TRUE;
3575 Link = GetFirstNode (&gBrowserFormSetList);
3576 while (!IsNull (&gBrowserFormSetList, Link)) {
3577 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3578 Link = GetNextNode (&gBrowserFormSetList, Link);
3579 if (!ValidateFormSet(LocalFormSet)) {
3580 continue;
3581 }
3582
3583 Status = SubmitForFormSet (LocalFormSet, TRUE);
3584 if (EFI_ERROR (Status)) {
3585 continue;
3586 }
3587
3588 //
3589 // Remove maintain backup list after save except for the current using FormSet.
3590 //
3591 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3592 CleanBrowserStorage(LocalFormSet);
3593 RemoveEntryList (&LocalFormSet->Link);
3594 DestroyFormSet (LocalFormSet);
3595 }
3596 }
3597 mSystemSubmit = FALSE;
3598
3599 Status = EFI_SUCCESS;
3600
3601 //
3602 // Process the save failed formsets.
3603 //
3604 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3605 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) {
3606 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
3607 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link);
3608
3609 if (!ValidateFormSet(LocalFormSet)) {
3610 continue;
3611 }
3612
3613 Form = LocalFormSet->SaveFailForm;
3614 Question= LocalFormSet->SaveFailStatement;
3615
3616 //
3617 // Confirm with user, get user input.
3618 //
3619 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3620 //
3621 // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check.
3622 //
3623 UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle);
3624 } else {
3625 UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle);
3626 }
3627
3628 if (UserSelection == BROWSER_ACTION_DISCARD) {
3629 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3630 StorageLink = GetFirstNode (&LocalFormSet->StorageListHead);
3631 while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) {
3632 FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
3633 StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink);
3634
3635 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE);
3636 }
3637 } else {
3638 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
3639 while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) {
3640 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
3641 StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink);
3642 //
3643 // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer
3644 // base on the SyncConfigRequest to Sync the buffer.
3645 //
3646 SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE);
3647 FreePool (FormSetStorage->RestoreConfigRequest);
3648 FormSetStorage->RestoreConfigRequest = NULL;
3649 if ( FormSetStorage->SyncConfigRequest != NULL) {
3650 SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE);
3651 FreePool (FormSetStorage->SyncConfigRequest);
3652 FormSetStorage->SyncConfigRequest = NULL;
3653 }
3654 }
3655 }
3656
3657 FormLink = GetFirstNode (&LocalFormSet->FormListHead);
3658 while (!IsNull (&LocalFormSet->FormListHead, FormLink)) {
3659 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3660 FormLink = GetNextNode (&LocalFormSet->FormListHead, FormLink);
3661 //
3662 // Call callback with Changed type to inform the driver.
3663 //
3664 SendDiscardInfoToDriver (LocalFormSet, Form);
3665 }
3666
3667 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
3668 CleanBrowserStorage(LocalFormSet);
3669 RemoveEntryList (&LocalFormSet->Link);
3670 RemoveEntryList (&LocalFormSet->SaveFailLink);
3671 DestroyFormSet (LocalFormSet);
3672 } else {
3673 ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL);
3674 }
3675 } else {
3676 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3677 NoSubmitCheck (LocalFormSet, &Form, &Question);
3678 }
3679
3680 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead);
3681
3682 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
3683 gCurrentSelection->Handle = LocalFormSet->HiiHandle;
3684 CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid);
3685 gCurrentSelection->FormId = Form->FormId;
3686 gCurrentSelection->QuestionId = Question->QuestionId;
3687
3688 Status = EFI_UNSUPPORTED;
3689 break;
3690 }
3691 }
3692
3693 //
3694 // Clean the list which will not process.
3695 //
3696 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) {
3697 Link = GetFirstNode (&gBrowserSaveFailFormSetList);
3698 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link);
3699 RemoveEntryList (&LocalFormSet->SaveFailLink);
3700
3701 while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) {
3702 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead);
3703 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink);
3704 RemoveEntryList (&FormSetStorage->SaveFailLink);
3705 }
3706 }
3707
3708 return Status;
3709 }
3710
3711 /**
3712 Submit data based on the input Setting level (Form, FormSet or System).
3713
3714 @param FormSet FormSet data structure.
3715 @param Form Form data structure.
3716 @param SettingScope Setting Scope for Submit action.
3717
3718 @retval EFI_SUCCESS The function completed successfully.
3719 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3720
3721 **/
3722 EFI_STATUS
3723 SubmitForm (
3724 IN FORM_BROWSER_FORMSET *FormSet,
3725 IN FORM_BROWSER_FORM *Form,
3726 IN BROWSER_SETTING_SCOPE SettingScope
3727 )
3728 {
3729 EFI_STATUS Status;
3730
3731 switch (SettingScope) {
3732 case FormLevel:
3733 Status = SubmitForForm(FormSet, Form);
3734 break;
3735
3736 case FormSetLevel:
3737 Status = SubmitForFormSet (FormSet, FALSE);
3738 break;
3739
3740 case SystemLevel:
3741 Status = SubmitForSystem ();
3742 break;
3743
3744 default:
3745 Status = EFI_UNSUPPORTED;
3746 break;
3747 }
3748
3749 return Status;
3750 }
3751
3752 /**
3753 Converts the unicode character of the string from uppercase to lowercase.
3754 This is a internal function.
3755
3756 @param ConfigString String to be converted
3757
3758 **/
3759 VOID
3760 EFIAPI
3761 HiiToLower (
3762 IN EFI_STRING ConfigString
3763 )
3764 {
3765 EFI_STRING String;
3766 BOOLEAN Lower;
3767
3768 ASSERT (ConfigString != NULL);
3769
3770 //
3771 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
3772 //
3773 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
3774 if (*String == L'=') {
3775 Lower = TRUE;
3776 } else if (*String == L'&') {
3777 Lower = FALSE;
3778 } else if (Lower && *String >= L'A' && *String <= L'F') {
3779 *String = (CHAR16) (*String - L'A' + L'a');
3780 }
3781 }
3782 }
3783
3784 /**
3785 Find the point in the ConfigResp string for this question.
3786
3787 @param Question The question.
3788 @param ConfigResp Get ConfigResp string.
3789
3790 @retval point to the offset where is for this question.
3791
3792 **/
3793 CHAR16 *
3794 GetOffsetFromConfigResp (
3795 IN FORM_BROWSER_STATEMENT *Question,
3796 IN CHAR16 *ConfigResp
3797 )
3798 {
3799 CHAR16 *RequestElement;
3800 CHAR16 *BlockData;
3801
3802 //
3803 // Type is EFI_HII_VARSTORE_NAME_VALUE.
3804 //
3805 if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3806 RequestElement = StrStr (ConfigResp, Question->VariableName);
3807 if (RequestElement != NULL) {
3808 //
3809 // Skip the "VariableName=" field.
3810 //
3811 RequestElement += StrLen (Question->VariableName) + 1;
3812 }
3813
3814 return RequestElement;
3815 }
3816
3817 //
3818 // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
3819 //
3820
3821 //
3822 // Convert all hex digits in ConfigResp to lower case before searching.
3823 //
3824 HiiToLower (ConfigResp);
3825
3826 //
3827 // 1. Directly use Question->BlockName to find.
3828 //
3829 RequestElement = StrStr (ConfigResp, Question->BlockName);
3830 if (RequestElement != NULL) {
3831 //
3832 // Skip the "Question->BlockName&VALUE=" field.
3833 //
3834 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
3835 return RequestElement;
3836 }
3837
3838 //
3839 // 2. Change all hex digits in Question->BlockName to lower and compare again.
3840 //
3841 BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName);
3842 ASSERT (BlockData != NULL);
3843 HiiToLower (BlockData);
3844 RequestElement = StrStr (ConfigResp, BlockData);
3845 FreePool (BlockData);
3846
3847 if (RequestElement != NULL) {
3848 //
3849 // Skip the "Question->BlockName&VALUE=" field.
3850 //
3851 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
3852 }
3853
3854 return RequestElement;
3855 }
3856
3857 /**
3858 Get Question default value from AltCfg string.
3859
3860 @param FormSet The form set.
3861 @param Form The form
3862 @param Question The question.
3863
3864 @retval EFI_SUCCESS Question is reset to default value.
3865
3866 **/
3867 EFI_STATUS
3868 GetDefaultValueFromAltCfg (
3869 IN FORM_BROWSER_FORMSET *FormSet,
3870 IN FORM_BROWSER_FORM *Form,
3871 IN OUT FORM_BROWSER_STATEMENT *Question
3872 )
3873 {
3874 BROWSER_STORAGE *Storage;
3875 FORMSET_STORAGE *FormSetStorage;
3876 CHAR16 *ConfigResp;
3877 CHAR16 *Value;
3878 LIST_ENTRY *Link;
3879 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
3880
3881 Storage = Question->Storage;
3882 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
3883 return EFI_NOT_FOUND;
3884 }
3885
3886 //
3887 // Try to get AltCfg string from form. If not found it, then
3888 // try to get it from formset.
3889 //
3890 ConfigResp = NULL;
3891 Link = GetFirstNode (&Form->ConfigRequestHead);
3892 while (!IsNull (&Form->ConfigRequestHead, Link)) {
3893 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
3894 Link = GetNextNode (&Form->ConfigRequestHead, Link);
3895
3896 if (Storage == ConfigInfo->Storage) {
3897 ConfigResp = ConfigInfo->ConfigAltResp;
3898 break;
3899 }
3900 }
3901
3902 if (ConfigResp == NULL) {
3903 Link = GetFirstNode (&FormSet->StorageListHead);
3904 while (!IsNull (&FormSet->StorageListHead, Link)) {
3905 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
3906 Link = GetNextNode (&FormSet->StorageListHead, Link);
3907
3908 if (Storage == FormSetStorage->BrowserStorage) {
3909 ConfigResp = FormSetStorage->ConfigAltResp;
3910 break;
3911 }
3912 }
3913 }
3914
3915 if (ConfigResp == NULL) {
3916 return EFI_NOT_FOUND;
3917 }
3918
3919 Value = GetOffsetFromConfigResp (Question, ConfigResp);
3920 if (Value == NULL) {
3921 return EFI_NOT_FOUND;
3922 }
3923
3924 return BufferToValue (Question, Value);
3925 }
3926
3927 /**
3928 Get default Id value used for browser.
3929
3930 @param DefaultId The default id value used by hii.
3931
3932 @retval Browser used default value.
3933
3934 **/
3935 INTN
3936 GetDefaultIdForCallBack (
3937 UINTN DefaultId
3938 )
3939 {
3940 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
3941 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
3942 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3943 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
3944 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
3945 return EFI_BROWSER_ACTION_DEFAULT_SAFE;
3946 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
3947 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
3948 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
3949 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
3950 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
3951 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
3952 } else {
3953 return -1;
3954 }
3955 }
3956
3957
3958
3959 /**
3960 Return data element in an Array by its Index.
3961
3962 @param Array The data array.
3963 @param Type Type of the data in this array.
3964 @param Index Zero based index for data in this array.
3965
3966 @retval Value The data to be returned
3967
3968 **/
3969 UINT64
3970 GetArrayData (
3971 IN VOID *Array,
3972 IN UINT8 Type,
3973 IN UINTN Index
3974 )
3975 {
3976 UINT64 Data;
3977
3978 ASSERT (Array != NULL);
3979
3980 Data = 0;
3981 switch (Type) {
3982 case EFI_IFR_TYPE_NUM_SIZE_8:
3983 Data = (UINT64) *(((UINT8 *) Array) + Index);
3984 break;
3985
3986 case EFI_IFR_TYPE_NUM_SIZE_16:
3987 Data = (UINT64) *(((UINT16 *) Array) + Index);
3988 break;
3989
3990 case EFI_IFR_TYPE_NUM_SIZE_32:
3991 Data = (UINT64) *(((UINT32 *) Array) + Index);
3992 break;
3993
3994 case EFI_IFR_TYPE_NUM_SIZE_64:
3995 Data = (UINT64) *(((UINT64 *) Array) + Index);
3996 break;
3997
3998 default:
3999 break;
4000 }
4001
4002 return Data;
4003 }
4004
4005
4006 /**
4007 Set value of a data element in an Array by its Index.
4008
4009 @param Array The data array.
4010 @param Type Type of the data in this array.
4011 @param Index Zero based index for data in this array.
4012 @param Value The value to be set.
4013
4014 **/
4015 VOID
4016 SetArrayData (
4017 IN VOID *Array,
4018 IN UINT8 Type,
4019 IN UINTN Index,
4020 IN UINT64 Value
4021 )
4022 {
4023
4024 ASSERT (Array != NULL);
4025
4026 switch (Type) {
4027 case EFI_IFR_TYPE_NUM_SIZE_8:
4028 *(((UINT8 *) Array) + Index) = (UINT8) Value;
4029 break;
4030
4031 case EFI_IFR_TYPE_NUM_SIZE_16:
4032 *(((UINT16 *) Array) + Index) = (UINT16) Value;
4033 break;
4034
4035 case EFI_IFR_TYPE_NUM_SIZE_32:
4036 *(((UINT32 *) Array) + Index) = (UINT32) Value;
4037 break;
4038
4039 case EFI_IFR_TYPE_NUM_SIZE_64:
4040 *(((UINT64 *) Array) + Index) = (UINT64) Value;
4041 break;
4042
4043 default:
4044 break;
4045 }
4046 }
4047
4048 /**
4049 Search an Option of a Question by its value.
4050
4051 @param Question The Question
4052 @param OptionValue Value for Option to be searched.
4053
4054 @retval Pointer Pointer to the found Option.
4055 @retval NULL Option not found.
4056
4057 **/
4058 QUESTION_OPTION *
4059 ValueToOption (
4060 IN FORM_BROWSER_STATEMENT *Question,
4061 IN EFI_HII_VALUE *OptionValue
4062 )
4063 {
4064 LIST_ENTRY *Link;
4065 QUESTION_OPTION *Option;
4066 INTN Result;
4067
4068 Link = GetFirstNode (&Question->OptionListHead);
4069 while (!IsNull (&Question->OptionListHead, Link)) {
4070 Option = QUESTION_OPTION_FROM_LINK (Link);
4071
4072 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
4073 //
4074 // Check the suppressif condition, only a valid option can be return.
4075 //
4076 if ((Option->SuppressExpression == NULL) ||
4077 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
4078 return Option;
4079 }
4080 }
4081
4082 Link = GetNextNode (&Question->OptionListHead, Link);
4083 }
4084
4085 return NULL;
4086 }
4087
4088
4089 /**
4090 Reset Question to its default value.
4091
4092 @param FormSet The form set.
4093 @param Form The form.
4094 @param Question The question.
4095 @param DefaultId The Class of the default.
4096
4097 @retval EFI_SUCCESS Question is reset to default value.
4098
4099 **/
4100 EFI_STATUS
4101 GetQuestionDefault (
4102 IN FORM_BROWSER_FORMSET *FormSet,
4103 IN FORM_BROWSER_FORM *Form,
4104 IN FORM_BROWSER_STATEMENT *Question,
4105 IN UINT16 DefaultId
4106 )
4107 {
4108 EFI_STATUS Status;
4109 LIST_ENTRY *Link;
4110 QUESTION_DEFAULT *Default;
4111 QUESTION_OPTION *Option;
4112 EFI_HII_VALUE *HiiValue;
4113 UINT8 Index;
4114 EFI_STRING StrValue;
4115 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
4116 EFI_BROWSER_ACTION_REQUEST ActionRequest;
4117 INTN Action;
4118 CHAR16 *NewString;
4119 EFI_IFR_TYPE_VALUE *TypeValue;
4120 UINT16 OriginalDefaultId;
4121 FORMSET_DEFAULTSTORE *DefaultStore;
4122 LIST_ENTRY *DefaultLink;
4123
4124 Status = EFI_NOT_FOUND;
4125 StrValue = NULL;
4126 OriginalDefaultId = DefaultId;
4127 DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
4128
4129 //
4130 // Statement don't have storage, skip them
4131 //
4132 if (Question->QuestionId == 0) {
4133 return Status;
4134 }
4135
4136 //
4137 // There are Five ways to specify default value for a Question:
4138 // 1, use call back function (highest priority)
4139 // 2, use ExtractConfig function
4140 // 3, use nested EFI_IFR_DEFAULT
4141 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
4142 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
4143 //
4144 ReGetDefault:
4145 HiiValue = &Question->HiiValue;
4146 TypeValue = &HiiValue->Value;
4147 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
4148 //
4149 // For orderedlist, need to pass the BufferValue to Callback function.
4150 //
4151 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
4152 }
4153
4154 //
4155 // Get Question defaut value from call back function.
4156 //
4157 ConfigAccess = FormSet->ConfigAccess;
4158 Action = GetDefaultIdForCallBack (DefaultId);
4159 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
4160 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
4161 Status = ConfigAccess->Callback (
4162 ConfigAccess,
4163 Action,
4164 Question->QuestionId,
4165 HiiValue->Type,
4166 TypeValue,
4167 &ActionRequest
4168 );
4169 if (!EFI_ERROR (Status)) {
4170 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
4171 NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle);
4172 ASSERT (NewString != NULL);
4173
4174 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth);
4175 if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) {
4176 ZeroMem (Question->BufferValue, Question->StorageWidth);
4177 CopyMem (Question->BufferValue, NewString, StrSize (NewString));
4178 } else {
4179 CopyMem (Question->BufferValue, NewString, Question->StorageWidth);
4180 }
4181
4182 FreePool (NewString);
4183 }
4184 return Status;
4185 }
4186 }
4187
4188 //
4189 // Get default value from altcfg string.
4190 //
4191 if (ConfigAccess != NULL) {
4192 Status = GetDefaultValueFromAltCfg(FormSet, Form, Question);
4193 if (!EFI_ERROR (Status)) {
4194 return Status;
4195 }
4196 }
4197
4198 //
4199 // EFI_IFR_DEFAULT has highest priority
4200 //
4201 if (!IsListEmpty (&Question->DefaultListHead)) {
4202 Link = GetFirstNode (&Question->DefaultListHead);
4203 while (!IsNull (&Question->DefaultListHead, Link)) {
4204 Default = QUESTION_DEFAULT_FROM_LINK (Link);
4205
4206 if (Default->DefaultId == DefaultId) {
4207 if (Default->ValueExpression != NULL) {
4208 //
4209 // Default is provided by an Expression, evaluate it
4210 //
4211 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
4212 if (EFI_ERROR (Status)) {
4213 return Status;
4214 }
4215
4216 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
4217 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
4218 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
4219 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
4220 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
4221 } else {
4222 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
4223 Question->HiiValue.BufferLen = Question->StorageWidth;
4224 }
4225 FreePool (Default->ValueExpression->Result.Buffer);
4226 }
4227 HiiValue->Type = Default->ValueExpression->Result.Type;
4228 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
4229 } else {
4230 //
4231 // Default value is embedded in EFI_IFR_DEFAULT
4232 //
4233 if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
4234 ASSERT (HiiValue->Buffer != NULL);
4235 CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
4236 } else {
4237 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
4238 }
4239 }
4240
4241 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
4242 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
4243 if (StrValue == NULL) {
4244 return EFI_NOT_FOUND;
4245 }
4246 if (Question->StorageWidth > StrSize (StrValue)) {
4247 ZeroMem (Question->BufferValue, Question->StorageWidth);
4248 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
4249 } else {
4250 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
4251 }
4252 }
4253
4254 return EFI_SUCCESS;
4255 }
4256
4257 Link = GetNextNode (&Question->DefaultListHead, Link);
4258 }
4259 }
4260
4261 //
4262 // EFI_ONE_OF_OPTION
4263 //
4264 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
4265 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
4266 //
4267 // OneOfOption could only provide Standard and Manufacturing default
4268 //
4269 Link = GetFirstNode (&Question->OptionListHead);
4270 while (!IsNull (&Question->OptionListHead, Link)) {
4271 Option = QUESTION_OPTION_FROM_LINK (Link);
4272 Link = GetNextNode (&Question->OptionListHead, Link);
4273
4274 if ((Option->SuppressExpression != NULL) &&
4275 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
4276 continue;
4277 }
4278
4279 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
4280 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
4281 ) {
4282 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
4283
4284 return EFI_SUCCESS;
4285 }
4286 }
4287 }
4288 }
4289
4290 //
4291 // EFI_IFR_CHECKBOX - lowest priority
4292 //
4293 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
4294 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
4295 //
4296 // Checkbox could only provide Standard and Manufacturing default
4297 //
4298 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
4299 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
4300 ) {
4301 HiiValue->Value.b = TRUE;
4302 }
4303
4304 return EFI_SUCCESS;
4305 }
4306 }
4307
4308 //
4309 // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
4310 // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
4311 // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
4312 //
4313 while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
4314 DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
4315 DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
4316 DefaultId = DefaultStore->DefaultId;
4317 if (DefaultId == OriginalDefaultId) {
4318 continue;
4319 }
4320 goto ReGetDefault;
4321 }
4322
4323 //
4324 // For Questions without default value for all the default id in the DefaultStoreList.
4325 //
4326 Status = EFI_NOT_FOUND;
4327 switch (Question->Operand) {
4328 case EFI_IFR_CHECKBOX_OP:
4329 HiiValue->Value.b = FALSE;
4330 Status = EFI_SUCCESS;
4331 break;
4332
4333 case EFI_IFR_NUMERIC_OP:
4334 //
4335 // Take minimum value as numeric default value
4336 //
4337 if ((Question->Flags & EFI_IFR_DISPLAY) == 0) {
4338 //
4339 // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
4340 //
4341 switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) {
4342 case EFI_IFR_NUMERIC_SIZE_1:
4343 if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) {
4344 HiiValue->Value.u8 = (UINT8) Question->Minimum;
4345 Status = EFI_SUCCESS;
4346 }
4347 break;
4348 case EFI_IFR_NUMERIC_SIZE_2:
4349 if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) {
4350 HiiValue->Value.u16 = (UINT16) Question->Minimum;
4351 Status = EFI_SUCCESS;
4352 }
4353 break;
4354 case EFI_IFR_NUMERIC_SIZE_4:
4355 if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) {
4356 HiiValue->Value.u32 = (UINT32) Question->Minimum;
4357 Status = EFI_SUCCESS;
4358 }
4359 break;
4360 case EFI_IFR_NUMERIC_SIZE_8:
4361 if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) {
4362 HiiValue->Value.u64 = Question->Minimum;
4363 Status = EFI_SUCCESS;
4364 }
4365 break;
4366 default:
4367 break;
4368 }
4369 } else {
4370 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
4371 HiiValue->Value.u64 = Question->Minimum;
4372 Status = EFI_SUCCESS;
4373 }
4374 }
4375 break;
4376
4377 case EFI_IFR_ONE_OF_OP:
4378 //
4379 // Take first oneof option as oneof's default value
4380 //
4381 if (ValueToOption (Question, HiiValue) == NULL) {
4382 Link = GetFirstNode (&Question->OptionListHead);
4383 while (!IsNull (&Question->OptionListHead, Link)) {
4384 Option = QUESTION_OPTION_FROM_LINK (Link);
4385 Link = GetNextNode (&Question->OptionListHead, Link);
4386
4387 if ((Option->SuppressExpression != NULL) &&
4388 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
4389 continue;
4390 }
4391
4392 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
4393 Status = EFI_SUCCESS;
4394 break;
4395 }
4396 }
4397 break;
4398
4399 case EFI_IFR_ORDERED_LIST_OP:
4400 //
4401 // Take option sequence in IFR as ordered list's default value
4402 //
4403 Index = 0;
4404 Link = GetFirstNode (&Question->OptionListHead);
4405 while (!IsNull (&Question->OptionListHead, Link)) {
4406 Status = EFI_SUCCESS;
4407 Option = QUESTION_OPTION_FROM_LINK (Link);
4408 Link = GetNextNode (&Question->OptionListHead, Link);
4409
4410 if ((Option->SuppressExpression != NULL) &&
4411 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
4412 continue;
4413 }
4414
4415 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
4416
4417 Index++;
4418 if (Index >= Question->MaxContainers) {
4419 break;
4420 }
4421 }
4422 break;
4423
4424 default:
4425 break;
4426 }
4427
4428 return Status;
4429 }
4430
4431 /**
4432 Get AltCfg string for current form.
4433
4434 @param FormSet Form data structure.
4435 @param Form Form data structure.
4436 @param DefaultId The Class of the default.
4437 @param BrowserStorage The input request storage for the questions.
4438
4439 **/
4440 VOID
4441 ExtractAltCfgForForm (
4442 IN FORM_BROWSER_FORMSET *FormSet,
4443 IN FORM_BROWSER_FORM *Form,
4444 IN UINT16 DefaultId,
4445 IN BROWSER_STORAGE *BrowserStorage
4446 )
4447 {
4448 EFI_STATUS Status;
4449 LIST_ENTRY *Link;
4450 CHAR16 *ConfigResp;
4451 CHAR16 *Progress;
4452 CHAR16 *Result;
4453 BROWSER_STORAGE *Storage;
4454 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
4455 FORMSET_STORAGE *FormSetStorage;
4456
4457 //
4458 // Check whether has get AltCfg string for this formset.
4459 // If yes, no need to get AltCfg for form.
4460 //
4461 Link = GetFirstNode (&FormSet->StorageListHead);
4462 while (!IsNull (&FormSet->StorageListHead, Link)) {
4463 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
4464 Storage = FormSetStorage->BrowserStorage;
4465 Link = GetNextNode (&FormSet->StorageListHead, Link);
4466 if (BrowserStorage != NULL && BrowserStorage != Storage) {
4467 continue;
4468 }
4469
4470 if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE &&
4471 FormSetStorage->ElementCount != 0 &&
4472 FormSetStorage->HasCallAltCfg) {
4473 return;
4474 }
4475 }
4476
4477 //
4478 // Get AltCfg string for each form.
4479 //
4480 Link = GetFirstNode (&Form->ConfigRequestHead);
4481 while (!IsNull (&Form->ConfigRequestHead, Link)) {
4482 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
4483 Link = GetNextNode (&Form->ConfigRequestHead, Link);
4484
4485 Storage = ConfigInfo->Storage;
4486 if (BrowserStorage != NULL && BrowserStorage != Storage) {
4487 continue;
4488 }
4489
4490 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
4491 continue;
4492 }
4493
4494 //
4495 // 1. Skip if there is no RequestElement
4496 //
4497 if (ConfigInfo->ElementCount == 0) {
4498 continue;
4499 }
4500
4501 //
4502 // 2. Get value through hii config routine protocol.
4503 //
4504 Status = mHiiConfigRouting->ExtractConfig (
4505 mHiiConfigRouting,
4506 ConfigInfo->ConfigRequest,
4507 &Progress,
4508 &Result
4509 );
4510 if (EFI_ERROR (Status)) {
4511 continue;
4512 }
4513
4514 //
4515 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
4516 // Get the default configuration string according to the default ID.
4517 //
4518 Status = mHiiConfigRouting->GetAltConfig (
4519 mHiiConfigRouting,
4520 Result,
4521 &Storage->Guid,
4522 Storage->Name,
4523 NULL,
4524 &DefaultId, // it can be NULL to get the current setting.
4525 &ConfigResp
4526 );
4527 FreePool (Result);
4528 if (EFI_ERROR (Status)) {
4529 continue;
4530 }
4531
4532 ConfigInfo->ConfigAltResp = ConfigResp;
4533 }
4534 }
4535
4536 /**
4537 Clean AltCfg string for current form.
4538
4539 @param Form Form data structure.
4540
4541 **/
4542 VOID
4543 CleanAltCfgForForm (
4544 IN FORM_BROWSER_FORM *Form
4545 )
4546 {
4547 LIST_ENTRY *Link;
4548 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
4549
4550 Link = GetFirstNode (&Form->ConfigRequestHead);
4551 while (!IsNull (&Form->ConfigRequestHead, Link)) {
4552 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
4553 Link = GetNextNode (&Form->ConfigRequestHead, Link);
4554
4555 if (ConfigInfo->ConfigAltResp != NULL) {
4556 FreePool (ConfigInfo->ConfigAltResp);
4557 ConfigInfo->ConfigAltResp = NULL;
4558 }
4559 }
4560 }
4561
4562 /**
4563 Get AltCfg string for current formset.
4564
4565 @param FormSet Form data structure.
4566 @param DefaultId The Class of the default.
4567 @param BrowserStorage The input request storage for the questions.
4568
4569 **/
4570 VOID
4571 ExtractAltCfgForFormSet (
4572 IN FORM_BROWSER_FORMSET *FormSet,
4573 IN UINT16 DefaultId,
4574 IN BROWSER_STORAGE *BrowserStorage
4575 )
4576 {
4577 EFI_STATUS Status;
4578 LIST_ENTRY *Link;
4579 CHAR16 *ConfigResp;
4580 CHAR16 *Progress;
4581 CHAR16 *Result;
4582 BROWSER_STORAGE *Storage;
4583 FORMSET_STORAGE *FormSetStorage;
4584
4585 Link = GetFirstNode (&FormSet->StorageListHead);
4586 while (!IsNull (&FormSet->StorageListHead, Link)) {
4587 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
4588 Storage = FormSetStorage->BrowserStorage;
4589 Link = GetNextNode (&FormSet->StorageListHead, Link);
4590
4591 if (BrowserStorage != NULL && BrowserStorage != Storage) {
4592 continue;
4593 }
4594
4595 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
4596 continue;
4597 }
4598
4599 //
4600 // 1. Skip if there is no RequestElement
4601 //
4602 if (FormSetStorage->ElementCount == 0) {
4603 continue;
4604 }
4605
4606 FormSetStorage->HasCallAltCfg = TRUE;
4607
4608 //
4609 // 2. Get value through hii config routine protocol.
4610 //
4611 Status = mHiiConfigRouting->ExtractConfig (
4612 mHiiConfigRouting,
4613 FormSetStorage->ConfigRequest,
4614 &Progress,
4615 &Result
4616 );
4617 if (EFI_ERROR (Status)) {
4618 continue;
4619 }
4620
4621 //
4622 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
4623 // Get the default configuration string according to the default ID.
4624 //
4625 Status = mHiiConfigRouting->GetAltConfig (
4626 mHiiConfigRouting,
4627 Result,
4628 &Storage->Guid,
4629 Storage->Name,
4630 NULL,
4631 &DefaultId, // it can be NULL to get the current setting.
4632 &ConfigResp
4633 );
4634
4635 FreePool (Result);
4636 if (EFI_ERROR (Status)) {
4637 continue;
4638 }
4639
4640 FormSetStorage->ConfigAltResp = ConfigResp;
4641 }
4642
4643 }
4644
4645 /**
4646 Clean AltCfg string for current formset.
4647
4648 @param FormSet Form data structure.
4649
4650 **/
4651 VOID
4652 CleanAltCfgForFormSet (
4653 IN FORM_BROWSER_FORMSET *FormSet
4654 )
4655 {
4656 LIST_ENTRY *Link;
4657 FORMSET_STORAGE *FormSetStorage;
4658
4659 Link = GetFirstNode (&FormSet->StorageListHead);
4660 while (!IsNull (&FormSet->StorageListHead, Link)) {
4661 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link);
4662 Link = GetNextNode (&FormSet->StorageListHead, Link);
4663
4664 if (FormSetStorage->ConfigAltResp != NULL) {
4665 FreePool (FormSetStorage->ConfigAltResp);
4666 FormSetStorage->ConfigAltResp = NULL;
4667 }
4668
4669 FormSetStorage->HasCallAltCfg = FALSE;
4670 }
4671 }
4672
4673 /**
4674 Reset Questions to their initial value or default value in a Form, Formset or System.
4675
4676 GetDefaultValueScope parameter decides which questions will reset
4677 to its default value.
4678
4679 @param FormSet FormSet data structure.
4680 @param Form Form data structure.
4681 @param DefaultId The Class of the default.
4682 @param SettingScope Setting Scope for Default action.
4683 @param GetDefaultValueScope Get default value scope.
4684 @param Storage Get default value only for this storage.
4685 @param RetrieveValueFirst Whether call the retrieve call back to
4686 get the initial value before get default
4687 value.
4688 @param SkipGetAltCfg Whether skip the get altcfg string process.
4689
4690 @retval EFI_SUCCESS The function completed successfully.
4691 @retval EFI_UNSUPPORTED Unsupport SettingScope.
4692
4693 **/
4694 EFI_STATUS
4695 ExtractDefault (
4696 IN FORM_BROWSER_FORMSET *FormSet,
4697 IN FORM_BROWSER_FORM *Form,
4698 IN UINT16 DefaultId,
4699 IN BROWSER_SETTING_SCOPE SettingScope,
4700 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
4701 IN BROWSER_STORAGE *Storage OPTIONAL,
4702 IN BOOLEAN RetrieveValueFirst,
4703 IN BOOLEAN SkipGetAltCfg
4704 )
4705 {
4706 EFI_STATUS Status;
4707 LIST_ENTRY *FormLink;
4708 LIST_ENTRY *Link;
4709 FORM_BROWSER_STATEMENT *Question;
4710 FORM_BROWSER_FORMSET *LocalFormSet;
4711 FORM_BROWSER_FORMSET *OldFormSet;
4712
4713 Status = EFI_SUCCESS;
4714
4715 //
4716 // Check the supported setting level.
4717 //
4718 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
4719 return EFI_UNSUPPORTED;
4720 }
4721
4722 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
4723 return EFI_UNSUPPORTED;
4724 }
4725
4726 if (SettingScope == FormLevel) {
4727 //
4728 // Prepare the AltCfg String for form.
4729 //
4730 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4731 ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage);
4732 }
4733
4734 //
4735 // Extract Form default
4736 //
4737 Link = GetFirstNode (&Form->StatementListHead);
4738 while (!IsNull (&Form->StatementListHead, Link)) {
4739 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
4740 Link = GetNextNode (&Form->StatementListHead, Link);
4741
4742 //
4743 // If get default value only for this storage, check the storage first.
4744 //
4745 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
4746 continue;
4747 }
4748
4749 //
4750 // If get default value only for no storage question, just skip the question which has storage.
4751 //
4752 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
4753 continue;
4754 }
4755
4756 //
4757 // If Question is disabled, don't reset it to default
4758 //
4759 if (Question->Expression != NULL) {
4760 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
4761 continue;
4762 }
4763 }
4764
4765 if (RetrieveValueFirst) {
4766 //
4767 // Call the Retrieve call back to get the initial question value.
4768 //
4769 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet);
4770 }
4771
4772 //
4773 // If not request to get the initial value or get initial value fail, then get default value.
4774 //
4775 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
4776 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
4777 if (EFI_ERROR (Status)) {
4778 continue;
4779 }
4780 }
4781
4782 //
4783 // Synchronize Buffer storage's Edit buffer
4784 //
4785 if ((Question->Storage != NULL) &&
4786 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
4787 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4788 }
4789 }
4790
4791 //
4792 // Clean the AltCfg String.
4793 //
4794 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4795 CleanAltCfgForForm(Form);
4796 }
4797 } else if (SettingScope == FormSetLevel) {
4798 //
4799 // Prepare the AltCfg String for formset.
4800 //
4801 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4802 ExtractAltCfgForFormSet (FormSet, DefaultId, Storage);
4803 }
4804
4805 FormLink = GetFirstNode (&FormSet->FormListHead);
4806 while (!IsNull (&FormSet->FormListHead, FormLink)) {
4807 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
4808 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
4809 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
4810 }
4811
4812 //
4813 // Clean the AltCfg String.
4814 //
4815 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) {
4816 CleanAltCfgForFormSet (FormSet);
4817 }
4818 } else if (SettingScope == SystemLevel) {
4819 //
4820 // Preload all Hii formset.
4821 //
4822 LoadAllHiiFormset();
4823
4824 OldFormSet = mSystemLevelFormSet;
4825
4826 //
4827 // Set Default Value for each FormSet in the maintain list.
4828 //
4829 Link = GetFirstNode (&gBrowserFormSetList);
4830 while (!IsNull (&gBrowserFormSetList, Link)) {
4831 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4832 Link = GetNextNode (&gBrowserFormSetList, Link);
4833 if (!ValidateFormSet(LocalFormSet)) {
4834 continue;
4835 }
4836
4837 mSystemLevelFormSet = LocalFormSet;
4838
4839 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg);
4840 }
4841
4842 mSystemLevelFormSet = OldFormSet;
4843 }
4844
4845 return EFI_SUCCESS;
4846 }
4847
4848
4849 /**
4850 Validate whether this question's value has changed.
4851
4852 @param FormSet FormSet data structure.
4853 @param Form Form data structure.
4854 @param Question Question to be initialized.
4855 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
4856
4857 @retval TRUE Question's value has changed.
4858 @retval FALSE Question's value has not changed
4859
4860 **/
4861 BOOLEAN
4862 IsQuestionValueChanged (
4863 IN FORM_BROWSER_FORMSET *FormSet,
4864 IN FORM_BROWSER_FORM *Form,
4865 IN OUT FORM_BROWSER_STATEMENT *Question,
4866 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
4867 )
4868 {
4869 EFI_HII_VALUE BackUpValue;
4870 CHAR8 *BackUpBuffer;
4871 EFI_HII_VALUE BackUpValue2;
4872 CHAR8 *BackUpBuffer2;
4873 EFI_STATUS Status;
4874 BOOLEAN ValueChanged;
4875 UINTN BufferWidth;
4876
4877 //
4878 // For quetion without storage, always mark it as data not changed.
4879 //
4880 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {
4881 return FALSE;
4882 }
4883
4884 BackUpBuffer = NULL;
4885 BackUpBuffer2 = NULL;
4886 ValueChanged = FALSE;
4887
4888 switch (Question->Operand) {
4889 case EFI_IFR_ORDERED_LIST_OP:
4890 BufferWidth = Question->StorageWidth;
4891 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
4892 ASSERT (BackUpBuffer != NULL);
4893 break;
4894
4895 case EFI_IFR_STRING_OP:
4896 case EFI_IFR_PASSWORD_OP:
4897 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
4898 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);
4899 ASSERT (BackUpBuffer != NULL);
4900 break;
4901
4902 default:
4903 BufferWidth = 0;
4904 break;
4905 }
4906 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
4907
4908 if (GetValueFrom == GetSetValueWithBothBuffer) {
4909 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4910 ASSERT_EFI_ERROR(Status);
4911
4912 switch (Question->Operand) {
4913 case EFI_IFR_ORDERED_LIST_OP:
4914 BufferWidth = Question->StorageWidth;
4915 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
4916 ASSERT (BackUpBuffer2 != NULL);
4917 break;
4918
4919 case EFI_IFR_STRING_OP:
4920 case EFI_IFR_PASSWORD_OP:
4921 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16);
4922 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue);
4923 ASSERT (BackUpBuffer2 != NULL);
4924 break;
4925
4926 default:
4927 BufferWidth = 0;
4928 break;
4929 }
4930 CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE));
4931
4932 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
4933 ASSERT_EFI_ERROR(Status);
4934
4935 if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
4936 CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) {
4937 ValueChanged = TRUE;
4938 }
4939 } else {
4940 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);
4941 ASSERT_EFI_ERROR(Status);
4942
4943 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||
4944 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {
4945 ValueChanged = TRUE;
4946 }
4947 }
4948
4949 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));
4950 if (BackUpBuffer != NULL) {
4951 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);
4952 FreePool (BackUpBuffer);
4953 }
4954
4955 if (BackUpBuffer2 != NULL) {
4956 FreePool (BackUpBuffer2);
4957 }
4958
4959 Question->ValueChanged = ValueChanged;
4960
4961 return ValueChanged;
4962 }
4963
4964 /**
4965 Initialize Question's Edit copy from Storage.
4966
4967 @param Selection Selection contains the information about
4968 the Selection, form and formset to be displayed.
4969 Selection action may be updated in retrieve callback.
4970 If Selection is NULL, only initialize Question value.
4971 @param FormSet FormSet data structure.
4972 @param Form Form data structure.
4973
4974 @retval EFI_SUCCESS The function completed successfully.
4975
4976 **/
4977 EFI_STATUS
4978 LoadFormConfig (
4979 IN OUT UI_MENU_SELECTION *Selection,
4980 IN FORM_BROWSER_FORMSET *FormSet,
4981 IN FORM_BROWSER_FORM *Form
4982 )
4983 {
4984 EFI_STATUS Status;
4985 LIST_ENTRY *Link;
4986 FORM_BROWSER_STATEMENT *Question;
4987
4988 Link = GetFirstNode (&Form->StatementListHead);
4989 while (!IsNull (&Form->StatementListHead, Link)) {
4990 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
4991
4992 //
4993 // Initialize local copy of Value for each Question
4994 //
4995 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {
4996 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
4997 } else {
4998 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
4999 }
5000 if (EFI_ERROR (Status)) {
5001 return Status;
5002 }
5003
5004 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
5005 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
5006 }
5007
5008 Link = GetNextNode (&Form->StatementListHead, Link);
5009 }
5010
5011 return EFI_SUCCESS;
5012 }
5013
5014 /**
5015 Initialize Question's Edit copy from Storage for the whole Formset.
5016
5017 @param Selection Selection contains the information about
5018 the Selection, form and formset to be displayed.
5019 Selection action may be updated in retrieve callback.
5020 If Selection is NULL, only initialize Question value.
5021 @param FormSet FormSet data structure.
5022
5023 @retval EFI_SUCCESS The function completed successfully.
5024
5025 **/
5026 EFI_STATUS
5027 LoadFormSetConfig (
5028 IN OUT UI_MENU_SELECTION *Selection,
5029 IN FORM_BROWSER_FORMSET *FormSet
5030 )
5031 {
5032 EFI_STATUS Status;
5033 LIST_ENTRY *Link;
5034 FORM_BROWSER_FORM *Form;
5035
5036 Link = GetFirstNode (&FormSet->FormListHead);
5037 while (!IsNull (&FormSet->FormListHead, Link)) {
5038 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5039
5040 //
5041 // Initialize local copy of Value for each Form
5042 //
5043 Status = LoadFormConfig (Selection, FormSet, Form);
5044 if (EFI_ERROR (Status)) {
5045 return Status;
5046 }
5047
5048 Link = GetNextNode (&FormSet->FormListHead, Link);
5049 }
5050
5051 //
5052 // Finished question initialization.
5053 //
5054 FormSet->QuestionInited = TRUE;
5055
5056 return EFI_SUCCESS;
5057 }
5058
5059 /**
5060 Remove the Request element from the Config Request.
5061
5062 @param Storage Pointer to the browser storage.
5063 @param RequestElement The pointer to the Request element.
5064
5065 **/
5066 VOID
5067 RemoveElement (
5068 IN OUT BROWSER_STORAGE *Storage,
5069 IN CHAR16 *RequestElement
5070 )
5071 {
5072 CHAR16 *NewStr;
5073 CHAR16 *DestStr;
5074
5075 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL);
5076
5077 NewStr = StrStr (Storage->ConfigRequest, RequestElement);
5078
5079 if (NewStr == NULL) {
5080 return;
5081 }
5082
5083 //
5084 // Remove this element from this ConfigRequest.
5085 //
5086 DestStr = NewStr;
5087 NewStr += StrLen (RequestElement);
5088 CopyMem (DestStr, NewStr, StrSize (NewStr));
5089
5090 Storage->SpareStrLen += StrLen (RequestElement);
5091 }
5092
5093 /**
5094 Adjust config request in storage, remove the request elements existed in the input ConfigRequest.
5095
5096 @param Storage Pointer to the formset storage.
5097 @param ConfigRequest The pointer to the Request element.
5098
5099 **/
5100 VOID
5101 RemoveConfigRequest (
5102 FORMSET_STORAGE *Storage,
5103 CHAR16 *ConfigRequest
5104 )
5105 {
5106 CHAR16 *RequestElement;
5107 CHAR16 *NextRequestElement;
5108 CHAR16 *SearchKey;
5109
5110 //
5111 // No request element in it, just return.
5112 //
5113 if (ConfigRequest == NULL) {
5114 return;
5115 }
5116
5117 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
5118 //
5119 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
5120 //
5121 SearchKey = L"&";
5122 } else {
5123 //
5124 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
5125 //
5126 SearchKey = L"&OFFSET";
5127 }
5128
5129 //
5130 // Find SearchKey storage
5131 //
5132 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
5133 RequestElement = StrStr (ConfigRequest, L"PATH");
5134 ASSERT (RequestElement != NULL);
5135 RequestElement = StrStr (RequestElement, SearchKey);
5136 } else {
5137 RequestElement = StrStr (ConfigRequest, SearchKey);
5138 }
5139
5140 while (RequestElement != NULL) {
5141 //
5142 // +1 to avoid find header itself.
5143 //
5144 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
5145
5146 //
5147 // The last Request element in configRequest string.
5148 //
5149 if (NextRequestElement != NULL) {
5150 //
5151 // Replace "&" with '\0'.
5152 //
5153 *NextRequestElement = L'\0';
5154 }
5155
5156 RemoveElement (Storage->BrowserStorage, RequestElement);
5157
5158 if (NextRequestElement != NULL) {
5159 //
5160 // Restore '&' with '\0' for later used.
5161 //
5162 *NextRequestElement = L'&';
5163 }
5164
5165 RequestElement = NextRequestElement;
5166 }
5167
5168 //
5169 // If no request element remain, just remove the ConfigRequest string.
5170 //
5171 if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) {
5172 FreePool (Storage->BrowserStorage->ConfigRequest);
5173 Storage->BrowserStorage->ConfigRequest = NULL;
5174 Storage->BrowserStorage->SpareStrLen = 0;
5175 }
5176 }
5177
5178 /**
5179 Base on the current formset info, clean the ConfigRequest string in browser storage.
5180
5181 @param FormSet Pointer of the FormSet
5182
5183 **/
5184 VOID
5185 CleanBrowserStorage (
5186 IN OUT FORM_BROWSER_FORMSET *FormSet
5187 )
5188 {
5189 LIST_ENTRY *Link;
5190 FORMSET_STORAGE *Storage;
5191
5192 Link = GetFirstNode (&FormSet->StorageListHead);
5193 while (!IsNull (&FormSet->StorageListHead, Link)) {
5194 Storage = FORMSET_STORAGE_FROM_LINK (Link);
5195 Link = GetNextNode (&FormSet->StorageListHead, Link);
5196
5197 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
5198 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) {
5199 continue;
5200 }
5201
5202 RemoveConfigRequest (Storage, Storage->ConfigRequest);
5203 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||
5204 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
5205 if (Storage->BrowserStorage->ConfigRequest != NULL) {
5206 FreePool (Storage->BrowserStorage->ConfigRequest);
5207 Storage->BrowserStorage->ConfigRequest = NULL;
5208 }
5209 Storage->BrowserStorage->Initialized = FALSE;
5210 }
5211 }
5212 }
5213
5214 /**
5215 Check whether current element in the ConfigReqeust string.
5216
5217 @param BrowserStorage Storage which includes ConfigReqeust.
5218 @param RequestElement New element need to check.
5219
5220 @retval TRUE The Element is in the ConfigReqeust string.
5221 @retval FALSE The Element not in the configReqeust String.
5222
5223 **/
5224 BOOLEAN
5225 ElementValidation (
5226 BROWSER_STORAGE *BrowserStorage,
5227 CHAR16 *RequestElement
5228 )
5229 {
5230 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE;
5231 }
5232
5233 /**
5234 Append the Request element to the Config Request.
5235
5236 @param ConfigRequest Current ConfigRequest info.
5237 @param SpareStrLen Current remain free buffer for config reqeust.
5238 @param RequestElement New Request element.
5239
5240 **/
5241 VOID
5242 AppendConfigRequest (
5243 IN OUT CHAR16 **ConfigRequest,
5244 IN OUT UINTN *SpareStrLen,
5245 IN CHAR16 *RequestElement
5246 )
5247 {
5248 CHAR16 *NewStr;
5249 UINTN StringSize;
5250 UINTN StrLength;
5251 UINTN MaxLen;
5252
5253 StrLength = StrLen (RequestElement);
5254 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16);
5255 MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen;
5256
5257 //
5258 // Append <RequestElement> to <ConfigRequest>
5259 //
5260 if (StrLength > *SpareStrLen) {
5261 //
5262 // Old String buffer is not sufficient for RequestElement, allocate a new one
5263 //
5264 MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL;
5265 NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
5266 ASSERT (NewStr != NULL);
5267
5268 if (*ConfigRequest != NULL) {
5269 CopyMem (NewStr, *ConfigRequest, StringSize);
5270 FreePool (*ConfigRequest);
5271 }
5272 *ConfigRequest = NewStr;
5273 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL;
5274 }
5275
5276 StrCatS (*ConfigRequest, MaxLen, RequestElement);
5277 *SpareStrLen -= StrLength;
5278 }
5279
5280 /**
5281 Adjust the config request info, remove the request elements which already in AllConfigRequest string.
5282
5283 @param Storage Form set Storage.
5284 @param Request The input request string.
5285 @param RespString Whether the input is ConfigRequest or ConfigResp format.
5286
5287 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig
5288 @retval FALSE All elements covered by current used elements.
5289
5290 **/
5291 BOOLEAN
5292 ConfigRequestAdjust (
5293 IN BROWSER_STORAGE *Storage,
5294 IN CHAR16 *Request,
5295 IN BOOLEAN RespString
5296 )
5297 {
5298 CHAR16 *RequestElement;
5299 CHAR16 *NextRequestElement;
5300 CHAR16 *NextElementBakup;
5301 CHAR16 *SearchKey;
5302 CHAR16 *ValueKey;
5303 BOOLEAN RetVal;
5304 CHAR16 *ConfigRequest;
5305
5306 RetVal = FALSE;
5307 NextElementBakup = NULL;
5308 ValueKey = NULL;
5309
5310 if (Request != NULL) {
5311 ConfigRequest = Request;
5312 } else {
5313 ConfigRequest = Storage->ConfigRequest;
5314 }
5315
5316 if (Storage->ConfigRequest == NULL) {
5317 Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
5318 return TRUE;
5319 }
5320
5321 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
5322 //
5323 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage
5324 //
5325 SearchKey = L"&";
5326 } else {
5327 //
5328 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage
5329 //
5330 SearchKey = L"&OFFSET";
5331 ValueKey = L"&VALUE";
5332 }
5333
5334 //
5335 // Find SearchKey storage
5336 //
5337 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
5338 RequestElement = StrStr (ConfigRequest, L"PATH");
5339 ASSERT (RequestElement != NULL);
5340 RequestElement = StrStr (RequestElement, SearchKey);
5341 } else {
5342 RequestElement = StrStr (ConfigRequest, SearchKey);
5343 }
5344
5345 while (RequestElement != NULL) {
5346
5347 //
5348 // +1 to avoid find header itself.
5349 //
5350 NextRequestElement = StrStr (RequestElement + 1, SearchKey);
5351
5352 //
5353 // The last Request element in configRequest string.
5354 //
5355 if (NextRequestElement != NULL) {
5356 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
5357 NextElementBakup = NextRequestElement;
5358 NextRequestElement = StrStr (RequestElement, ValueKey);
5359 ASSERT (NextRequestElement != NULL);
5360 }
5361 //
5362 // Replace "&" with '\0'.
5363 //
5364 *NextRequestElement = L'\0';
5365 } else {
5366 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
5367 NextElementBakup = NextRequestElement;
5368 NextRequestElement = StrStr (RequestElement, ValueKey);
5369 ASSERT (NextRequestElement != NULL);
5370 //
5371 // Replace "&" with '\0'.
5372 //
5373 *NextRequestElement = L'\0';
5374 }
5375 }
5376
5377 if (!ElementValidation (Storage, RequestElement)) {
5378 //
5379 // Add this element to the Storage->BrowserStorage->AllRequestElement.
5380 //
5381 AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement);
5382 RetVal = TRUE;
5383 }
5384
5385 if (NextRequestElement != NULL) {
5386 //
5387 // Restore '&' with '\0' for later used.
5388 //
5389 *NextRequestElement = L'&';
5390 }
5391
5392 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
5393 RequestElement = NextElementBakup;
5394 } else {
5395 RequestElement = NextRequestElement;
5396 }
5397 }
5398
5399 return RetVal;
5400 }
5401
5402 /**
5403 Fill storage's edit copy with settings requested from Configuration Driver.
5404
5405 @param FormSet FormSet data structure.
5406 @param Storage Buffer Storage.
5407
5408 **/
5409 VOID
5410 LoadStorage (
5411 IN FORM_BROWSER_FORMSET *FormSet,
5412 IN FORMSET_STORAGE *Storage
5413 )
5414 {
5415 EFI_STATUS Status;
5416 EFI_STRING Progress;
5417 EFI_STRING Result;
5418 CHAR16 *StrPtr;
5419 EFI_STRING ConfigRequest;
5420 UINTN StrLen;
5421
5422 ConfigRequest = NULL;
5423
5424 switch (Storage->BrowserStorage->Type) {
5425 case EFI_HII_VARSTORE_EFI_VARIABLE:
5426 return;
5427
5428 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
5429 if (Storage->BrowserStorage->ConfigRequest != NULL) {
5430 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
5431 return;
5432 }
5433 break;
5434
5435 case EFI_HII_VARSTORE_BUFFER:
5436 case EFI_HII_VARSTORE_NAME_VALUE:
5437 //
5438 // Skip if there is no RequestElement.
5439 //
5440 if (Storage->ElementCount == 0) {
5441 return;
5442 }
5443
5444 //
5445 // Just update the ConfigRequest, if storage already initialized.
5446 //
5447 if (Storage->BrowserStorage->Initialized) {
5448 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE);
5449 return;
5450 }
5451
5452 Storage->BrowserStorage->Initialized = TRUE;
5453 break;
5454
5455 default:
5456 return;
5457 }
5458
5459 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
5460 //
5461 // Create the config request string to get all fields for this storage.
5462 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
5463 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator
5464 //
5465 StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16);
5466 ConfigRequest = AllocateZeroPool (StrLen);
5467 ASSERT (ConfigRequest != NULL);
5468 UnicodeSPrint (
5469 ConfigRequest,
5470 StrLen,
5471 L"%s&OFFSET=0&WIDTH=%04x",
5472 Storage->ConfigHdr,
5473 Storage->BrowserStorage->Size);
5474 } else {
5475 ConfigRequest = Storage->ConfigRequest;
5476 }
5477
5478 //
5479 // Request current settings from Configuration Driver
5480 //
5481 Status = mHiiConfigRouting->ExtractConfig (
5482 mHiiConfigRouting,
5483 ConfigRequest,
5484 &Progress,
5485 &Result
5486 );
5487
5488 //
5489 // If get value fail, extract default from IFR binary
5490 //
5491 if (EFI_ERROR (Status)) {
5492 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE);
5493 } else {
5494 //
5495 // Convert Result from <ConfigAltResp> to <ConfigResp>
5496 //
5497 StrPtr = StrStr (Result, L"&GUID=");
5498 if (StrPtr != NULL) {
5499 *StrPtr = L'\0';
5500 }
5501
5502 Status = ConfigRespToStorage (Storage->BrowserStorage, Result);
5503 FreePool (Result);
5504 }
5505
5506 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);
5507
5508 //
5509 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer.
5510 //
5511 SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE);
5512
5513 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
5514 if (ConfigRequest != NULL) {
5515 FreePool (ConfigRequest);
5516 }
5517 }
5518 }
5519
5520 /**
5521 Get Value changed status from old question.
5522
5523 @param NewFormSet FormSet data structure.
5524 @param OldQuestion Old question which has value changed.
5525
5526 **/
5527 VOID
5528 SyncStatusForQuestion (
5529 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5530 IN FORM_BROWSER_STATEMENT *OldQuestion
5531 )
5532 {
5533 LIST_ENTRY *Link;
5534 LIST_ENTRY *QuestionLink;
5535 FORM_BROWSER_FORM *Form;
5536 FORM_BROWSER_STATEMENT *Question;
5537
5538 //
5539 // For each form in one formset.
5540 //
5541 Link = GetFirstNode (&NewFormSet->FormListHead);
5542 while (!IsNull (&NewFormSet->FormListHead, Link)) {
5543 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5544 Link = GetNextNode (&NewFormSet->FormListHead, Link);
5545
5546 //
5547 // for each question in one form.
5548 //
5549 QuestionLink = GetFirstNode (&Form->StatementListHead);
5550 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5551 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5552 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5553
5554 if (Question->QuestionId == OldQuestion->QuestionId) {
5555 Question->ValueChanged = TRUE;
5556 return;
5557 }
5558 }
5559 }
5560 }
5561
5562 /**
5563 Get Value changed status from old formset.
5564
5565 @param NewFormSet FormSet data structure.
5566 @param OldFormSet FormSet data structure.
5567
5568 **/
5569 VOID
5570 SyncStatusForFormSet (
5571 IN OUT FORM_BROWSER_FORMSET *NewFormSet,
5572 IN FORM_BROWSER_FORMSET *OldFormSet
5573 )
5574 {
5575 LIST_ENTRY *Link;
5576 LIST_ENTRY *QuestionLink;
5577 FORM_BROWSER_FORM *Form;
5578 FORM_BROWSER_STATEMENT *Question;
5579
5580 //
5581 // For each form in one formset.
5582 //
5583 Link = GetFirstNode (&OldFormSet->FormListHead);
5584 while (!IsNull (&OldFormSet->FormListHead, Link)) {
5585 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
5586 Link = GetNextNode (&OldFormSet->FormListHead, Link);
5587
5588 //
5589 // for each question in one form.
5590 //
5591 QuestionLink = GetFirstNode (&Form->StatementListHead);
5592 while (!IsNull (&Form->StatementListHead, QuestionLink)) {
5593 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
5594 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
5595
5596 if (!Question->ValueChanged) {
5597 continue;
5598 }
5599
5600 //
5601 // Find the same question in new formset and update the value changed flag.
5602 //
5603 SyncStatusForQuestion (NewFormSet, Question);
5604 }
5605 }
5606 }
5607
5608 /**
5609 Get current setting of Questions.
5610
5611 @param FormSet FormSet data structure.
5612
5613 **/
5614 VOID
5615 InitializeCurrentSetting (
5616 IN OUT FORM_BROWSER_FORMSET *FormSet
5617 )
5618 {
5619 LIST_ENTRY *Link;
5620 FORMSET_STORAGE *Storage;
5621 FORM_BROWSER_FORMSET *OldFormSet;
5622
5623 //
5624 // Try to find pre FormSet in the maintain backup list.
5625 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.
5626 //
5627 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);
5628 if (OldFormSet != NULL) {
5629 SyncStatusForFormSet (FormSet, OldFormSet);
5630 RemoveEntryList (&OldFormSet->Link);
5631 DestroyFormSet (OldFormSet);
5632 }
5633 InsertTailList (&gBrowserFormSetList, &FormSet->Link);
5634
5635 //
5636 // Extract default from IFR binary for no storage questions.
5637 //
5638 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE);
5639
5640 //
5641 // Request current settings from Configuration Driver
5642 //
5643 Link = GetFirstNode (&FormSet->StorageListHead);
5644 while (!IsNull (&FormSet->StorageListHead, Link)) {
5645 Storage = FORMSET_STORAGE_FROM_LINK (Link);
5646
5647 LoadStorage (FormSet, Storage);
5648
5649 Link = GetNextNode (&FormSet->StorageListHead, Link);
5650 }
5651 }
5652
5653
5654 /**
5655 Fetch the Ifr binary data of a FormSet.
5656
5657 @param Handle PackageList Handle
5658 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5659 specified (NULL or zero GUID), take the first
5660 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5661 found in package list.
5662 On output, GUID of the formset found(if not NULL).
5663 @param BinaryLength The length of the FormSet IFR binary.
5664 @param BinaryData The buffer designed to receive the FormSet.
5665
5666 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
5667 BufferLength was updated.
5668 @retval EFI_INVALID_PARAMETER The handle is unknown.
5669 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
5670 be found with the requested FormId.
5671
5672 **/
5673 EFI_STATUS
5674 GetIfrBinaryData (
5675 IN EFI_HII_HANDLE Handle,
5676 IN OUT EFI_GUID *FormSetGuid,
5677 OUT UINTN *BinaryLength,
5678 OUT UINT8 **BinaryData
5679 )
5680 {
5681 EFI_STATUS Status;
5682 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
5683 UINTN BufferSize;
5684 UINT8 *Package;
5685 UINT8 *OpCodeData;
5686 UINT32 Offset;
5687 UINT32 Offset2;
5688 UINT32 PackageListLength;
5689 EFI_HII_PACKAGE_HEADER PackageHeader;
5690 UINT8 Index;
5691 UINT8 NumberOfClassGuid;
5692 BOOLEAN ClassGuidMatch;
5693 EFI_GUID *ClassGuid;
5694 EFI_GUID *ComparingGuid;
5695
5696 OpCodeData = NULL;
5697 Package = NULL;
5698 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
5699
5700 //
5701 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
5702 //
5703 if (FormSetGuid == NULL) {
5704 ComparingGuid = &gZeroGuid;
5705 } else {
5706 ComparingGuid = FormSetGuid;
5707 }
5708
5709 //
5710 // Get HII PackageList
5711 //
5712 BufferSize = 0;
5713 HiiPackageList = NULL;
5714 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5715 if (Status == EFI_BUFFER_TOO_SMALL) {
5716 HiiPackageList = AllocatePool (BufferSize);
5717 ASSERT (HiiPackageList != NULL);
5718
5719 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
5720 }
5721 if (EFI_ERROR (Status)) {
5722 return Status;
5723 }
5724 ASSERT (HiiPackageList != NULL);
5725
5726 //
5727 // Get Form package from this HII package List
5728 //
5729 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
5730 Offset2 = 0;
5731 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
5732
5733 ClassGuidMatch = FALSE;
5734 while (Offset < PackageListLength) {
5735 Package = ((UINT8 *) HiiPackageList) + Offset;
5736 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
5737
5738 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
5739 //
5740 // Search FormSet in this Form Package
5741 //
5742 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
5743 while (Offset2 < PackageHeader.Length) {
5744 OpCodeData = Package + Offset2;
5745
5746 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
5747 //
5748 // Try to compare against formset GUID
5749 //
5750 if (IsZeroGuid (FormSetGuid) ||
5751 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
5752 break;
5753 }
5754
5755 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
5756 //
5757 // Try to compare against formset class GUID
5758 //
5759 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
5760 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
5761 for (Index = 0; Index < NumberOfClassGuid; Index++) {
5762 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
5763 ClassGuidMatch = TRUE;
5764 break;
5765 }
5766 }
5767 if (ClassGuidMatch) {
5768 break;
5769 }
5770 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
5771 ClassGuidMatch = TRUE;
5772 break;
5773 }
5774 }
5775
5776 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
5777 }
5778
5779 if (Offset2 < PackageHeader.Length) {
5780 //
5781 // Target formset found
5782 //
5783 break;
5784 }
5785 }
5786
5787 Offset += PackageHeader.Length;
5788 }
5789
5790 if (Offset >= PackageListLength) {
5791 //
5792 // Form package not found in this Package List
5793 //
5794 FreePool (HiiPackageList);
5795 return EFI_NOT_FOUND;
5796 }
5797
5798 if (FormSetGuid != NULL) {
5799 //
5800 // Return the FormSet GUID
5801 //
5802 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
5803 }
5804
5805 //
5806 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
5807 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
5808 // of the Form Package.
5809 //
5810 *BinaryLength = PackageHeader.Length - Offset2;
5811 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
5812
5813 FreePool (HiiPackageList);
5814
5815 if (*BinaryData == NULL) {
5816 return EFI_OUT_OF_RESOURCES;
5817 }
5818
5819 return EFI_SUCCESS;
5820 }
5821
5822
5823 /**
5824 Initialize the internal data structure of a FormSet.
5825
5826 @param Handle PackageList Handle
5827 @param FormSetGuid On input, GUID or class GUID of a formset. If not
5828 specified (NULL or zero GUID), take the first
5829 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
5830 found in package list.
5831 On output, GUID of the formset found(if not NULL).
5832 @param FormSet FormSet data structure.
5833
5834 @retval EFI_SUCCESS The function completed successfully.
5835 @retval EFI_NOT_FOUND The specified FormSet could not be found.
5836
5837 **/
5838 EFI_STATUS
5839 InitializeFormSet (
5840 IN EFI_HII_HANDLE Handle,
5841 IN OUT EFI_GUID *FormSetGuid,
5842 OUT FORM_BROWSER_FORMSET *FormSet
5843 )
5844 {
5845 EFI_STATUS Status;
5846 EFI_HANDLE DriverHandle;
5847
5848 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
5849 if (EFI_ERROR (Status)) {
5850 return Status;
5851 }
5852
5853 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
5854 FormSet->HiiHandle = Handle;
5855 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
5856 FormSet->QuestionInited = FALSE;
5857
5858 //
5859 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
5860 //
5861 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
5862 if (EFI_ERROR (Status)) {
5863 return Status;
5864 }
5865 FormSet->DriverHandle = DriverHandle;
5866 Status = gBS->HandleProtocol (
5867 DriverHandle,
5868 &gEfiHiiConfigAccessProtocolGuid,
5869 (VOID **) &FormSet->ConfigAccess
5870 );
5871 if (EFI_ERROR (Status)) {
5872 //
5873 // Configuration Driver don't attach ConfigAccess protocol to its HII package
5874 // list, then there will be no configuration action required
5875 //
5876 FormSet->ConfigAccess = NULL;
5877 }
5878
5879 //
5880 // Parse the IFR binary OpCodes
5881 //
5882 Status = ParseOpCodes (FormSet);
5883
5884 return Status;
5885 }
5886
5887
5888 /**
5889 Save globals used by previous call to SendForm(). SendForm() may be called from
5890 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
5891 So, save globals of previous call to SendForm() and restore them upon exit.
5892
5893 **/
5894 VOID
5895 SaveBrowserContext (
5896 VOID
5897 )
5898 {
5899 BROWSER_CONTEXT *Context;
5900 FORM_ENTRY_INFO *MenuList;
5901 FORM_BROWSER_FORMSET *FormSet;
5902
5903 gBrowserContextCount++;
5904 if (gBrowserContextCount == 1) {
5905 //
5906 // This is not reentry of SendForm(), no context to save
5907 //
5908 return;
5909 }
5910
5911 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
5912 ASSERT (Context != NULL);
5913
5914 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
5915
5916 //
5917 // Save FormBrowser context
5918 //
5919 Context->Selection = gCurrentSelection;
5920 Context->ResetRequired = gResetRequired;
5921 Context->FlagReconnect = gFlagReconnect;
5922 Context->CallbackReconnect = gCallbackReconnect;
5923 Context->ExitRequired = gExitRequired;
5924 Context->HiiHandle = mCurrentHiiHandle;
5925 Context->FormId = mCurrentFormId;
5926 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid);
5927 Context->SystemLevelFormSet = mSystemLevelFormSet;
5928 Context->CurFakeQestId = mCurFakeQestId;
5929 Context->HiiPackageListUpdated = mHiiPackageListUpdated;
5930 Context->FinishRetrieveCall = mFinishRetrieveCall;
5931
5932 //
5933 // Save the menu history data.
5934 //
5935 InitializeListHead(&Context->FormHistoryList);
5936 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {
5937 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);
5938 RemoveEntryList (&MenuList->Link);
5939
5940 InsertTailList(&Context->FormHistoryList, &MenuList->Link);
5941 }
5942
5943 //
5944 // Save formset list.
5945 //
5946 InitializeListHead(&Context->FormSetList);
5947 while (!IsListEmpty (&gBrowserFormSetList)) {
5948 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink);
5949 RemoveEntryList (&FormSet->Link);
5950
5951 InsertTailList(&Context->FormSetList, &FormSet->Link);
5952 }
5953
5954 //
5955 // Insert to FormBrowser context list
5956 //
5957 InsertHeadList (&gBrowserContextList, &Context->Link);
5958 }
5959
5960
5961 /**
5962 Restore globals used by previous call to SendForm().
5963
5964 **/
5965 VOID
5966 RestoreBrowserContext (
5967 VOID
5968 )
5969 {
5970 LIST_ENTRY *Link;
5971 BROWSER_CONTEXT *Context;
5972 FORM_ENTRY_INFO *MenuList;
5973 FORM_BROWSER_FORMSET *FormSet;
5974
5975 ASSERT (gBrowserContextCount != 0);
5976 gBrowserContextCount--;
5977 if (gBrowserContextCount == 0) {
5978 //
5979 // This is not reentry of SendForm(), no context to restore
5980 //
5981 return;
5982 }
5983
5984 ASSERT (!IsListEmpty (&gBrowserContextList));
5985
5986 Link = GetFirstNode (&gBrowserContextList);
5987 Context = BROWSER_CONTEXT_FROM_LINK (Link);
5988
5989 //
5990 // Restore FormBrowser context
5991 //
5992 gCurrentSelection = Context->Selection;
5993 gResetRequired = Context->ResetRequired;
5994 gFlagReconnect = Context->FlagReconnect;
5995 gCallbackReconnect = Context->CallbackReconnect;
5996 gExitRequired = Context->ExitRequired;
5997 mCurrentHiiHandle = Context->HiiHandle;
5998 mCurrentFormId = Context->FormId;
5999 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid);
6000 mSystemLevelFormSet = Context->SystemLevelFormSet;
6001 mCurFakeQestId = Context->CurFakeQestId;
6002 mHiiPackageListUpdated = Context->HiiPackageListUpdated;
6003 mFinishRetrieveCall = Context->FinishRetrieveCall;
6004
6005 //
6006 // Restore the menu history data.
6007 //
6008 while (!IsListEmpty (&Context->FormHistoryList)) {
6009 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);
6010 RemoveEntryList (&MenuList->Link);
6011
6012 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);
6013 }
6014
6015 //
6016 // Restore the Formset data.
6017 //
6018 while (!IsListEmpty (&Context->FormSetList)) {
6019 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink);
6020 RemoveEntryList (&FormSet->Link);
6021
6022 InsertTailList(&gBrowserFormSetList, &FormSet->Link);
6023 }
6024
6025 //
6026 // Remove from FormBrowser context list
6027 //
6028 RemoveEntryList (&Context->Link);
6029 gBS->FreePool (Context);
6030 }
6031
6032 /**
6033 Find the matched FormSet context in the backup maintain list based on HiiHandle.
6034
6035 @param Handle The Hii Handle.
6036
6037 @return the found FormSet context. If no found, NULL will return.
6038
6039 **/
6040 FORM_BROWSER_FORMSET *
6041 GetFormSetFromHiiHandle (
6042 EFI_HII_HANDLE Handle
6043 )
6044 {
6045 LIST_ENTRY *Link;
6046 FORM_BROWSER_FORMSET *FormSet;
6047
6048 Link = GetFirstNode (&gBrowserFormSetList);
6049 while (!IsNull (&gBrowserFormSetList, Link)) {
6050 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6051 Link = GetNextNode (&gBrowserFormSetList, Link);
6052 if (!ValidateFormSet(FormSet)) {
6053 continue;
6054 }
6055 if (FormSet->HiiHandle == Handle) {
6056 return FormSet;
6057 }
6058 }
6059
6060 return NULL;
6061 }
6062
6063 /**
6064 Check whether the input HII handle is the FormSet that is being used.
6065
6066 @param Handle The Hii Handle.
6067
6068 @retval TRUE HII handle is being used.
6069 @retval FALSE HII handle is not being used.
6070
6071 **/
6072 BOOLEAN
6073 IsHiiHandleInBrowserContext (
6074 EFI_HII_HANDLE Handle
6075 )
6076 {
6077 LIST_ENTRY *Link;
6078 BROWSER_CONTEXT *Context;
6079
6080 //
6081 // HiiHandle is Current FormSet.
6082 //
6083 if (mCurrentHiiHandle == Handle) {
6084 return TRUE;
6085 }
6086
6087 //
6088 // Check whether HiiHandle is in BrowserContext.
6089 //
6090 Link = GetFirstNode (&gBrowserContextList);
6091 while (!IsNull (&gBrowserContextList, Link)) {
6092 Context = BROWSER_CONTEXT_FROM_LINK (Link);
6093 if (Context->HiiHandle == Handle) {
6094 //
6095 // HiiHandle is in BrowserContext
6096 //
6097 return TRUE;
6098 }
6099 Link = GetNextNode (&gBrowserContextList, Link);
6100 }
6101
6102 return FALSE;
6103 }
6104
6105 /**
6106 Perform Password check.
6107 Passwork may be encrypted by driver that requires the specific check.
6108
6109 @param Form Form where Password Statement is in.
6110 @param Statement Password statement
6111 @param PasswordString Password string to be checked. It may be NULL.
6112 NULL means to restore password.
6113 "" string can be used to checked whether old password does exist.
6114
6115 @return Status Status of Password check.
6116 **/
6117 EFI_STATUS
6118 EFIAPI
6119 PasswordCheck (
6120 IN FORM_DISPLAY_ENGINE_FORM *Form,
6121 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
6122 IN EFI_STRING PasswordString OPTIONAL
6123 )
6124 {
6125 EFI_STATUS Status;
6126 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
6127 EFI_BROWSER_ACTION_REQUEST ActionRequest;
6128 EFI_IFR_TYPE_VALUE IfrTypeValue;
6129 FORM_BROWSER_STATEMENT *Question;
6130
6131 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;
6132 Question = GetBrowserStatement(Statement);
6133 ASSERT (Question != NULL);
6134
6135 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {
6136 if (ConfigAccess == NULL) {
6137 return EFI_UNSUPPORTED;
6138 }
6139 } else {
6140 //
6141 // If a password doesn't have the CALLBACK flag, browser will not handle it.
6142 //
6143 return EFI_UNSUPPORTED;
6144 }
6145
6146 //
6147 // Prepare password string in HII database
6148 //
6149 if (PasswordString != NULL) {
6150 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);
6151 } else {
6152 IfrTypeValue.string = 0;
6153 }
6154
6155 //
6156 // Send password to Configuration Driver for validation
6157 //
6158 Status = ConfigAccess->Callback (
6159 ConfigAccess,
6160 EFI_BROWSER_ACTION_CHANGING,
6161 Question->QuestionId,
6162 Question->HiiValue.Type,
6163 &IfrTypeValue,
6164 &ActionRequest
6165 );
6166
6167 //
6168 // Remove password string from HII database
6169 //
6170 if (PasswordString != NULL) {
6171 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);
6172 }
6173
6174 return Status;
6175 }
6176
6177 /**
6178 Find the registered HotKey based on KeyData.
6179
6180 @param[in] KeyData A pointer to a buffer that describes the keystroke
6181 information for the hot key.
6182
6183 @return The registered HotKey context. If no found, NULL will return.
6184 **/
6185 BROWSER_HOT_KEY *
6186 GetHotKeyFromRegisterList (
6187 IN EFI_INPUT_KEY *KeyData
6188 )
6189 {
6190 LIST_ENTRY *Link;
6191 BROWSER_HOT_KEY *HotKey;
6192
6193 Link = GetFirstNode (&gBrowserHotKeyList);
6194 while (!IsNull (&gBrowserHotKeyList, Link)) {
6195 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
6196 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
6197 return HotKey;
6198 }
6199 Link = GetNextNode (&gBrowserHotKeyList, Link);
6200 }
6201
6202 return NULL;
6203 }
6204
6205 /**
6206 Configure what scope the hot key will impact.
6207 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
6208 If no scope is set, the default scope will be FormSet level.
6209 After all registered hot keys are removed, previous Scope can reset to another level.
6210
6211 @param[in] Scope Scope level to be set.
6212
6213 @retval EFI_SUCCESS Scope is set correctly.
6214 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
6215 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
6216
6217 **/
6218 EFI_STATUS
6219 EFIAPI
6220 SetScope (
6221 IN BROWSER_SETTING_SCOPE Scope
6222 )
6223 {
6224 if (Scope >= MaxLevel) {
6225 return EFI_INVALID_PARAMETER;
6226 }
6227
6228 //
6229 // When no hot key registered in system or on the first setting,
6230 // Scope can be set.
6231 //
6232 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
6233 gBrowserSettingScope = Scope;
6234 mBrowserScopeFirstSet = FALSE;
6235 } else if (Scope != gBrowserSettingScope) {
6236 return EFI_UNSUPPORTED;
6237 }
6238
6239 return EFI_SUCCESS;
6240 }
6241
6242 /**
6243 Register the hot key with its browser action, or unregistered the hot key.
6244 Only support hot key that is not printable character (control key, function key, etc.).
6245 If the action value is zero, the hot key will be unregistered if it has been registered.
6246 If the same hot key has been registered, the new action and help string will override the previous ones.
6247
6248 @param[in] KeyData A pointer to a buffer that describes the keystroke
6249 information for the hot key. Its type is EFI_INPUT_KEY to
6250 be supported by all ConsoleIn devices.
6251 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
6252 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
6253 @param[in] HelpString Help string that describes the hot key information.
6254 Its value may be NULL for the unregistered hot key.
6255
6256 @retval EFI_SUCCESS Hot key is registered or unregistered.
6257 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
6258 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
6259 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
6260 @retval EFI_ALREADY_STARTED Key already been registered for one hot key.
6261 **/
6262 EFI_STATUS
6263 EFIAPI
6264 RegisterHotKey (
6265 IN EFI_INPUT_KEY *KeyData,
6266 IN UINT32 Action,
6267 IN UINT16 DefaultId,
6268 IN EFI_STRING HelpString OPTIONAL
6269 )
6270 {
6271 BROWSER_HOT_KEY *HotKey;
6272
6273 //
6274 // Check input parameters.
6275 //
6276 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
6277 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
6278 return EFI_INVALID_PARAMETER;
6279 }
6280
6281 //
6282 // Check whether the input KeyData is in BrowserHotKeyList.
6283 //
6284 HotKey = GetHotKeyFromRegisterList (KeyData);
6285
6286 //
6287 // Unregister HotKey
6288 //
6289 if (Action == BROWSER_ACTION_UNREGISTER) {
6290 if (HotKey != NULL) {
6291 //
6292 // The registered HotKey is found.
6293 // Remove it from List, and free its resource.
6294 //
6295 RemoveEntryList (&HotKey->Link);
6296 FreePool (HotKey->KeyData);
6297 FreePool (HotKey->HelpString);
6298 return EFI_SUCCESS;
6299 } else {
6300 //
6301 // The registered HotKey is not found.
6302 //
6303 return EFI_NOT_FOUND;
6304 }
6305 }
6306
6307 if (HotKey != NULL) {
6308 return EFI_ALREADY_STARTED;
6309 }
6310
6311 //
6312 // Create new Key, and add it into List.
6313 //
6314 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
6315 ASSERT (HotKey != NULL);
6316 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
6317 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
6318 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
6319
6320 //
6321 // Fill HotKey information.
6322 //
6323 HotKey->Action = Action;
6324 HotKey->DefaultId = DefaultId;
6325 if (HotKey->HelpString != NULL) {
6326 FreePool (HotKey->HelpString);
6327 }
6328 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
6329
6330 return EFI_SUCCESS;
6331 }
6332
6333 /**
6334 Register Exit handler function.
6335 When more than one handler function is registered, the latter one will override the previous one.
6336 When NULL handler is specified, the previous Exit handler will be unregistered.
6337
6338 @param[in] Handler Pointer to handler function.
6339
6340 **/
6341 VOID
6342 EFIAPI
6343 RegiserExitHandler (
6344 IN EXIT_HANDLER Handler
6345 )
6346 {
6347 ExitHandlerFunction = Handler;
6348 return;
6349 }
6350
6351 /**
6352 Check whether the browser data has been modified.
6353
6354 @retval TRUE Browser data is modified.
6355 @retval FALSE No browser data is modified.
6356
6357 **/
6358 BOOLEAN
6359 EFIAPI
6360 IsBrowserDataModified (
6361 VOID
6362 )
6363 {
6364 LIST_ENTRY *Link;
6365 FORM_BROWSER_FORMSET *FormSet;
6366
6367 switch (gBrowserSettingScope) {
6368 case FormLevel:
6369 if (gCurrentSelection == NULL) {
6370 return FALSE;
6371 }
6372 return IsNvUpdateRequiredForForm (gCurrentSelection->Form);
6373
6374 case FormSetLevel:
6375 if (gCurrentSelection == NULL) {
6376 return FALSE;
6377 }
6378 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);
6379
6380 case SystemLevel:
6381 Link = GetFirstNode (&gBrowserFormSetList);
6382 while (!IsNull (&gBrowserFormSetList, Link)) {
6383 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6384 if (!ValidateFormSet(FormSet)) {
6385 continue;
6386 }
6387
6388 if (IsNvUpdateRequiredForFormSet (FormSet)) {
6389 return TRUE;
6390 }
6391 Link = GetNextNode (&gBrowserFormSetList, Link);
6392 }
6393 return FALSE;
6394
6395 default:
6396 return FALSE;
6397 }
6398 }
6399
6400 /**
6401 Execute the action requested by the Action parameter.
6402
6403 @param[in] Action Execute the request action.
6404 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.
6405
6406 @retval EFI_SUCCESS Execute the request action succss.
6407 @retval EFI_INVALID_PARAMETER The input action value is invalid.
6408
6409 **/
6410 EFI_STATUS
6411 EFIAPI
6412 ExecuteAction (
6413 IN UINT32 Action,
6414 IN UINT16 DefaultId
6415 )
6416 {
6417 EFI_STATUS Status;
6418 FORM_BROWSER_FORMSET *FormSet;
6419 FORM_BROWSER_FORM *Form;
6420
6421 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) {
6422 return EFI_NOT_READY;
6423 }
6424
6425 Status = EFI_SUCCESS;
6426 FormSet = NULL;
6427 Form = NULL;
6428 if (gBrowserSettingScope < SystemLevel) {
6429 FormSet = gCurrentSelection->FormSet;
6430 Form = gCurrentSelection->Form;
6431 }
6432
6433 //
6434 // Executet the discard action.
6435 //
6436 if ((Action & BROWSER_ACTION_DISCARD) != 0) {
6437 Status = DiscardForm (FormSet, Form, gBrowserSettingScope);
6438 if (EFI_ERROR (Status)) {
6439 return Status;
6440 }
6441 }
6442
6443 //
6444 // Executet the difault action.
6445 //
6446 if ((Action & BROWSER_ACTION_DEFAULT) != 0) {
6447 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
6448 if (EFI_ERROR (Status)) {
6449 return Status;
6450 }
6451 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope);
6452 }
6453
6454 //
6455 // Executet the submit action.
6456 //
6457 if ((Action & BROWSER_ACTION_SUBMIT) != 0) {
6458 Status = SubmitForm (FormSet, Form, gBrowserSettingScope);
6459 if (EFI_ERROR (Status)) {
6460 return Status;
6461 }
6462 }
6463
6464 //
6465 // Executet the reset action.
6466 //
6467 if ((Action & BROWSER_ACTION_RESET) != 0) {
6468 gResetRequired = TRUE;
6469 }
6470
6471 //
6472 // Executet the exit action.
6473 //
6474 if ((Action & BROWSER_ACTION_EXIT) != 0) {
6475 DiscardForm (FormSet, Form, gBrowserSettingScope);
6476 if (gBrowserSettingScope == SystemLevel) {
6477 if (ExitHandlerFunction != NULL) {
6478 ExitHandlerFunction ();
6479 }
6480 }
6481
6482 gExitRequired = TRUE;
6483 }
6484
6485 return Status;
6486 }
6487
6488 /**
6489 Create reminder to let user to choose save or discard the changed browser data.
6490 Caller can use it to actively check the changed browser data.
6491
6492 @retval BROWSER_NO_CHANGES No browser data is changed.
6493 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
6494 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
6495 @retval BROWSER_KEEP_CURRENT Browser keep current changes.
6496
6497 **/
6498 UINT32
6499 EFIAPI
6500 SaveReminder (
6501 VOID
6502 )
6503 {
6504 LIST_ENTRY *Link;
6505 FORM_BROWSER_FORMSET *FormSet;
6506 BOOLEAN IsDataChanged;
6507 UINT32 DataSavedAction;
6508 UINT32 ConfirmRet;
6509
6510 DataSavedAction = BROWSER_NO_CHANGES;
6511 IsDataChanged = FALSE;
6512 Link = GetFirstNode (&gBrowserFormSetList);
6513 while (!IsNull (&gBrowserFormSetList, Link)) {
6514 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
6515 Link = GetNextNode (&gBrowserFormSetList, Link);
6516 if (!ValidateFormSet(FormSet)) {
6517 continue;
6518 }
6519 if (IsNvUpdateRequiredForFormSet (FormSet)) {
6520 IsDataChanged = TRUE;
6521 break;
6522 }
6523 }
6524
6525 //
6526 // No data is changed. No save is required.
6527 //
6528 if (!IsDataChanged) {
6529 return DataSavedAction;
6530 }
6531
6532 //
6533 // If data is changed, prompt user to save or discard it.
6534 //
6535 do {
6536 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange();
6537
6538 if (ConfirmRet == BROWSER_ACTION_SUBMIT) {
6539 SubmitForm (NULL, NULL, SystemLevel);
6540 DataSavedAction = BROWSER_SAVE_CHANGES;
6541 break;
6542 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) {
6543 DiscardForm (NULL, NULL, SystemLevel);
6544 DataSavedAction = BROWSER_DISCARD_CHANGES;
6545 break;
6546 } else if (ConfirmRet == BROWSER_ACTION_NONE) {
6547 DataSavedAction = BROWSER_KEEP_CURRENT;
6548 break;
6549 }
6550 } while (1);
6551
6552 return DataSavedAction;
6553 }
6554
6555 /**
6556 Check whether the Reset Required for the browser
6557
6558 @retval TRUE Browser required to reset after exit.
6559 @retval FALSE Browser not need to reset after exit.
6560
6561 **/
6562 BOOLEAN
6563 EFIAPI
6564 IsResetRequired (
6565 VOID
6566 )
6567 {
6568 return gResetRequired;
6569 }
6570