]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
MdeModulePkg: Remove variables that are set, but not used
[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 do {
326 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
327 ASSERT (FormSet != NULL);
328
329 //
330 // Initialize internal data structures of FormSet
331 //
332 Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
333 if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
334 DestroyFormSet (FormSet);
335 break;
336 }
337 Selection->FormSet = FormSet;
338
339 //
340 // Try to find pre FormSet in the maintain backup list.
341 //
342 gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle);
343
344 //
345 // Display this formset
346 //
347 gCurrentSelection = Selection;
348
349 Status = SetupBrowser (Selection);
350
351 gCurrentSelection = NULL;
352
353 if (EFI_ERROR (Status)) {
354 break;
355 }
356
357 } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
358
359 if (gOldFormSet != NULL) {
360 //
361 // If no data is changed, don't need to save current FormSet into the maintain list.
362 //
363 if (!IsNvUpdateRequired (gOldFormSet)) {
364 RemoveEntryList (&gOldFormSet->Link);
365 DestroyFormSet (gOldFormSet);
366 }
367 gOldFormSet = NULL;
368 }
369
370 FreePool (Selection);
371 }
372
373 if (ActionRequest != NULL) {
374 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
375 if (gResetRequired) {
376 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
377 }
378 }
379
380 FreeBrowserStrings ();
381
382 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
383 gST->ConOut->ClearScreen (gST->ConOut);
384
385 Done:
386 //
387 // Restore globals used by SendForm()
388 //
389 RestoreBrowserContext ();
390
391 return Status;
392 }
393
394
395 /**
396 This function is called by a callback handler to retrieve uncommitted state
397 data from the browser.
398
399 @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
400 instance.
401 @param ResultsDataSize A pointer to the size of the buffer associated
402 with ResultsData.
403 @param ResultsData A string returned from an IFR browser or
404 equivalent. The results string will have no
405 routing information in them.
406 @param RetrieveData A BOOLEAN field which allows an agent to retrieve
407 (if RetrieveData = TRUE) data from the uncommitted
408 browser state information or set (if RetrieveData
409 = FALSE) data in the uncommitted browser state
410 information.
411 @param VariableGuid An optional field to indicate the target variable
412 GUID name to use.
413 @param VariableName An optional field to indicate the target
414 human-readable variable name.
415
416 @retval EFI_SUCCESS The results have been distributed or are awaiting
417 distribution.
418 @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
419 contain the results data.
420
421 **/
422 EFI_STATUS
423 EFIAPI
424 BrowserCallback (
425 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
426 IN OUT UINTN *ResultsDataSize,
427 IN OUT EFI_STRING ResultsData,
428 IN BOOLEAN RetrieveData,
429 IN CONST EFI_GUID *VariableGuid, OPTIONAL
430 IN CONST CHAR16 *VariableName OPTIONAL
431 )
432 {
433 EFI_STATUS Status;
434 LIST_ENTRY *Link;
435 FORMSET_STORAGE *Storage;
436 FORM_BROWSER_FORMSET *FormSet;
437 BOOLEAN Found;
438 CHAR16 *ConfigResp;
439 CHAR16 *StrPtr;
440 UINTN BufferSize;
441 UINTN TmpSize;
442
443 if (ResultsDataSize == NULL || ResultsData == NULL) {
444 return EFI_INVALID_PARAMETER;
445 }
446
447 if (gCurrentSelection == NULL) {
448 return EFI_NOT_READY;
449 }
450
451 Storage = NULL;
452 ConfigResp = NULL;
453 FormSet = gCurrentSelection->FormSet;
454
455 //
456 // Find target storage
457 //
458 Link = GetFirstNode (&FormSet->StorageListHead);
459 if (IsNull (&FormSet->StorageListHead, Link)) {
460 return EFI_UNSUPPORTED;
461 }
462
463 if (VariableGuid != NULL) {
464 //
465 // Try to find target storage
466 //
467 Found = FALSE;
468 while (!IsNull (&FormSet->StorageListHead, Link)) {
469 Storage = FORMSET_STORAGE_FROM_LINK (Link);
470 Link = GetNextNode (&FormSet->StorageListHead, Link);
471
472 if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
473 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
474 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
475 //
476 // Buffer storage require both GUID and Name
477 //
478 if (VariableName == NULL) {
479 return EFI_NOT_FOUND;
480 }
481
482 if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
483 continue;
484 }
485 }
486 Found = TRUE;
487 break;
488 }
489 }
490
491 if (!Found) {
492 return EFI_NOT_FOUND;
493 }
494 } else {
495 //
496 // GUID/Name is not specified, take the first storage in FormSet
497 //
498 Storage = FORMSET_STORAGE_FROM_LINK (Link);
499 }
500
501 if (RetrieveData) {
502 //
503 // Skip if there is no RequestElement
504 //
505 if (Storage->ElementCount == 0) {
506 return EFI_SUCCESS;
507 }
508
509 //
510 // Generate <ConfigResp>
511 //
512 Status = StorageToConfigResp (Storage, &ConfigResp, FALSE);
513 if (EFI_ERROR (Status)) {
514 return Status;
515 }
516
517 //
518 // Skip <ConfigHdr> and '&' to point to <ConfigBody>
519 //
520 StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;
521
522 BufferSize = StrSize (StrPtr);
523 if (*ResultsDataSize < BufferSize) {
524 *ResultsDataSize = BufferSize;
525
526 FreePool (ConfigResp);
527 return EFI_BUFFER_TOO_SMALL;
528 }
529
530 *ResultsDataSize = BufferSize;
531 CopyMem (ResultsData, StrPtr, BufferSize);
532
533 FreePool (ConfigResp);
534 } else {
535 //
536 // Prepare <ConfigResp>
537 //
538 TmpSize = StrLen (ResultsData);
539 BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);
540 ConfigResp = AllocateZeroPool (BufferSize);
541 ASSERT (ConfigResp != NULL);
542
543 StrCpy (ConfigResp, Storage->ConfigHdr);
544 StrCat (ConfigResp, L"&");
545 StrCat (ConfigResp, ResultsData);
546
547 //
548 // Update Browser uncommited data
549 //
550 Status = ConfigRespToStorage (Storage, ConfigResp);
551 if (EFI_ERROR (Status)) {
552 return Status;
553 }
554 }
555
556 return EFI_SUCCESS;
557 }
558
559 /**
560 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 if (IsBufferStorage) {
1451 Value = StrStr (Result, L"&VALUE");
1452 if (Value == NULL) {
1453 FreePool (Result);
1454 return EFI_NOT_FOUND;
1455 }
1456 //
1457 // Skip "&VALUE"
1458 //
1459 Value = Value + 6;
1460 } else {
1461 Value = Result + Length;
1462 }
1463 if (*Value != '=') {
1464 FreePool (Result);
1465 return EFI_NOT_FOUND;
1466 }
1467 //
1468 // Skip '=', point to value
1469 //
1470 Value = Value + 1;
1471
1472 //
1473 // Suppress <AltResp> if any
1474 //
1475 StringPtr = Value;
1476 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1477 StringPtr++;
1478 }
1479 *StringPtr = L'\0';
1480
1481 LengthStr = StrLen (Value);
1482 Status = EFI_SUCCESS;
1483 if (!IsBufferStorage && IsString) {
1484 //
1485 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1486 // Add string tail char L'\0' into Length
1487 //
1488 Length = StorageWidth + sizeof (CHAR16);
1489 if (Length < ((LengthStr / 4 + 1) * 2)) {
1490 Status = EFI_BUFFER_TOO_SMALL;
1491 } else {
1492 StringPtr = (CHAR16 *) Dst;
1493 ZeroMem (TemStr, sizeof (TemStr));
1494 for (Index = 0; Index < LengthStr; Index += 4) {
1495 StrnCpy (TemStr, Value + Index, 4);
1496 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1497 }
1498 //
1499 // Add tailing L'\0' character
1500 //
1501 StringPtr[Index/4] = L'\0';
1502 }
1503 } else {
1504 if (StorageWidth < ((LengthStr + 1) / 2)) {
1505 Status = EFI_BUFFER_TOO_SMALL;
1506 } else {
1507 ZeroMem (TemStr, sizeof (TemStr));
1508 for (Index = 0; Index < LengthStr; Index ++) {
1509 TemStr[0] = Value[LengthStr - Index - 1];
1510 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1511 if ((Index & 1) == 0) {
1512 Dst [Index/2] = DigitUint8;
1513 } else {
1514 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1515 }
1516 }
1517 }
1518 }
1519 FreePool (Result);
1520
1521 if (EFI_ERROR (Status)) {
1522 return Status;
1523 }
1524 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1525 TemBuffer = NULL;
1526 TemBuffer = AllocateZeroPool (Storage->Size);
1527 if (TemBuffer == NULL) {
1528 Status = EFI_OUT_OF_RESOURCES;
1529 return Status;
1530 }
1531 Length = Storage->Size;
1532 Status = gRT->GetVariable (
1533 Storage->Name,
1534 &Storage->Guid,
1535 NULL,
1536 &Length,
1537 TemBuffer
1538 );
1539 if (EFI_ERROR (Status)) {
1540 FreePool (TemBuffer);
1541 return Status;
1542 }
1543
1544 CopyMem (Dst, TemBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1545
1546 FreePool (TemBuffer);
1547 }
1548
1549 //
1550 // Synchronize Edit Buffer
1551 //
1552 if (IsBufferStorage) {
1553 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
1554 } else {
1555 SetValueByName (Storage, Question->VariableName, Value, TRUE);
1556 }
1557 }
1558
1559 return Status;
1560 }
1561
1562
1563 /**
1564 Save Question Value to edit copy(cached) or Storage(uncached).
1565
1566 @param FormSet FormSet data structure.
1567 @param Form Form data structure.
1568 @param Question Pointer to the Question.
1569 @param Cached TRUE: set to Edit copy FALSE: set to original
1570 Storage
1571
1572 @retval EFI_SUCCESS The function completed successfully.
1573
1574 **/
1575 EFI_STATUS
1576 SetQuestionValue (
1577 IN FORM_BROWSER_FORMSET *FormSet,
1578 IN FORM_BROWSER_FORM *Form,
1579 IN OUT FORM_BROWSER_STATEMENT *Question,
1580 IN BOOLEAN Cached
1581 )
1582 {
1583 EFI_STATUS Status;
1584 BOOLEAN Enabled;
1585 BOOLEAN Pending;
1586 UINT8 *Src;
1587 EFI_TIME EfiTime;
1588 UINTN BufferLen;
1589 UINTN StorageWidth;
1590 FORMSET_STORAGE *Storage;
1591 EFI_IFR_TYPE_VALUE *QuestionValue;
1592 CHAR16 *ConfigResp;
1593 CHAR16 *Progress;
1594 CHAR16 *Value;
1595 UINTN Length;
1596 BOOLEAN IsBufferStorage;
1597 BOOLEAN IsString;
1598 UINT8 *TemBuffer;
1599 CHAR16 *TemName;
1600 CHAR16 *TemString;
1601 UINTN Index;
1602
1603 Status = EFI_SUCCESS;
1604
1605 //
1606 // Statement don't have storage, skip them
1607 //
1608 if (Question->QuestionId == 0) {
1609 return Status;
1610 }
1611
1612 //
1613 // If Question value is provided by an Expression, then it is read only
1614 //
1615 if (Question->ValueExpression != NULL) {
1616 return Status;
1617 }
1618
1619 //
1620 // Before set question value, evaluate its write expression.
1621 //
1622 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1623 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
1624 if (EFI_ERROR (Status)) {
1625 return Status;
1626 }
1627 }
1628
1629 //
1630 // Question value is provided by RTC
1631 //
1632 Storage = Question->Storage;
1633 QuestionValue = &Question->HiiValue.Value;
1634 if (Storage == NULL) {
1635 //
1636 // It's a Question without storage, or RTC date/time
1637 //
1638 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1639 //
1640 // Date and time define the same Flags bit
1641 //
1642 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1643 case QF_DATE_STORAGE_TIME:
1644 Status = gRT->GetTime (&EfiTime, NULL);
1645 break;
1646
1647 case QF_DATE_STORAGE_WAKEUP:
1648 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1649 break;
1650
1651 case QF_DATE_STORAGE_NORMAL:
1652 default:
1653 //
1654 // For date/time without storage
1655 //
1656 return EFI_SUCCESS;
1657 }
1658
1659 if (EFI_ERROR (Status)) {
1660 return Status;
1661 }
1662
1663 if (Question->Operand == EFI_IFR_DATE_OP) {
1664 EfiTime.Year = QuestionValue->date.Year;
1665 EfiTime.Month = QuestionValue->date.Month;
1666 EfiTime.Day = QuestionValue->date.Day;
1667 } else {
1668 EfiTime.Hour = QuestionValue->time.Hour;
1669 EfiTime.Minute = QuestionValue->time.Minute;
1670 EfiTime.Second = QuestionValue->time.Second;
1671 }
1672
1673 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
1674 Status = gRT->SetTime (&EfiTime);
1675 } else {
1676 Status = gRT->SetWakeupTime (TRUE, &EfiTime);
1677 }
1678 }
1679
1680 return Status;
1681 }
1682
1683 //
1684 // Question value is provided by EFI variable
1685 //
1686 StorageWidth = Question->StorageWidth;
1687 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1688 if (Question->BufferValue != NULL) {
1689 Src = Question->BufferValue;
1690 } else {
1691 Src = (UINT8 *) QuestionValue;
1692 }
1693
1694 Status = gRT->SetVariable (
1695 Question->VariableName,
1696 &Storage->Guid,
1697 Storage->Attributes,
1698 StorageWidth,
1699 Src
1700 );
1701 return Status;
1702 }
1703
1704 //
1705 // Question Value is provided by Buffer Storage or NameValue Storage
1706 //
1707 if (Question->BufferValue != NULL) {
1708 Src = Question->BufferValue;
1709 } else {
1710 Src = (UINT8 *) &Question->HiiValue.Value;
1711 }
1712
1713 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1714 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1715 IsBufferStorage = TRUE;
1716 } else {
1717 IsBufferStorage = FALSE;
1718 }
1719 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1720 if (IsBufferStorage) {
1721 //
1722 // Copy to storage edit buffer
1723 //
1724 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1725 } else {
1726 if (IsString) {
1727 //
1728 // Allocate enough string buffer.
1729 //
1730 Value = NULL;
1731 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
1732 Value = AllocateZeroPool (BufferLen);
1733 ASSERT (Value != NULL);
1734 //
1735 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1736 //
1737 TemName = (CHAR16 *) Src;
1738 TemString = Value;
1739 for (; *TemName != L'\0'; TemName++) {
1740 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1741 }
1742 } else {
1743 BufferLen = StorageWidth * 2 + 1;
1744 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
1745 ASSERT (Value != NULL);
1746 //
1747 // Convert Buffer to Hex String
1748 //
1749 TemBuffer = Src + StorageWidth - 1;
1750 TemString = Value;
1751 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1752 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1753 }
1754 }
1755
1756 Status = SetValueByName (Storage, Question->VariableName, Value, TRUE);
1757 FreePool (Value);
1758 }
1759
1760 if (!Cached) {
1761 if (Storage->Type == EFI_HII_VARSTORE_BUFFER) {
1762 //
1763 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
1764 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
1765 //
1766 if (IsBufferStorage) {
1767 Length = StrLen (Question->BlockName) + 7;
1768 } else {
1769 Length = StrLen (Question->VariableName) + 2;
1770 }
1771 if (!IsBufferStorage && IsString) {
1772 Length += (StrLen ((CHAR16 *) Src) * 4);
1773 } else {
1774 Length += (StorageWidth * 2);
1775 }
1776 ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
1777 ASSERT (ConfigResp != NULL);
1778
1779 StrCpy (ConfigResp, Storage->ConfigHdr);
1780 if (IsBufferStorage) {
1781 StrCat (ConfigResp, Question->BlockName);
1782 StrCat (ConfigResp, L"&VALUE=");
1783 } else {
1784 StrCat (ConfigResp, L"&");
1785 StrCat (ConfigResp, Question->VariableName);
1786 StrCat (ConfigResp, L"=");
1787 }
1788
1789 Value = ConfigResp + StrLen (ConfigResp);
1790
1791 if (!IsBufferStorage && IsString) {
1792 //
1793 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1794 //
1795 TemName = (CHAR16 *) Src;
1796 TemString = Value;
1797 for (; *TemName != L'\0'; TemName++) {
1798 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1799 }
1800 } else {
1801 //
1802 // Convert Buffer to Hex String
1803 //
1804 TemBuffer = Src + StorageWidth - 1;
1805 TemString = Value;
1806 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1807 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1808 }
1809 }
1810
1811 //
1812 // Convert to lower char.
1813 //
1814 for (TemString = Value; *Value != L'\0'; Value++) {
1815 if (*Value >= L'A' && *Value <= L'Z') {
1816 *Value = (CHAR16) (*Value - L'A' + L'a');
1817 }
1818 }
1819
1820 //
1821 // Submit Question Value to Configuration Driver
1822 //
1823 if (FormSet->ConfigAccess != NULL) {
1824 Status = FormSet->ConfigAccess->RouteConfig (
1825 FormSet->ConfigAccess,
1826 ConfigResp,
1827 &Progress
1828 );
1829 if (EFI_ERROR (Status)) {
1830 FreePool (ConfigResp);
1831 return Status;
1832 }
1833 }
1834 FreePool (ConfigResp);
1835
1836 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1837 TemBuffer = NULL;
1838 TemBuffer = AllocateZeroPool(Storage->Size);
1839 if (TemBuffer == NULL) {
1840 Status = EFI_OUT_OF_RESOURCES;
1841 return Status;
1842 }
1843 Length = Storage->Size;
1844 Status = gRT->GetVariable (
1845 Storage->Name,
1846 &Storage->Guid,
1847 NULL,
1848 &Length,
1849 TemBuffer
1850 );
1851
1852 CopyMem (TemBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1853
1854 Status = gRT->SetVariable (
1855 Storage->Name,
1856 &Storage->Guid,
1857 Storage->Attributes,
1858 Storage->Size,
1859 TemBuffer
1860 );
1861 FreePool (TemBuffer);
1862 if (EFI_ERROR (Status)){
1863 return Status;
1864 }
1865 }
1866 //
1867 // Sync storage, from editbuffer to buffer.
1868 //
1869 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1870 }
1871
1872 return Status;
1873 }
1874
1875
1876 /**
1877 Perform inconsistent check for a Form.
1878
1879 @param FormSet FormSet data structure.
1880 @param Form Form data structure.
1881 @param Question The Question to be validated.
1882 @param Type Validation type: InConsistent or NoSubmit
1883
1884 @retval EFI_SUCCESS Form validation pass.
1885 @retval other Form validation failed.
1886
1887 **/
1888 EFI_STATUS
1889 ValidateQuestion (
1890 IN FORM_BROWSER_FORMSET *FormSet,
1891 IN FORM_BROWSER_FORM *Form,
1892 IN FORM_BROWSER_STATEMENT *Question,
1893 IN UINTN Type
1894 )
1895 {
1896 EFI_STATUS Status;
1897 LIST_ENTRY *Link;
1898 LIST_ENTRY *ListHead;
1899 EFI_STRING PopUp;
1900 EFI_INPUT_KEY Key;
1901 FORM_EXPRESSION *Expression;
1902
1903 if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {
1904 ListHead = &Question->InconsistentListHead;
1905 } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
1906 ListHead = &Question->NoSubmitListHead;
1907 } else {
1908 return EFI_UNSUPPORTED;
1909 }
1910
1911 Link = GetFirstNode (ListHead);
1912 while (!IsNull (ListHead, Link)) {
1913 Expression = FORM_EXPRESSION_FROM_LINK (Link);
1914
1915 //
1916 // Evaluate the expression
1917 //
1918 Status = EvaluateExpression (FormSet, Form, Expression);
1919 if (EFI_ERROR (Status)) {
1920 return Status;
1921 }
1922
1923 if (Expression->Result.Value.b) {
1924 //
1925 // Condition meet, show up error message
1926 //
1927 if (Expression->Error != 0) {
1928 PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
1929 do {
1930 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);
1931 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1932 FreePool (PopUp);
1933 }
1934
1935 return EFI_NOT_READY;
1936 }
1937
1938 Link = GetNextNode (ListHead, Link);
1939 }
1940
1941 return EFI_SUCCESS;
1942 }
1943
1944
1945 /**
1946 Perform NoSubmit check for each Form in FormSet.
1947
1948 @param FormSet FormSet data structure.
1949 @param CurrentForm Current input form data structure.
1950
1951 @retval EFI_SUCCESS Form validation pass.
1952 @retval other Form validation failed.
1953
1954 **/
1955 EFI_STATUS
1956 NoSubmitCheck (
1957 IN FORM_BROWSER_FORMSET *FormSet,
1958 IN FORM_BROWSER_FORM *CurrentForm
1959 )
1960 {
1961 EFI_STATUS Status;
1962 LIST_ENTRY *Link;
1963 FORM_BROWSER_STATEMENT *Question;
1964 FORM_BROWSER_FORM *Form;
1965 LIST_ENTRY *LinkForm;
1966
1967 LinkForm = GetFirstNode (&FormSet->FormListHead);
1968 while (!IsNull (&FormSet->FormListHead, LinkForm)) {
1969 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
1970 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
1971
1972 if (CurrentForm != NULL && CurrentForm != Form) {
1973 continue;
1974 }
1975
1976 Link = GetFirstNode (&Form->StatementListHead);
1977 while (!IsNull (&Form->StatementListHead, Link)) {
1978 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1979
1980 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
1981 if (EFI_ERROR (Status)) {
1982 return Status;
1983 }
1984
1985 Link = GetNextNode (&Form->StatementListHead, Link);
1986 }
1987 }
1988
1989 return EFI_SUCCESS;
1990 }
1991
1992 /**
1993 Fill storage's edit copy with settings requested from Configuration Driver.
1994
1995 @param FormSet FormSet data structure.
1996 @param ConfigInfo The config info related to this form.
1997 @param SyncOrRestore Sync the buffer to editbuffer or Restore the
1998 editbuffer to buffer
1999 if TRUE, copy the editbuffer to the buffer.
2000 if FALSE, copy the buffer to the editbuffer.
2001
2002 @retval EFI_SUCCESS The function completed successfully.
2003
2004 **/
2005 EFI_STATUS
2006 SynchronizeStorageForForm (
2007 IN FORM_BROWSER_FORMSET *FormSet,
2008 IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo,
2009 IN BOOLEAN SyncOrRestore
2010 )
2011 {
2012 EFI_STATUS Status;
2013 EFI_STRING Progress;
2014 EFI_STRING Result;
2015 UINTN BufferSize;
2016 LIST_ENTRY *Link;
2017 NAME_VALUE_NODE *Node;
2018 UINT8 *Src;
2019 UINT8 *Dst;
2020
2021 Status = EFI_SUCCESS;
2022 Result = NULL;
2023 if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
2024 return EFI_NOT_FOUND;
2025 }
2026
2027 if (ConfigInfo->ElementCount == 0) {
2028 //
2029 // Skip if there is no RequestElement
2030 //
2031 return EFI_SUCCESS;
2032 }
2033
2034 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2035 (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2036 BufferSize = ConfigInfo->Storage->Size;
2037
2038 if (SyncOrRestore) {
2039 Src = ConfigInfo->Storage->EditBuffer;
2040 Dst = ConfigInfo->Storage->Buffer;
2041 } else {
2042 Src = ConfigInfo->Storage->Buffer;
2043 Dst = ConfigInfo->Storage->EditBuffer;
2044 }
2045
2046 Status = mHiiConfigRouting->BlockToConfig(
2047 mHiiConfigRouting,
2048 ConfigInfo->ConfigRequest,
2049 Src,
2050 BufferSize,
2051 &Result,
2052 &Progress
2053 );
2054 if (EFI_ERROR (Status)) {
2055 return Status;
2056 }
2057
2058 Status = mHiiConfigRouting->ConfigToBlock (
2059 mHiiConfigRouting,
2060 Result,
2061 Dst,
2062 &BufferSize,
2063 &Progress
2064 );
2065 if (Result != NULL) {
2066 FreePool (Result);
2067 }
2068 } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2069 Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead);
2070 while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) {
2071 Node = NAME_VALUE_NODE_FROM_LINK (Link);
2072
2073 if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) {
2074 if (SyncOrRestore) {
2075 NewStringCpy (&Node->Value, Node->EditValue);
2076 } else {
2077 NewStringCpy (&Node->EditValue, Node->Value);
2078 }
2079 }
2080
2081 Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link);
2082 }
2083 }
2084
2085 return Status;
2086 }
2087
2088
2089 /**
2090 Discard data based on the input setting scope (Form, FormSet or System).
2091
2092 @param FormSet FormSet data structure.
2093 @param Form Form data structure.
2094 @param SettingScope Setting Scope for Discard action.
2095
2096 @retval EFI_SUCCESS The function completed successfully.
2097 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2098
2099 **/
2100 EFI_STATUS
2101 DiscardForm (
2102 IN FORM_BROWSER_FORMSET *FormSet,
2103 IN FORM_BROWSER_FORM *Form,
2104 IN BROWSER_SETTING_SCOPE SettingScope
2105 )
2106 {
2107 LIST_ENTRY *Link;
2108 FORMSET_STORAGE *Storage;
2109 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2110 FORM_BROWSER_FORMSET *LocalFormSet;
2111
2112 //
2113 // Check the supported setting level.
2114 //
2115 if (SettingScope >= MaxLevel) {
2116 return EFI_UNSUPPORTED;
2117 }
2118
2119 if (SettingScope == FormLevel && Form->NvUpdateRequired) {
2120 ConfigInfo = NULL;
2121 Link = GetFirstNode (&Form->ConfigRequestHead);
2122 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2123 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2124 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2125
2126 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2127 continue;
2128 }
2129
2130 //
2131 // Skip if there is no RequestElement
2132 //
2133 if (ConfigInfo->ElementCount == 0) {
2134 continue;
2135 }
2136
2137 //
2138 // Prepare <ConfigResp>
2139 //
2140 SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE);
2141 }
2142
2143 Form->NvUpdateRequired = FALSE;
2144 } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
2145 //
2146 // Discard Buffer storage or Name/Value storage
2147 //
2148 Link = GetFirstNode (&FormSet->StorageListHead);
2149 while (!IsNull (&FormSet->StorageListHead, Link)) {
2150 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2151 Link = GetNextNode (&FormSet->StorageListHead, Link);
2152
2153 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2154 continue;
2155 }
2156
2157 //
2158 // Skip if there is no RequestElement
2159 //
2160 if (Storage->ElementCount == 0) {
2161 continue;
2162 }
2163
2164 SynchronizeStorage(Storage, FALSE);
2165 }
2166
2167 UpdateNvInfoInForm (FormSet, FALSE);
2168 } else if (SettingScope == SystemLevel) {
2169 //
2170 // System Level Discard.
2171 //
2172
2173 //
2174 // Discard changed value for each FormSet in the maintain list.
2175 //
2176 Link = GetFirstNode (&gBrowserFormSetList);
2177 while (!IsNull (&gBrowserFormSetList, Link)) {
2178 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2179 DiscardForm (LocalFormSet, NULL, FormSetLevel);
2180 Link = GetNextNode (&gBrowserFormSetList, Link);
2181 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2182 //
2183 // Remove maintain backup list after discard except for the current using FormSet.
2184 //
2185 RemoveEntryList (&LocalFormSet->Link);
2186 DestroyFormSet (LocalFormSet);
2187 }
2188 }
2189 }
2190
2191 return EFI_SUCCESS;
2192 }
2193
2194 /**
2195 Submit data based on the input Setting level (Form, FormSet or System).
2196
2197 @param FormSet FormSet data structure.
2198 @param Form Form data structure.
2199 @param SettingScope Setting Scope for Submit action.
2200
2201 @retval EFI_SUCCESS The function completed successfully.
2202 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2203
2204 **/
2205 EFI_STATUS
2206 SubmitForm (
2207 IN FORM_BROWSER_FORMSET *FormSet,
2208 IN FORM_BROWSER_FORM *Form,
2209 IN BROWSER_SETTING_SCOPE SettingScope
2210 )
2211 {
2212 EFI_STATUS Status;
2213 LIST_ENTRY *Link;
2214 EFI_STRING ConfigResp;
2215 EFI_STRING Progress;
2216 FORMSET_STORAGE *Storage;
2217 UINTN BufferSize;
2218 UINT8 *TmpBuf;
2219 FORM_BROWSER_FORMSET *LocalFormSet;
2220 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2221
2222 //
2223 // Check the supported setting level.
2224 //
2225 if (SettingScope >= MaxLevel) {
2226 return EFI_UNSUPPORTED;
2227 }
2228
2229 //
2230 // Validate the Form by NoSubmit check
2231 //
2232 Status = EFI_SUCCESS;
2233 if (SettingScope == FormLevel) {
2234 Status = NoSubmitCheck (FormSet, Form);
2235 } else if (SettingScope == FormSetLevel) {
2236 Status = NoSubmitCheck (FormSet, NULL);
2237 }
2238 if (EFI_ERROR (Status)) {
2239 return Status;
2240 }
2241
2242 if (SettingScope == FormLevel && Form->NvUpdateRequired) {
2243 ConfigInfo = NULL;
2244 Link = GetFirstNode (&Form->ConfigRequestHead);
2245 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2246 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2247 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2248
2249 Storage = ConfigInfo->Storage;
2250 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2251 continue;
2252 }
2253
2254 //
2255 // Skip if there is no RequestElement
2256 //
2257 if (ConfigInfo->ElementCount == 0) {
2258 continue;
2259 }
2260
2261 //
2262 // 1. Prepare <ConfigResp>
2263 //
2264 Status = StorageToConfigResp (ConfigInfo, &ConfigResp, TRUE);
2265 if (EFI_ERROR (Status)) {
2266 return Status;
2267 }
2268
2269 //
2270 // 2. Set value to hii driver or efi variable.
2271 //
2272 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2273 Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2274 //
2275 // Send <ConfigResp> to Configuration Driver
2276 //
2277 if (FormSet->ConfigAccess != NULL) {
2278 Status = FormSet->ConfigAccess->RouteConfig (
2279 FormSet->ConfigAccess,
2280 ConfigResp,
2281 &Progress
2282 );
2283 if (EFI_ERROR (Status)) {
2284 FreePool (ConfigResp);
2285 return Status;
2286 }
2287 }
2288 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
2289 TmpBuf = NULL;
2290 TmpBuf = AllocateZeroPool(Storage->Size);
2291 if (TmpBuf == NULL) {
2292 Status = EFI_OUT_OF_RESOURCES;
2293 return Status;
2294 }
2295
2296 BufferSize = Storage->Size;
2297 Status = gRT->GetVariable (
2298 Storage->Name,
2299 &Storage->Guid,
2300 NULL,
2301 &BufferSize,
2302 TmpBuf
2303 );
2304 if (EFI_ERROR (Status)) {
2305 FreePool (TmpBuf);
2306 FreePool (ConfigResp);
2307 return Status;
2308 }
2309 ASSERT (BufferSize == Storage->Size);
2310 Status = mHiiConfigRouting->ConfigToBlock (
2311 mHiiConfigRouting,
2312 ConfigResp,
2313 TmpBuf,
2314 &BufferSize,
2315 &Progress
2316 );
2317 if (EFI_ERROR (Status)) {
2318 FreePool (TmpBuf);
2319 FreePool (ConfigResp);
2320 return Status;
2321 }
2322
2323 Status = gRT->SetVariable (
2324 Storage->Name,
2325 &Storage->Guid,
2326 Storage->Attributes,
2327 Storage->Size,
2328 TmpBuf
2329 );
2330 FreePool (TmpBuf);
2331 if (EFI_ERROR (Status)) {
2332 FreePool (ConfigResp);
2333 return Status;
2334 }
2335 }
2336 FreePool (ConfigResp);
2337 //
2338 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
2339 //
2340 SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE);
2341 }
2342
2343 //
2344 // 4. Update the NV flag.
2345 //
2346 Form->NvUpdateRequired = FALSE;
2347 } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
2348 //
2349 // Submit Buffer storage or Name/Value storage
2350 //
2351 Link = GetFirstNode (&FormSet->StorageListHead);
2352 while (!IsNull (&FormSet->StorageListHead, Link)) {
2353 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2354 Link = GetNextNode (&FormSet->StorageListHead, Link);
2355
2356 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2357 continue;
2358 }
2359
2360 //
2361 // Skip if there is no RequestElement
2362 //
2363 if (Storage->ElementCount == 0) {
2364 continue;
2365 }
2366
2367 //
2368 // 1. Prepare <ConfigResp>
2369 //
2370 Status = StorageToConfigResp (Storage, &ConfigResp, FALSE);
2371 if (EFI_ERROR (Status)) {
2372 return Status;
2373 }
2374
2375 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2376 Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2377
2378 //
2379 // 2. Send <ConfigResp> to Configuration Driver
2380 //
2381 if (FormSet->ConfigAccess != NULL) {
2382 Status = FormSet->ConfigAccess->RouteConfig (
2383 FormSet->ConfigAccess,
2384 ConfigResp,
2385 &Progress
2386 );
2387 if (EFI_ERROR (Status)) {
2388 FreePool (ConfigResp);
2389 return Status;
2390 }
2391 }
2392 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
2393 //
2394 // 1&2. Set the edit data to the variable.
2395 //
2396 TmpBuf = NULL;
2397 TmpBuf = AllocateZeroPool (Storage->Size);
2398 if (TmpBuf == NULL) {
2399 Status = EFI_OUT_OF_RESOURCES;
2400 return Status;
2401 }
2402 BufferSize = Storage->Size;
2403 Status = gRT->GetVariable (
2404 Storage->Name,
2405 &Storage->Guid,
2406 NULL,
2407 &BufferSize,
2408 TmpBuf
2409 );
2410 ASSERT (BufferSize == Storage->Size);
2411 Status = mHiiConfigRouting->ConfigToBlock (
2412 mHiiConfigRouting,
2413 ConfigResp,
2414 TmpBuf,
2415 &BufferSize,
2416 &Progress
2417 );
2418 if (EFI_ERROR (Status)) {
2419 FreePool (TmpBuf);
2420 FreePool (ConfigResp);
2421 return Status;
2422 }
2423
2424 Status = gRT->SetVariable (
2425 Storage->Name,
2426 &Storage->Guid,
2427 Storage->Attributes,
2428 Storage->Size,
2429 TmpBuf
2430 );
2431 if (EFI_ERROR (Status)) {
2432 FreePool (TmpBuf);
2433 FreePool (ConfigResp);
2434 return Status;
2435 }
2436 FreePool (TmpBuf);
2437 }
2438 FreePool (ConfigResp);
2439 //
2440 // 3. Config success, update storage shadow Buffer
2441 //
2442 SynchronizeStorage (Storage, TRUE);
2443 }
2444
2445 //
2446 // 4. Update the NV flag.
2447 //
2448 UpdateNvInfoInForm (FormSet, FALSE);
2449 } else if (SettingScope == SystemLevel) {
2450 //
2451 // System Level Save.
2452 //
2453
2454 //
2455 // Save changed value for each FormSet in the maintain list.
2456 //
2457 Link = GetFirstNode (&gBrowserFormSetList);
2458 while (!IsNull (&gBrowserFormSetList, Link)) {
2459 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2460 SubmitForm (LocalFormSet, NULL, FormSetLevel);
2461 Link = GetNextNode (&gBrowserFormSetList, Link);
2462 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2463 //
2464 // Remove maintain backup list after save except for the current using FormSet.
2465 //
2466 RemoveEntryList (&LocalFormSet->Link);
2467 DestroyFormSet (LocalFormSet);
2468 }
2469 }
2470 }
2471
2472 return EFI_SUCCESS;
2473 }
2474
2475 /**
2476 Get Question default value from AltCfg string.
2477
2478 @param FormSet The form set.
2479 @param Question The question.
2480 @param DefaultId The default Id.
2481
2482 @retval EFI_SUCCESS Question is reset to default value.
2483
2484 **/
2485 EFI_STATUS
2486 GetDefaultValueFromAltCfg (
2487 IN FORM_BROWSER_FORMSET *FormSet,
2488 IN OUT FORM_BROWSER_STATEMENT *Question,
2489 IN UINT16 DefaultId
2490 )
2491 {
2492 BOOLEAN IsBufferStorage;
2493 BOOLEAN IsString;
2494 UINTN Length;
2495 FORMSET_STORAGE *Storage;
2496 CHAR16 *ConfigRequest;
2497 CHAR16 *Progress;
2498 CHAR16 *Result;
2499 CHAR16 *ConfigResp;
2500 CHAR16 *Value;
2501 CHAR16 *StringPtr;
2502 UINTN LengthStr;
2503 UINT8 *Dst;
2504 CHAR16 TemStr[5];
2505 UINTN Index;
2506 UINT8 DigitUint8;
2507 EFI_STATUS Status;
2508
2509 Status = EFI_NOT_FOUND;
2510 Length = 0;
2511 Dst = NULL;
2512 ConfigRequest = NULL;
2513 Result = NULL;
2514 ConfigResp = NULL;
2515 Value = NULL;
2516 Storage = Question->Storage;
2517
2518 if ((Storage == NULL) ||
2519 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) ||
2520 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2521 return Status;
2522 }
2523
2524 //
2525 // Question Value is provided by Buffer Storage or NameValue Storage
2526 //
2527 if (Question->BufferValue != NULL) {
2528 //
2529 // This Question is password or orderedlist
2530 //
2531 Dst = Question->BufferValue;
2532 } else {
2533 //
2534 // Other type of Questions
2535 //
2536 Dst = (UINT8 *) &Question->HiiValue.Value;
2537 }
2538
2539 IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
2540 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
2541
2542 //
2543 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
2544 // <ConfigHdr> + "&" + <VariableName>
2545 //
2546 if (IsBufferStorage) {
2547 Length = StrLen (Storage->ConfigHdr);
2548 Length += StrLen (Question->BlockName);
2549 } else {
2550 Length = StrLen (Storage->ConfigHdr);
2551 Length += StrLen (Question->VariableName) + 1;
2552 }
2553 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
2554 ASSERT (ConfigRequest != NULL);
2555
2556 StrCpy (ConfigRequest, Storage->ConfigHdr);
2557 if (IsBufferStorage) {
2558 StrCat (ConfigRequest, Question->BlockName);
2559 } else {
2560 StrCat (ConfigRequest, L"&");
2561 StrCat (ConfigRequest, Question->VariableName);
2562 }
2563
2564 Status = FormSet->ConfigAccess->ExtractConfig (
2565 FormSet->ConfigAccess,
2566 ConfigRequest,
2567 &Progress,
2568 &Result
2569 );
2570 if (EFI_ERROR (Status)) {
2571 goto Done;
2572 }
2573
2574 //
2575 // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
2576 // Get the default configuration string according to the default ID.
2577 //
2578 Status = mHiiConfigRouting->GetAltConfig (
2579 mHiiConfigRouting,
2580 Result,
2581 &Storage->Guid,
2582 Storage->Name,
2583 NULL,
2584 &DefaultId, // it can be NULL to get the current setting.
2585 &ConfigResp
2586 );
2587
2588 //
2589 // The required setting can't be found. So, it is not required to be validated and set.
2590 //
2591 if (EFI_ERROR (Status)) {
2592 goto Done;
2593 }
2594
2595 //
2596 // Skip <ConfigRequest>
2597 //
2598 if (IsBufferStorage) {
2599 Value = StrStr (ConfigResp, L"&VALUE");
2600 ASSERT (Value != NULL);
2601 //
2602 // Skip "&VALUE"
2603 //
2604 Value = Value + 6;
2605 } else {
2606 Value = StrStr (ConfigResp, Question->VariableName);
2607 ASSERT (Value != NULL);
2608
2609 Value = Value + StrLen (Question->VariableName);
2610 }
2611 if (*Value != '=') {
2612 Status = EFI_NOT_FOUND;
2613 goto Done;
2614 }
2615 //
2616 // Skip '=', point to value
2617 //
2618 Value = Value + 1;
2619
2620 //
2621 // Suppress <AltResp> if any
2622 //
2623 StringPtr = Value;
2624 while (*StringPtr != L'\0' && *StringPtr != L'&') {
2625 StringPtr++;
2626 }
2627 *StringPtr = L'\0';
2628
2629 LengthStr = StrLen (Value);
2630 if (!IsBufferStorage && IsString) {
2631 StringPtr = (CHAR16 *) Dst;
2632 ZeroMem (TemStr, sizeof (TemStr));
2633 for (Index = 0; Index < LengthStr; Index += 4) {
2634 StrnCpy (TemStr, Value + Index, 4);
2635 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
2636 }
2637 //
2638 // Add tailing L'\0' character
2639 //
2640 StringPtr[Index/4] = L'\0';
2641 } else {
2642 ZeroMem (TemStr, sizeof (TemStr));
2643 for (Index = 0; Index < LengthStr; Index ++) {
2644 TemStr[0] = Value[LengthStr - Index - 1];
2645 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
2646 if ((Index & 1) == 0) {
2647 Dst [Index/2] = DigitUint8;
2648 } else {
2649 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
2650 }
2651 }
2652 }
2653
2654 Done:
2655 if (ConfigRequest != NULL){
2656 FreePool (ConfigRequest);
2657 }
2658
2659 if (ConfigResp != NULL) {
2660 FreePool (ConfigResp);
2661 }
2662
2663 if (Result != NULL) {
2664 FreePool (Result);
2665 }
2666
2667 return Status;
2668 }
2669
2670 /**
2671 Get default Id value used for browser.
2672
2673 @param DefaultId The default id value used by hii.
2674
2675 @retval Browser used default value.
2676
2677 **/
2678 INTN
2679 GetDefaultIdForCallBack (
2680 UINTN DefaultId
2681 )
2682 {
2683 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
2684 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
2685 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2686 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
2687 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
2688 return EFI_BROWSER_ACTION_DEFAULT_SAFE;
2689 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
2690 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
2691 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
2692 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
2693 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
2694 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
2695 } else {
2696 return -1;
2697 }
2698 }
2699
2700 /**
2701 Reset Question to its default value.
2702
2703 @param FormSet The form set.
2704 @param Form The form.
2705 @param Question The question.
2706 @param DefaultId The Class of the default.
2707
2708 @retval EFI_SUCCESS Question is reset to default value.
2709
2710 **/
2711 EFI_STATUS
2712 GetQuestionDefault (
2713 IN FORM_BROWSER_FORMSET *FormSet,
2714 IN FORM_BROWSER_FORM *Form,
2715 IN FORM_BROWSER_STATEMENT *Question,
2716 IN UINT16 DefaultId
2717 )
2718 {
2719 EFI_STATUS Status;
2720 LIST_ENTRY *Link;
2721 QUESTION_DEFAULT *Default;
2722 QUESTION_OPTION *Option;
2723 EFI_HII_VALUE *HiiValue;
2724 UINT8 Index;
2725 EFI_STRING StrValue;
2726 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2727 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2728 INTN Action;
2729
2730 Status = EFI_NOT_FOUND;
2731 StrValue = NULL;
2732
2733 //
2734 // Statement don't have storage, skip them
2735 //
2736 if (Question->QuestionId == 0) {
2737 return Status;
2738 }
2739
2740 //
2741 // There are Five ways to specify default value for a Question:
2742 // 1, use call back function (highest priority)
2743 // 2, use ExtractConfig function
2744 // 3, use nested EFI_IFR_DEFAULT
2745 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
2746 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
2747 //
2748 HiiValue = &Question->HiiValue;
2749
2750 //
2751 // Get Question defaut value from call back function.
2752 //
2753 ConfigAccess = FormSet->ConfigAccess;
2754 Action = GetDefaultIdForCallBack (DefaultId);
2755 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
2756 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2757 Status = ConfigAccess->Callback (
2758 ConfigAccess,
2759 Action,
2760 Question->QuestionId,
2761 HiiValue->Type,
2762 &HiiValue->Value,
2763 &ActionRequest
2764 );
2765 if (!EFI_ERROR (Status)) {
2766 return Status;
2767 }
2768 }
2769
2770 //
2771 // Get default value from altcfg string.
2772 //
2773 if (ConfigAccess != NULL) {
2774 Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);
2775 if (!EFI_ERROR (Status)) {
2776 return Status;
2777 }
2778 }
2779
2780 //
2781 // EFI_IFR_DEFAULT has highest priority
2782 //
2783 if (!IsListEmpty (&Question->DefaultListHead)) {
2784 Link = GetFirstNode (&Question->DefaultListHead);
2785 while (!IsNull (&Question->DefaultListHead, Link)) {
2786 Default = QUESTION_DEFAULT_FROM_LINK (Link);
2787
2788 if (Default->DefaultId == DefaultId) {
2789 if (Default->ValueExpression != NULL) {
2790 //
2791 // Default is provided by an Expression, evaluate it
2792 //
2793 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
2794 if (EFI_ERROR (Status)) {
2795 return Status;
2796 }
2797
2798 CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE));
2799 } else {
2800 //
2801 // Default value is embedded in EFI_IFR_DEFAULT
2802 //
2803 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
2804 }
2805
2806 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2807 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
2808 if (StrValue == NULL) {
2809 return EFI_NOT_FOUND;
2810 }
2811 if (Question->StorageWidth > StrSize (StrValue)) {
2812 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
2813 } else {
2814 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
2815 }
2816 }
2817
2818 return EFI_SUCCESS;
2819 }
2820
2821 Link = GetNextNode (&Question->DefaultListHead, Link);
2822 }
2823 }
2824
2825 //
2826 // EFI_ONE_OF_OPTION
2827 //
2828 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
2829 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2830 //
2831 // OneOfOption could only provide Standard and Manufacturing default
2832 //
2833 Link = GetFirstNode (&Question->OptionListHead);
2834 while (!IsNull (&Question->OptionListHead, Link)) {
2835 Option = QUESTION_OPTION_FROM_LINK (Link);
2836
2837 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
2838 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
2839 ) {
2840 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
2841
2842 return EFI_SUCCESS;
2843 }
2844
2845 Link = GetNextNode (&Question->OptionListHead, Link);
2846 }
2847 }
2848 }
2849
2850 //
2851 // EFI_IFR_CHECKBOX - lowest priority
2852 //
2853 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
2854 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2855 //
2856 // Checkbox could only provide Standard and Manufacturing default
2857 //
2858 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
2859 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
2860 ) {
2861 HiiValue->Value.b = TRUE;
2862 } else {
2863 HiiValue->Value.b = FALSE;
2864 }
2865
2866 return EFI_SUCCESS;
2867 }
2868 }
2869
2870 //
2871 // For Questions without default
2872 //
2873 Status = EFI_NOT_FOUND;
2874 switch (Question->Operand) {
2875 case EFI_IFR_NUMERIC_OP:
2876 //
2877 // Take minimum value as numeric default value
2878 //
2879 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
2880 HiiValue->Value.u64 = Question->Minimum;
2881 Status = EFI_SUCCESS;
2882 }
2883 break;
2884
2885 case EFI_IFR_ONE_OF_OP:
2886 //
2887 // Take first oneof option as oneof's default value
2888 //
2889 if (ValueToOption (Question, HiiValue) == NULL) {
2890 Link = GetFirstNode (&Question->OptionListHead);
2891 if (!IsNull (&Question->OptionListHead, Link)) {
2892 Option = QUESTION_OPTION_FROM_LINK (Link);
2893 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
2894 Status = EFI_SUCCESS;
2895 }
2896 }
2897 break;
2898
2899 case EFI_IFR_ORDERED_LIST_OP:
2900 //
2901 // Take option sequence in IFR as ordered list's default value
2902 //
2903 Index = 0;
2904 Link = GetFirstNode (&Question->OptionListHead);
2905 while (!IsNull (&Question->OptionListHead, Link)) {
2906 Status = EFI_SUCCESS;
2907 Option = QUESTION_OPTION_FROM_LINK (Link);
2908
2909 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
2910
2911 Index++;
2912 if (Index >= Question->MaxContainers) {
2913 break;
2914 }
2915
2916 Link = GetNextNode (&Question->OptionListHead, Link);
2917 }
2918 break;
2919
2920 default:
2921 break;
2922 }
2923
2924 return Status;
2925 }
2926
2927
2928 /**
2929 Reset Questions to their default value in a Form, Formset or System.
2930
2931 @param FormSet FormSet data structure.
2932 @param Form Form data structure.
2933 @param DefaultId The Class of the default.
2934 @param SettingScope Setting Scope for Default action.
2935
2936 @retval EFI_SUCCESS The function completed successfully.
2937 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2938
2939 **/
2940 EFI_STATUS
2941 ExtractDefault (
2942 IN FORM_BROWSER_FORMSET *FormSet,
2943 IN FORM_BROWSER_FORM *Form,
2944 IN UINT16 DefaultId,
2945 IN BROWSER_SETTING_SCOPE SettingScope
2946 )
2947 {
2948 EFI_STATUS Status;
2949 LIST_ENTRY *FormLink;
2950 LIST_ENTRY *Link;
2951 FORM_BROWSER_STATEMENT *Question;
2952 FORM_BROWSER_FORMSET *BackUpFormSet;
2953 FORM_BROWSER_FORMSET *LocalFormSet;
2954 EFI_HII_HANDLE *HiiHandles;
2955 UINTN Index;
2956 EFI_GUID ZeroGuid;
2957 UINTN BackUpClassOfVfr;
2958
2959 //
2960 // Check the supported setting level.
2961 //
2962 if (SettingScope >= MaxLevel) {
2963 return EFI_UNSUPPORTED;
2964 }
2965
2966 if (SettingScope == FormLevel) {
2967 //
2968 // Extract Form default
2969 //
2970 Link = GetFirstNode (&Form->StatementListHead);
2971 while (!IsNull (&Form->StatementListHead, Link)) {
2972 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2973 Link = GetNextNode (&Form->StatementListHead, Link);
2974
2975 //
2976 // If Question is disabled, don't reset it to default
2977 //
2978 if (Question->DisableExpression != NULL) {
2979 Status = EvaluateExpression (FormSet, Form, Question->DisableExpression);
2980 if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b) {
2981 continue;
2982 }
2983 }
2984
2985 //
2986 // Reset Question to its default value
2987 //
2988 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
2989 if (EFI_ERROR (Status)) {
2990 continue;
2991 }
2992
2993 //
2994 // Synchronize Buffer storage's Edit buffer
2995 //
2996 if ((Question->Storage != NULL) &&
2997 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
2998 SetQuestionValue (FormSet, Form, Question, TRUE);
2999 //
3000 // Update Form NV flag.
3001 //
3002 Form->NvUpdateRequired = TRUE;
3003 }
3004 }
3005 } else if (SettingScope == FormSetLevel) {
3006 FormLink = GetFirstNode (&FormSet->FormListHead);
3007 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3008 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3009 ExtractDefault (FormSet, Form, DefaultId, FormLevel);
3010 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3011 }
3012 } else if (SettingScope == SystemLevel) {
3013 //
3014 // Open all FormSet by locate HII packages.
3015 // Initiliaze the maintain FormSet to store default data as back up data.
3016 //
3017 BackUpClassOfVfr = gClassOfVfr;
3018 BackUpFormSet = gOldFormSet;
3019 gOldFormSet = NULL;
3020
3021 //
3022 // Get all the Hii handles
3023 //
3024 HiiHandles = HiiGetHiiHandles (NULL);
3025 ASSERT (HiiHandles != NULL);
3026
3027 //
3028 // Search for formset of each class type
3029 //
3030 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
3031 //
3032 // Check HiiHandles[Index] does exist in global maintain list.
3033 //
3034 if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
3035 continue;
3036 }
3037
3038 //
3039 // Initilize FormSet Setting
3040 //
3041 LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
3042 ASSERT (LocalFormSet != NULL);
3043 ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
3044 Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);
3045 if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
3046 DestroyFormSet (LocalFormSet);
3047 continue;
3048 }
3049 Status = InitializeCurrentSetting (LocalFormSet);
3050 if (EFI_ERROR (Status)) {
3051 DestroyFormSet (LocalFormSet);
3052 continue;
3053 }
3054
3055 //
3056 // Add FormSet into the maintain list.
3057 //
3058 InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);
3059 }
3060
3061 //
3062 // Free resources, and restore gOldFormSet and gClassOfVfr
3063 //
3064 FreePool (HiiHandles);
3065 gOldFormSet = BackUpFormSet;
3066 gClassOfVfr = BackUpClassOfVfr;
3067
3068 //
3069 // Set Default Value for each FormSet in the maintain list.
3070 //
3071 Link = GetFirstNode (&gBrowserFormSetList);
3072 while (!IsNull (&gBrowserFormSetList, Link)) {
3073 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3074 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel);
3075 Link = GetNextNode (&gBrowserFormSetList, Link);
3076 }
3077 }
3078
3079 return EFI_SUCCESS;
3080 }
3081
3082 /**
3083 Initialize Question's Edit copy from Storage.
3084
3085 @param Selection Selection contains the information about
3086 the Selection, form and formset to be displayed.
3087 Selection action may be updated in retrieve callback.
3088 @param FormSet FormSet data structure.
3089 @param Form Form data structure.
3090
3091 @retval EFI_SUCCESS The function completed successfully.
3092
3093 **/
3094 EFI_STATUS
3095 LoadFormConfig (
3096 IN OUT UI_MENU_SELECTION *Selection,
3097 IN FORM_BROWSER_FORMSET *FormSet,
3098 IN FORM_BROWSER_FORM *Form
3099 )
3100 {
3101 EFI_STATUS Status;
3102 LIST_ENTRY *Link;
3103 FORM_BROWSER_STATEMENT *Question;
3104 UINT8 *BufferValue;
3105 UINTN StorageWidth;
3106
3107 Link = GetFirstNode (&Form->StatementListHead);
3108 while (!IsNull (&Form->StatementListHead, Link)) {
3109 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3110
3111 //
3112 // Initialize local copy of Value for each Question
3113 //
3114 Status = GetQuestionValue (FormSet, Form, Question, TRUE);
3115 if (EFI_ERROR (Status)) {
3116 return Status;
3117 }
3118
3119 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
3120 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
3121 }
3122
3123 //
3124 // According the spec, ref opcode try to get value from call back with "retrieve" type.
3125 //
3126 if ((Question->Operand == EFI_IFR_REF_OP) && (FormSet->ConfigAccess != NULL)) {
3127 Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
3128 if (EFI_ERROR (Status)) {
3129 return Status;
3130 }
3131 }
3132
3133 //
3134 // Check whether EfiVarstore with CallBack can be got.
3135 //
3136 if ((FormSet->ConfigAccess != NULL) &&
3137 (Selection->Action != UI_ACTION_REFRESH_FORMSET) &&
3138 (Question->QuestionId != 0) &&
3139 (Question->Storage != NULL) &&
3140 (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) &&
3141 ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
3142
3143 //
3144 // Check QuestionValue does exist.
3145 //
3146 StorageWidth = Question->StorageWidth;
3147 if (Question->BufferValue != NULL) {
3148 BufferValue = Question->BufferValue;
3149 } else {
3150 BufferValue = (UINT8 *) &Question->HiiValue.Value;
3151 }
3152 Status = gRT->GetVariable (
3153 Question->VariableName,
3154 &Question->Storage->Guid,
3155 NULL,
3156 &StorageWidth,
3157 BufferValue
3158 );
3159
3160 if (!EFI_ERROR (Status)) {
3161 Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
3162 }
3163 }
3164
3165 Link = GetNextNode (&Form->StatementListHead, Link);
3166 }
3167
3168 return EFI_SUCCESS;
3169 }
3170
3171 /**
3172 Initialize Question's Edit copy from Storage for the whole Formset.
3173
3174 @param Selection Selection contains the information about
3175 the Selection, form and formset to be displayed.
3176 Selection action may be updated in retrieve callback.
3177 @param FormSet FormSet data structure.
3178
3179 @retval EFI_SUCCESS The function completed successfully.
3180
3181 **/
3182 EFI_STATUS
3183 LoadFormSetConfig (
3184 IN OUT UI_MENU_SELECTION *Selection,
3185 IN FORM_BROWSER_FORMSET *FormSet
3186 )
3187 {
3188 EFI_STATUS Status;
3189 LIST_ENTRY *Link;
3190 FORM_BROWSER_FORM *Form;
3191
3192 Link = GetFirstNode (&FormSet->FormListHead);
3193 while (!IsNull (&FormSet->FormListHead, Link)) {
3194 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3195
3196 //
3197 // Initialize local copy of Value for each Form
3198 //
3199 Status = LoadFormConfig (Selection, FormSet, Form);
3200 if (EFI_ERROR (Status)) {
3201 return Status;
3202 }
3203
3204 Link = GetNextNode (&FormSet->FormListHead, Link);
3205 }
3206
3207 return EFI_SUCCESS;
3208 }
3209
3210 /**
3211 Fill storage's edit copy with settings requested from Configuration Driver.
3212
3213 @param FormSet FormSet data structure.
3214 @param Storage Buffer Storage.
3215
3216 @retval EFI_SUCCESS The function completed successfully.
3217
3218 **/
3219 EFI_STATUS
3220 LoadStorage (
3221 IN FORM_BROWSER_FORMSET *FormSet,
3222 IN FORMSET_STORAGE *Storage
3223 )
3224 {
3225 EFI_STATUS Status;
3226 EFI_STRING Progress;
3227 EFI_STRING Result;
3228 CHAR16 *StrPtr;
3229
3230 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3231 return EFI_SUCCESS;
3232 }
3233
3234 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
3235 Status = gRT->GetVariable (
3236 Storage->Name,
3237 &Storage->Guid,
3238 NULL,
3239 (UINTN*)&Storage->Size,
3240 Storage->EditBuffer
3241 );
3242 return Status;
3243 }
3244
3245 if (FormSet->ConfigAccess == NULL) {
3246 return EFI_NOT_FOUND;
3247 }
3248
3249 if (Storage->ElementCount == 0) {
3250 //
3251 // Skip if there is no RequestElement
3252 //
3253 return EFI_SUCCESS;
3254 }
3255
3256 //
3257 // Request current settings from Configuration Driver
3258 //
3259 Status = FormSet->ConfigAccess->ExtractConfig (
3260 FormSet->ConfigAccess,
3261 Storage->ConfigRequest,
3262 &Progress,
3263 &Result
3264 );
3265 if (EFI_ERROR (Status)) {
3266 return Status;
3267 }
3268
3269 //
3270 // Convert Result from <ConfigAltResp> to <ConfigResp>
3271 //
3272 StrPtr = StrStr (Result, L"ALTCFG");
3273 if (StrPtr != NULL) {
3274 *StrPtr = L'\0';
3275 }
3276
3277 Status = ConfigRespToStorage (Storage, Result);
3278 FreePool (Result);
3279 return Status;
3280 }
3281
3282
3283 /**
3284 Copy uncommitted data from source Storage to destination Storage.
3285
3286 @param Dst Target Storage for uncommitted data.
3287 @param Src Source Storage for uncommitted data.
3288
3289 @retval EFI_SUCCESS The function completed successfully.
3290 @retval EFI_INVALID_PARAMETER Source and destination Storage is not the same type.
3291
3292 **/
3293 EFI_STATUS
3294 CopyStorage (
3295 IN OUT FORMSET_STORAGE *Dst,
3296 IN FORMSET_STORAGE *Src
3297 )
3298 {
3299 LIST_ENTRY *Link;
3300 NAME_VALUE_NODE *Node;
3301
3302 if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {
3303 return EFI_INVALID_PARAMETER;
3304 }
3305
3306 switch (Src->Type) {
3307 case EFI_HII_VARSTORE_BUFFER:
3308 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
3309 CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);
3310 CopyMem (Dst->Buffer, Src->Buffer, Src->Size);
3311 break;
3312
3313 case EFI_HII_VARSTORE_NAME_VALUE:
3314 Link = GetFirstNode (&Src->NameValueListHead);
3315 while (!IsNull (&Src->NameValueListHead, Link)) {
3316 Node = NAME_VALUE_NODE_FROM_LINK (Link);
3317
3318 SetValueByName (Dst, Node->Name, Node->EditValue, TRUE);
3319 SetValueByName (Dst, Node->Name, Node->Value, FALSE);
3320
3321 Link = GetNextNode (&Src->NameValueListHead, Link);
3322 }
3323 break;
3324
3325 case EFI_HII_VARSTORE_EFI_VARIABLE:
3326 default:
3327 break;
3328 }
3329
3330 return EFI_SUCCESS;
3331 }
3332
3333
3334 /**
3335 Get current setting of Questions.
3336
3337 @param FormSet FormSet data structure.
3338
3339 @retval EFI_SUCCESS The function completed successfully.
3340
3341 **/
3342 EFI_STATUS
3343 InitializeCurrentSetting (
3344 IN OUT FORM_BROWSER_FORMSET *FormSet
3345 )
3346 {
3347 LIST_ENTRY *Link;
3348 LIST_ENTRY *Link2;
3349 FORMSET_STORAGE *Storage;
3350 FORMSET_STORAGE *StorageSrc;
3351 FORMSET_STORAGE *OldStorage;
3352 FORM_BROWSER_FORM *Form;
3353 FORM_BROWSER_FORM *Form2;
3354 EFI_STATUS Status;
3355
3356 //
3357 // Extract default from IFR binary
3358 //
3359 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel);
3360 UpdateNvInfoInForm (FormSet, FALSE);
3361
3362 //
3363 // Request current settings from Configuration Driver
3364 //
3365 Link = GetFirstNode (&FormSet->StorageListHead);
3366 while (!IsNull (&FormSet->StorageListHead, Link)) {
3367 Storage = FORMSET_STORAGE_FROM_LINK (Link);
3368
3369 OldStorage = NULL;
3370 if (gOldFormSet != NULL) {
3371 //
3372 // Try to find the Storage in backup formset gOldFormSet
3373 //
3374 Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
3375 while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
3376 StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
3377
3378 if (StorageSrc->VarStoreId == Storage->VarStoreId) {
3379 OldStorage = StorageSrc;
3380 break;
3381 }
3382
3383 Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
3384 }
3385 }
3386
3387 if (OldStorage == NULL) {
3388 //
3389 // Storage is not found in backup formset, request it from ConfigDriver
3390 //
3391 Status = LoadStorage (FormSet, Storage);
3392 //
3393 // Now Edit Buffer is filled with default values(lower priority) and current
3394 // settings(higher priority), sychronize it to shadow Buffer
3395 //
3396 if (!EFI_ERROR (Status)) {
3397 SynchronizeStorage (Storage, TRUE);
3398 }
3399 } else {
3400 //
3401 // Storage found in backup formset, use it
3402 //
3403 Status = CopyStorage (Storage, OldStorage);
3404 }
3405
3406 Link = GetNextNode (&FormSet->StorageListHead, Link);
3407 }
3408
3409 //
3410 // If has old formset, get the old nv update status.
3411 //
3412 if (gOldFormSet != NULL) {
3413 Link = GetFirstNode (&FormSet->FormListHead);
3414 while (!IsNull (&FormSet->FormListHead, Link)) {
3415 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3416
3417 Link2 = GetFirstNode (&gOldFormSet->FormListHead);
3418 while (!IsNull (&gOldFormSet->FormListHead, Link2)) {
3419 Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);
3420
3421 if (Form->FormId == Form2->FormId) {
3422 Form->NvUpdateRequired = Form2->NvUpdateRequired;
3423 break;
3424 }
3425
3426 Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);
3427 }
3428 Link = GetNextNode (&FormSet->FormListHead, Link);
3429 }
3430 }
3431
3432 return EFI_SUCCESS;
3433 }
3434
3435
3436 /**
3437 Fetch the Ifr binary data of a FormSet.
3438
3439 @param Handle PackageList Handle
3440 @param FormSetGuid On input, GUID or class GUID of a formset. If not
3441 specified (NULL or zero GUID), take the first
3442 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
3443 found in package list.
3444 On output, GUID of the formset found(if not NULL).
3445 @param BinaryLength The length of the FormSet IFR binary.
3446 @param BinaryData The buffer designed to receive the FormSet.
3447
3448 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
3449 BufferLength was updated.
3450 @retval EFI_INVALID_PARAMETER The handle is unknown.
3451 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
3452 be found with the requested FormId.
3453
3454 **/
3455 EFI_STATUS
3456 GetIfrBinaryData (
3457 IN EFI_HII_HANDLE Handle,
3458 IN OUT EFI_GUID *FormSetGuid,
3459 OUT UINTN *BinaryLength,
3460 OUT UINT8 **BinaryData
3461 )
3462 {
3463 EFI_STATUS Status;
3464 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
3465 UINTN BufferSize;
3466 UINT8 *Package;
3467 UINT8 *OpCodeData;
3468 UINT32 Offset;
3469 UINT32 Offset2;
3470 UINT32 PackageListLength;
3471 EFI_HII_PACKAGE_HEADER PackageHeader;
3472 UINT8 Index;
3473 UINT8 NumberOfClassGuid;
3474 BOOLEAN ClassGuidMatch;
3475 EFI_GUID *ClassGuid;
3476 EFI_GUID *ComparingGuid;
3477
3478 OpCodeData = NULL;
3479 Package = NULL;
3480 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
3481
3482 //
3483 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
3484 //
3485 if (FormSetGuid == NULL) {
3486 ComparingGuid = &gZeroGuid;
3487 } else {
3488 ComparingGuid = FormSetGuid;
3489 }
3490
3491 //
3492 // Get HII PackageList
3493 //
3494 BufferSize = 0;
3495 HiiPackageList = NULL;
3496 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
3497 if (Status == EFI_BUFFER_TOO_SMALL) {
3498 HiiPackageList = AllocatePool (BufferSize);
3499 ASSERT (HiiPackageList != NULL);
3500
3501 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
3502 }
3503 if (EFI_ERROR (Status)) {
3504 return Status;
3505 }
3506 ASSERT (HiiPackageList != NULL);
3507
3508 //
3509 // Get Form package from this HII package List
3510 //
3511 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3512 Offset2 = 0;
3513 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
3514
3515 ClassGuidMatch = FALSE;
3516 while (Offset < PackageListLength) {
3517 Package = ((UINT8 *) HiiPackageList) + Offset;
3518 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3519
3520 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
3521 //
3522 // Search FormSet in this Form Package
3523 //
3524 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
3525 while (Offset2 < PackageHeader.Length) {
3526 OpCodeData = Package + Offset2;
3527
3528 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
3529 //
3530 // Try to compare against formset GUID
3531 //
3532 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
3533 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
3534 break;
3535 }
3536
3537 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
3538 //
3539 // Try to compare against formset class GUID
3540 //
3541 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
3542 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
3543 for (Index = 0; Index < NumberOfClassGuid; Index++) {
3544 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
3545 ClassGuidMatch = TRUE;
3546 break;
3547 }
3548 }
3549 if (ClassGuidMatch) {
3550 break;
3551 }
3552 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
3553 ClassGuidMatch = TRUE;
3554 break;
3555 }
3556 }
3557
3558 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
3559 }
3560
3561 if (Offset2 < PackageHeader.Length) {
3562 //
3563 // Target formset found
3564 //
3565 break;
3566 }
3567 }
3568
3569 Offset += PackageHeader.Length;
3570 }
3571
3572 if (Offset >= PackageListLength) {
3573 //
3574 // Form package not found in this Package List
3575 //
3576 FreePool (HiiPackageList);
3577 return EFI_NOT_FOUND;
3578 }
3579
3580 if (FormSetGuid != NULL) {
3581 //
3582 // Return the FormSet GUID
3583 //
3584 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
3585 }
3586
3587 //
3588 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
3589 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
3590 // of the Form Package.
3591 //
3592 *BinaryLength = PackageHeader.Length - Offset2;
3593 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
3594
3595 FreePool (HiiPackageList);
3596
3597 if (*BinaryData == NULL) {
3598 return EFI_OUT_OF_RESOURCES;
3599 }
3600
3601 return EFI_SUCCESS;
3602 }
3603
3604
3605 /**
3606 Initialize the internal data structure of a FormSet.
3607
3608 @param Handle PackageList Handle
3609 @param FormSetGuid On input, GUID or class GUID of a formset. If not
3610 specified (NULL or zero GUID), take the first
3611 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
3612 found in package list.
3613 On output, GUID of the formset found(if not NULL).
3614 @param FormSet FormSet data structure.
3615
3616 @retval EFI_SUCCESS The function completed successfully.
3617 @retval EFI_NOT_FOUND The specified FormSet could not be found.
3618
3619 **/
3620 EFI_STATUS
3621 InitializeFormSet (
3622 IN EFI_HII_HANDLE Handle,
3623 IN OUT EFI_GUID *FormSetGuid,
3624 OUT FORM_BROWSER_FORMSET *FormSet
3625 )
3626 {
3627 EFI_STATUS Status;
3628 EFI_HANDLE DriverHandle;
3629 UINT16 Index;
3630
3631 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
3632 if (EFI_ERROR (Status)) {
3633 return Status;
3634 }
3635
3636 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
3637 FormSet->HiiHandle = Handle;
3638 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
3639
3640 //
3641 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
3642 //
3643 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
3644 if (EFI_ERROR (Status)) {
3645 return Status;
3646 }
3647 FormSet->DriverHandle = DriverHandle;
3648 Status = gBS->HandleProtocol (
3649 DriverHandle,
3650 &gEfiHiiConfigAccessProtocolGuid,
3651 (VOID **) &FormSet->ConfigAccess
3652 );
3653 if (EFI_ERROR (Status)) {
3654 //
3655 // Configuration Driver don't attach ConfigAccess protocol to its HII package
3656 // list, then there will be no configuration action required
3657 //
3658 FormSet->ConfigAccess = NULL;
3659 }
3660
3661 //
3662 // Parse the IFR binary OpCodes
3663 //
3664 Status = ParseOpCodes (FormSet);
3665 if (EFI_ERROR (Status)) {
3666 return Status;
3667 }
3668
3669 //
3670 // Set VFR type by FormSet SubClass field
3671 //
3672 gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
3673 if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
3674 gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
3675 }
3676
3677 //
3678 // Set VFR type by FormSet class guid
3679 //
3680 for (Index = 0; Index < 3; Index ++) {
3681 if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
3682 gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
3683 break;
3684 }
3685 }
3686
3687 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
3688 gFrontPageHandle = FormSet->HiiHandle;
3689 gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;
3690 }
3691
3692 //
3693 // Match GUID to find out the function key setting. If match fail, use the default setting.
3694 //
3695 for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
3696 if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
3697 //
3698 // Update the function key setting.
3699 //
3700 gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
3701 }
3702 }
3703
3704 return EFI_SUCCESS;
3705 }
3706
3707
3708 /**
3709 Save globals used by previous call to SendForm(). SendForm() may be called from
3710 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
3711 So, save globals of previous call to SendForm() and restore them upon exit.
3712
3713 **/
3714 VOID
3715 SaveBrowserContext (
3716 VOID
3717 )
3718 {
3719 BROWSER_CONTEXT *Context;
3720
3721 gBrowserContextCount++;
3722 if (gBrowserContextCount == 1) {
3723 //
3724 // This is not reentry of SendForm(), no context to save
3725 //
3726 return;
3727 }
3728
3729 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
3730 ASSERT (Context != NULL);
3731
3732 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
3733
3734 //
3735 // Save FormBrowser context
3736 //
3737 Context->BannerData = gBannerData;
3738 Context->ClassOfVfr = gClassOfVfr;
3739 Context->FunctionKeySetting = gFunctionKeySetting;
3740 Context->ResetRequired = gResetRequired;
3741 Context->Direction = gDirection;
3742 Context->EnterString = gEnterString;
3743 Context->EnterCommitString = gEnterCommitString;
3744 Context->EnterEscapeString = gEnterEscapeString;
3745 Context->EscapeString = gEscapeString;
3746 Context->MoveHighlight = gMoveHighlight;
3747 Context->MakeSelection = gMakeSelection;
3748 Context->DecNumericInput = gDecNumericInput;
3749 Context->HexNumericInput = gHexNumericInput;
3750 Context->ToggleCheckBox = gToggleCheckBox;
3751 Context->PromptForData = gPromptForData;
3752 Context->PromptForPassword = gPromptForPassword;
3753 Context->PromptForNewPassword = gPromptForNewPassword;
3754 Context->ConfirmPassword = gConfirmPassword;
3755 Context->ConfirmError = gConfirmError;
3756 Context->PassowordInvalid = gPassowordInvalid;
3757 Context->PressEnter = gPressEnter;
3758 Context->EmptyString = gEmptyString;
3759 Context->AreYouSure = gAreYouSure;
3760 Context->YesResponse = gYesResponse;
3761 Context->NoResponse = gNoResponse;
3762 Context->MiniString = gMiniString;
3763 Context->PlusString = gPlusString;
3764 Context->MinusString = gMinusString;
3765 Context->AdjustNumber = gAdjustNumber;
3766 Context->SaveChanges = gSaveChanges;
3767 Context->OptionMismatch = gOptionMismatch;
3768 Context->FormSuppress = gFormSuppress;
3769 Context->PromptBlockWidth = gPromptBlockWidth;
3770 Context->OptionBlockWidth = gOptionBlockWidth;
3771 Context->HelpBlockWidth = gHelpBlockWidth;
3772 Context->OldFormSet = gOldFormSet;
3773 Context->MenuRefreshHead = gMenuRefreshHead;
3774
3775 CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
3776 CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
3777
3778 //
3779 // Insert to FormBrowser context list
3780 //
3781 InsertHeadList (&gBrowserContextList, &Context->Link);
3782 }
3783
3784
3785 /**
3786 Restore globals used by previous call to SendForm().
3787
3788 **/
3789 VOID
3790 RestoreBrowserContext (
3791 VOID
3792 )
3793 {
3794 LIST_ENTRY *Link;
3795 BROWSER_CONTEXT *Context;
3796
3797 ASSERT (gBrowserContextCount != 0);
3798 gBrowserContextCount--;
3799 if (gBrowserContextCount == 0) {
3800 //
3801 // This is not reentry of SendForm(), no context to restore
3802 //
3803 return;
3804 }
3805
3806 ASSERT (!IsListEmpty (&gBrowserContextList));
3807
3808 Link = GetFirstNode (&gBrowserContextList);
3809 Context = BROWSER_CONTEXT_FROM_LINK (Link);
3810
3811 //
3812 // Restore FormBrowser context
3813 //
3814 gBannerData = Context->BannerData;
3815 gClassOfVfr = Context->ClassOfVfr;
3816 gFunctionKeySetting = Context->FunctionKeySetting;
3817 gResetRequired = Context->ResetRequired;
3818 gDirection = Context->Direction;
3819 gEnterString = Context->EnterString;
3820 gEnterCommitString = Context->EnterCommitString;
3821 gEnterEscapeString = Context->EnterEscapeString;
3822 gEscapeString = Context->EscapeString;
3823 gMoveHighlight = Context->MoveHighlight;
3824 gMakeSelection = Context->MakeSelection;
3825 gDecNumericInput = Context->DecNumericInput;
3826 gHexNumericInput = Context->HexNumericInput;
3827 gToggleCheckBox = Context->ToggleCheckBox;
3828 gPromptForData = Context->PromptForData;
3829 gPromptForPassword = Context->PromptForPassword;
3830 gPromptForNewPassword = Context->PromptForNewPassword;
3831 gConfirmPassword = Context->ConfirmPassword;
3832 gConfirmError = Context->ConfirmError;
3833 gPassowordInvalid = Context->PassowordInvalid;
3834 gPressEnter = Context->PressEnter;
3835 gEmptyString = Context->EmptyString;
3836 gAreYouSure = Context->AreYouSure;
3837 gYesResponse = Context->YesResponse;
3838 gNoResponse = Context->NoResponse;
3839 gMiniString = Context->MiniString;
3840 gPlusString = Context->PlusString;
3841 gMinusString = Context->MinusString;
3842 gAdjustNumber = Context->AdjustNumber;
3843 gSaveChanges = Context->SaveChanges;
3844 gOptionMismatch = Context->OptionMismatch;
3845 gFormSuppress = Context->FormSuppress;
3846 gPromptBlockWidth = Context->PromptBlockWidth;
3847 gOptionBlockWidth = Context->OptionBlockWidth;
3848 gHelpBlockWidth = Context->HelpBlockWidth;
3849 gOldFormSet = Context->OldFormSet;
3850 gMenuRefreshHead = Context->MenuRefreshHead;
3851
3852 CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
3853 CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
3854
3855 //
3856 // Remove from FormBrowser context list
3857 //
3858 RemoveEntryList (&Context->Link);
3859 gBS->FreePool (Context);
3860 }
3861
3862 /**
3863 Find the matched FormSet context in the backup maintain list based on HiiHandle.
3864
3865 @param Handle The Hii Handle.
3866
3867 @return the found FormSet context. If no found, NULL will return.
3868
3869 **/
3870 FORM_BROWSER_FORMSET *
3871 GetFormSetFromHiiHandle (
3872 EFI_HII_HANDLE Handle
3873 )
3874 {
3875 LIST_ENTRY *Link;
3876 FORM_BROWSER_FORMSET *FormSet;
3877
3878 Link = GetFirstNode (&gBrowserFormSetList);
3879 while (!IsNull (&gBrowserFormSetList, Link)) {
3880 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3881 if (FormSet->HiiHandle == Handle) {
3882 return FormSet;
3883 }
3884 Link = GetNextNode (&gBrowserFormSetList, Link);
3885 }
3886
3887 return NULL;
3888 }
3889
3890 /**
3891 Check whether the input HII handle is the FormSet that is being used.
3892
3893 @param Handle The Hii Handle.
3894
3895 @retval TRUE HII handle is being used.
3896 @retval FALSE HII handle is not being used.
3897
3898 **/
3899 BOOLEAN
3900 IsHiiHandleInBrowserContext (
3901 EFI_HII_HANDLE Handle
3902 )
3903 {
3904 LIST_ENTRY *Link;
3905 BROWSER_CONTEXT *Context;
3906
3907 //
3908 // HiiHandle is Current FormSet.
3909 //
3910 if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {
3911 return TRUE;
3912 }
3913
3914 //
3915 // Check whether HiiHandle is in BrowserContext.
3916 //
3917 Link = GetFirstNode (&gBrowserContextList);
3918 while (!IsNull (&gBrowserContextList, Link)) {
3919 Context = BROWSER_CONTEXT_FROM_LINK (Link);
3920 if (Context->OldFormSet->HiiHandle == Handle) {
3921 //
3922 // HiiHandle is in BrowserContext
3923 //
3924 return TRUE;
3925 }
3926 Link = GetNextNode (&gBrowserContextList, Link);
3927 }
3928
3929 return FALSE;
3930 }
3931
3932 /**
3933 Find the registered HotKey based on KeyData.
3934
3935 @param[in] KeyData A pointer to a buffer that describes the keystroke
3936 information for the hot key.
3937
3938 @return The registered HotKey context. If no found, NULL will return.
3939 **/
3940 BROWSER_HOT_KEY *
3941 GetHotKeyFromRegisterList (
3942 IN EFI_INPUT_KEY *KeyData
3943 )
3944 {
3945 LIST_ENTRY *Link;
3946 BROWSER_HOT_KEY *HotKey;
3947
3948 Link = GetFirstNode (&gBrowserHotKeyList);
3949 while (!IsNull (&gBrowserHotKeyList, Link)) {
3950 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
3951 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
3952 return HotKey;
3953 }
3954 Link = GetNextNode (&gBrowserHotKeyList, Link);
3955 }
3956
3957 return NULL;
3958 }
3959
3960 /**
3961 Configure what scope the hot key will impact.
3962 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
3963 If no scope is set, the default scope will be FormSet level.
3964 After all registered hot keys are removed, previous Scope can reset to another level.
3965
3966 @param[in] Scope Scope level to be set.
3967
3968 @retval EFI_SUCCESS Scope is set correctly.
3969 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
3970 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
3971
3972 **/
3973 EFI_STATUS
3974 EFIAPI
3975 SetScope (
3976 IN BROWSER_SETTING_SCOPE Scope
3977 )
3978 {
3979 if (Scope >= MaxLevel) {
3980 return EFI_INVALID_PARAMETER;
3981 }
3982
3983 //
3984 // When no hot key registered in system or on the first setting,
3985 // Scope can be set.
3986 //
3987 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
3988 gBrowserSettingScope = Scope;
3989 mBrowserScopeFirstSet = FALSE;
3990 } else if (Scope != gBrowserSettingScope) {
3991 return EFI_UNSUPPORTED;
3992 }
3993
3994 return EFI_SUCCESS;
3995 }
3996
3997 /**
3998 Register the hot key with its browser action, or unregistered the hot key.
3999 Only support hot key that is not printable character (control key, function key, etc.).
4000 If the action value is zero, the hot key will be unregistered if it has been registered.
4001 If the same hot key has been registered, the new action and help string will override the previous ones.
4002
4003 @param[in] KeyData A pointer to a buffer that describes the keystroke
4004 information for the hot key. Its type is EFI_INPUT_KEY to
4005 be supported by all ConsoleIn devices.
4006 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
4007 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
4008 @param[in] HelpString Help string that describes the hot key information.
4009 Its value may be NULL for the unregistered hot key.
4010
4011 @retval EFI_SUCCESS Hot key is registered or unregistered.
4012 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
4013 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
4014 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
4015 **/
4016 EFI_STATUS
4017 EFIAPI
4018 RegisterHotKey (
4019 IN EFI_INPUT_KEY *KeyData,
4020 IN UINT32 Action,
4021 IN UINT16 DefaultId,
4022 IN EFI_STRING HelpString OPTIONAL
4023 )
4024 {
4025 BROWSER_HOT_KEY *HotKey;
4026
4027 //
4028 // Check input parameters.
4029 //
4030 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
4031 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
4032 return EFI_INVALID_PARAMETER;
4033 }
4034
4035 //
4036 // Check whether the input KeyData is in BrowserHotKeyList.
4037 //
4038 HotKey = GetHotKeyFromRegisterList (KeyData);
4039
4040 //
4041 // Unregister HotKey
4042 //
4043 if (Action == BROWSER_ACTION_UNREGISTER) {
4044 if (HotKey != NULL) {
4045 //
4046 // The registered HotKey is found.
4047 // Remove it from List, and free its resource.
4048 //
4049 RemoveEntryList (&HotKey->Link);
4050 FreePool (HotKey->KeyData);
4051 FreePool (HotKey->HelpString);
4052 return EFI_SUCCESS;
4053 } else {
4054 //
4055 // The registered HotKey is not found.
4056 //
4057 return EFI_NOT_FOUND;
4058 }
4059 }
4060
4061 //
4062 // Register HotKey into List.
4063 //
4064 if (HotKey == NULL) {
4065 //
4066 // Create new Key, and add it into List.
4067 //
4068 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
4069 ASSERT (HotKey != NULL);
4070 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
4071 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
4072 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
4073 }
4074
4075 //
4076 // Fill HotKey information.
4077 //
4078 HotKey->Action = Action;
4079 HotKey->DefaultId = DefaultId;
4080 if (HotKey->HelpString != NULL) {
4081 FreePool (HotKey->HelpString);
4082 }
4083 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
4084
4085 return EFI_SUCCESS;
4086 }
4087
4088 /**
4089 Register Exit handler function.
4090 When more than one handler function is registered, the latter one will override the previous one.
4091 When NULL handler is specified, the previous Exit handler will be unregistered.
4092
4093 @param[in] Handler Pointer to handler function.
4094
4095 **/
4096 VOID
4097 EFIAPI
4098 RegiserExitHandler (
4099 IN EXIT_HANDLER Handler
4100 )
4101 {
4102 ExitHandlerFunction = Handler;
4103 return;
4104 }
4105
4106 /**
4107 Create reminder to let user to choose save or discard the changed browser data.
4108 Caller can use it to actively check the changed browser data.
4109
4110 @retval BROWSER_NO_CHANGES No browser data is changed.
4111 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
4112 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
4113
4114 **/
4115 UINT32
4116 EFIAPI
4117 SaveReminder (
4118 VOID
4119 )
4120 {
4121 LIST_ENTRY *Link;
4122 FORM_BROWSER_FORMSET *FormSet;
4123 BOOLEAN IsDataChanged;
4124 UINT32 DataSavedAction;
4125 CHAR16 *YesResponse;
4126 CHAR16 *NoResponse;
4127 CHAR16 *EmptyString;
4128 CHAR16 *ChangeReminderString;
4129 CHAR16 *SaveConfirmString;
4130 EFI_INPUT_KEY Key;
4131
4132 DataSavedAction = BROWSER_NO_CHANGES;
4133 IsDataChanged = FALSE;
4134 Link = GetFirstNode (&gBrowserFormSetList);
4135 while (!IsNull (&gBrowserFormSetList, Link)) {
4136 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4137 if (IsNvUpdateRequired (FormSet)) {
4138 IsDataChanged = TRUE;
4139 break;
4140 }
4141 Link = GetNextNode (&gBrowserFormSetList, Link);
4142 }
4143
4144 //
4145 // No data is changed. No save is required.
4146 //
4147 if (!IsDataChanged) {
4148 return DataSavedAction;
4149 }
4150
4151 //
4152 // If data is changed, prompt user
4153 //
4154 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
4155
4156 YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
4157 ASSERT (YesResponse != NULL);
4158 NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
4159 ASSERT (NoResponse != NULL);
4160 EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
4161 ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);
4162 SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);
4163
4164 do {
4165 CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);
4166 } while
4167 (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&
4168 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))
4169 );
4170
4171 //
4172 // If the user hits the YesResponse key
4173 //
4174 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {
4175 SubmitForm (NULL, NULL, SystemLevel);
4176 DataSavedAction = BROWSER_SAVE_CHANGES;
4177 } else {
4178 DiscardForm (NULL, NULL, SystemLevel);
4179 DataSavedAction = BROWSER_DISCARD_CHANGES;
4180 gResetRequired = FALSE;
4181 }
4182
4183 FreePool (YesResponse);
4184 FreePool (NoResponse);
4185 FreePool (EmptyString);
4186 FreePool (SaveConfirmString);
4187 FreePool (ChangeReminderString);
4188
4189 return DataSavedAction;
4190 }