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