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