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