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