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