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