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