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