]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
Base on the type field to get the width of value field for option opcode.
[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 Link = GetNextNode (&Question->OptionListHead, Link);
3030
3031 if ((Option->SuppressExpression != NULL) &&
3032 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3033 continue;
3034 }
3035
3036 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
3037 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
3038 ) {
3039 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3040
3041 return EFI_SUCCESS;
3042 }
3043 }
3044 }
3045 }
3046
3047 //
3048 // EFI_IFR_CHECKBOX - lowest priority
3049 //
3050 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
3051 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3052 //
3053 // Checkbox could only provide Standard and Manufacturing default
3054 //
3055 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
3056 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
3057 ) {
3058 HiiValue->Value.b = TRUE;
3059 } else {
3060 HiiValue->Value.b = FALSE;
3061 }
3062
3063 return EFI_SUCCESS;
3064 }
3065 }
3066
3067 //
3068 // For Questions without default
3069 //
3070 Status = EFI_NOT_FOUND;
3071 switch (Question->Operand) {
3072 case EFI_IFR_NUMERIC_OP:
3073 //
3074 // Take minimum value as numeric default value
3075 //
3076 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
3077 HiiValue->Value.u64 = Question->Minimum;
3078 Status = EFI_SUCCESS;
3079 }
3080 break;
3081
3082 case EFI_IFR_ONE_OF_OP:
3083 //
3084 // Take first oneof option as oneof's default value
3085 //
3086 if (ValueToOption (Question, HiiValue) == NULL) {
3087 Link = GetFirstNode (&Question->OptionListHead);
3088 while (!IsNull (&Question->OptionListHead, Link)) {
3089 Option = QUESTION_OPTION_FROM_LINK (Link);
3090 Link = GetNextNode (&Question->OptionListHead, Link);
3091
3092 if ((Option->SuppressExpression != NULL) &&
3093 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3094 continue;
3095 }
3096
3097 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3098 Status = EFI_SUCCESS;
3099 break;
3100 }
3101 }
3102 break;
3103
3104 case EFI_IFR_ORDERED_LIST_OP:
3105 //
3106 // Take option sequence in IFR as ordered list's default value
3107 //
3108 Index = 0;
3109 Link = GetFirstNode (&Question->OptionListHead);
3110 while (!IsNull (&Question->OptionListHead, Link)) {
3111 Status = EFI_SUCCESS;
3112 Option = QUESTION_OPTION_FROM_LINK (Link);
3113 Link = GetNextNode (&Question->OptionListHead, Link);
3114
3115 if ((Option->SuppressExpression != NULL) &&
3116 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3117 continue;
3118 }
3119
3120 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
3121
3122 Index++;
3123 if (Index >= Question->MaxContainers) {
3124 break;
3125 }
3126 }
3127 break;
3128
3129 default:
3130 break;
3131 }
3132
3133 return Status;
3134 }
3135
3136
3137 /**
3138 Reset Questions to their initial value or default value in a Form, Formset or System.
3139
3140 GetDefaultValueScope parameter decides which questions will reset
3141 to its default value.
3142
3143 @param FormSet FormSet data structure.
3144 @param Form Form data structure.
3145 @param DefaultId The Class of the default.
3146 @param SettingScope Setting Scope for Default action.
3147 @param GetDefaultValueScope Get default value scope.
3148 @param Storage Get default value only for this storage.
3149 @param RetrieveValueFirst Whether call the retrieve call back to
3150 get the initial value before get default
3151 value.
3152
3153 @retval EFI_SUCCESS The function completed successfully.
3154 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3155
3156 **/
3157 EFI_STATUS
3158 ExtractDefault (
3159 IN FORM_BROWSER_FORMSET *FormSet,
3160 IN FORM_BROWSER_FORM *Form,
3161 IN UINT16 DefaultId,
3162 IN BROWSER_SETTING_SCOPE SettingScope,
3163 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
3164 IN FORMSET_STORAGE *Storage OPTIONAL,
3165 IN BOOLEAN RetrieveValueFirst
3166 )
3167 {
3168 EFI_STATUS Status;
3169 LIST_ENTRY *FormLink;
3170 LIST_ENTRY *Link;
3171 FORM_BROWSER_STATEMENT *Question;
3172 FORM_BROWSER_FORMSET *BackUpFormSet;
3173 FORM_BROWSER_FORMSET *LocalFormSet;
3174 EFI_HII_HANDLE *HiiHandles;
3175 UINTN Index;
3176 EFI_GUID ZeroGuid;
3177
3178 Status = EFI_SUCCESS;
3179
3180 //
3181 // Check the supported setting level.
3182 //
3183 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
3184 return EFI_UNSUPPORTED;
3185 }
3186
3187 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
3188 return EFI_UNSUPPORTED;
3189 }
3190
3191 if (SettingScope == FormLevel) {
3192 //
3193 // Extract Form default
3194 //
3195 Link = GetFirstNode (&Form->StatementListHead);
3196 while (!IsNull (&Form->StatementListHead, Link)) {
3197 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3198 Link = GetNextNode (&Form->StatementListHead, Link);
3199
3200 //
3201 // If get default value only for this storage, check the storage first.
3202 //
3203 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
3204 continue;
3205 }
3206
3207 //
3208 // If get default value only for no storage question, just skip the question which has storage.
3209 //
3210 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
3211 continue;
3212 }
3213
3214 //
3215 // If Question is disabled, don't reset it to default
3216 //
3217 if (Question->Expression != NULL) {
3218 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
3219 continue;
3220 }
3221 }
3222
3223 if (RetrieveValueFirst) {
3224 //
3225 // Call the Retrieve call back to get the initial question value.
3226 //
3227 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);
3228 }
3229
3230 //
3231 // If not request to get the initial value or get initial value fail, then get default value.
3232 //
3233 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
3234 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
3235 if (EFI_ERROR (Status)) {
3236 continue;
3237 }
3238 }
3239
3240 //
3241 // Synchronize Buffer storage's Edit buffer
3242 //
3243 if ((Question->Storage != NULL) &&
3244 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
3245 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3246 //
3247 // Update Form NV flag.
3248 //
3249 Form->NvUpdateRequired = TRUE;
3250 }
3251 }
3252 } else if (SettingScope == FormSetLevel) {
3253 FormLink = GetFirstNode (&FormSet->FormListHead);
3254 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3255 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3256 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3257 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3258 }
3259 } else if (SettingScope == SystemLevel) {
3260 //
3261 // Open all FormSet by locate HII packages.
3262 // Initiliaze the maintain FormSet to store default data as back up data.
3263 //
3264 BackUpFormSet = gOldFormSet;
3265 gOldFormSet = NULL;
3266
3267 //
3268 // Get all the Hii handles
3269 //
3270 HiiHandles = HiiGetHiiHandles (NULL);
3271 ASSERT (HiiHandles != NULL);
3272
3273 //
3274 // Search for formset of each class type
3275 //
3276 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
3277 //
3278 // Check HiiHandles[Index] does exist in global maintain list.
3279 //
3280 if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
3281 continue;
3282 }
3283
3284 //
3285 // Initilize FormSet Setting
3286 //
3287 LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
3288 ASSERT (LocalFormSet != NULL);
3289 ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
3290 Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE);
3291 if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
3292 DestroyFormSet (LocalFormSet);
3293 continue;
3294 }
3295 Status = InitializeCurrentSetting (LocalFormSet);
3296 if (EFI_ERROR (Status)) {
3297 DestroyFormSet (LocalFormSet);
3298 continue;
3299 }
3300 //
3301 // Initilize Questions' Value
3302 //
3303 Status = LoadFormSetConfig (NULL, LocalFormSet);
3304 if (EFI_ERROR (Status)) {
3305 DestroyFormSet (LocalFormSet);
3306 continue;
3307 }
3308
3309 //
3310 // Add FormSet into the maintain list.
3311 //
3312 InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);
3313 }
3314
3315 //
3316 // Free resources, and restore gOldFormSet and gClassOfVfr
3317 //
3318 FreePool (HiiHandles);
3319 gOldFormSet = BackUpFormSet;
3320
3321 //
3322 // Set Default Value for each FormSet in the maintain list.
3323 //
3324 Link = GetFirstNode (&gBrowserFormSetList);
3325 while (!IsNull (&gBrowserFormSetList, Link)) {
3326 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3327 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3328 Link = GetNextNode (&gBrowserFormSetList, Link);
3329 }
3330 }
3331
3332 return EFI_SUCCESS;
3333 }
3334
3335 /**
3336 Initialize Question's Edit copy from Storage.
3337
3338 @param Selection Selection contains the information about
3339 the Selection, form and formset to be displayed.
3340 Selection action may be updated in retrieve callback.
3341 If Selection is NULL, only initialize Question value.
3342 @param FormSet FormSet data structure.
3343 @param Form Form data structure.
3344
3345 @retval EFI_SUCCESS The function completed successfully.
3346
3347 **/
3348 EFI_STATUS
3349 LoadFormConfig (
3350 IN OUT UI_MENU_SELECTION *Selection,
3351 IN FORM_BROWSER_FORMSET *FormSet,
3352 IN FORM_BROWSER_FORM *Form
3353 )
3354 {
3355 EFI_STATUS Status;
3356 LIST_ENTRY *Link;
3357 FORM_BROWSER_STATEMENT *Question;
3358 UINT8 *BufferValue;
3359 UINTN StorageWidth;
3360
3361 Link = GetFirstNode (&Form->StatementListHead);
3362 while (!IsNull (&Form->StatementListHead, Link)) {
3363 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3364
3365 //
3366 // Initialize local copy of Value for each Question
3367 //
3368 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3369 if (EFI_ERROR (Status)) {
3370 return Status;
3371 }
3372
3373 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
3374 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
3375 }
3376
3377 //
3378 // Call the Retrieve call back function for all questions.
3379 //
3380 if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&
3381 ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
3382 //
3383 // Check QuestionValue does exist.
3384 //
3385 StorageWidth = Question->StorageWidth;
3386 if (Question->BufferValue != NULL) {
3387 BufferValue = Question->BufferValue;
3388 } else {
3389 BufferValue = (UINT8 *) &Question->HiiValue.Value;
3390 }
3391
3392 //
3393 // For efivarstore storage, initial question value first.
3394 //
3395 if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
3396 Status = gRT->GetVariable (
3397 Question->VariableName,
3398 &Question->Storage->Guid,
3399 NULL,
3400 &StorageWidth,
3401 BufferValue
3402 );
3403 }
3404
3405 Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
3406 }
3407
3408 Link = GetNextNode (&Form->StatementListHead, Link);
3409 }
3410
3411 return EFI_SUCCESS;
3412 }
3413
3414 /**
3415 Initialize Question's Edit copy from Storage for the whole Formset.
3416
3417 @param Selection Selection contains the information about
3418 the Selection, form and formset to be displayed.
3419 Selection action may be updated in retrieve callback.
3420 If Selection is NULL, only initialize Question value.
3421 @param FormSet FormSet data structure.
3422
3423 @retval EFI_SUCCESS The function completed successfully.
3424
3425 **/
3426 EFI_STATUS
3427 LoadFormSetConfig (
3428 IN OUT UI_MENU_SELECTION *Selection,
3429 IN FORM_BROWSER_FORMSET *FormSet
3430 )
3431 {
3432 EFI_STATUS Status;
3433 LIST_ENTRY *Link;
3434 FORM_BROWSER_FORM *Form;
3435
3436 Link = GetFirstNode (&FormSet->FormListHead);
3437 while (!IsNull (&FormSet->FormListHead, Link)) {
3438 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3439
3440 //
3441 // Initialize local copy of Value for each Form
3442 //
3443 Status = LoadFormConfig (Selection, FormSet, Form);
3444 if (EFI_ERROR (Status)) {
3445 return Status;
3446 }
3447
3448 Link = GetNextNode (&FormSet->FormListHead, Link);
3449 }
3450
3451 return EFI_SUCCESS;
3452 }
3453
3454 /**
3455 Fill storage's edit copy with settings requested from Configuration Driver.
3456
3457 @param FormSet FormSet data structure.
3458 @param Storage Buffer Storage.
3459
3460 @retval EFI_SUCCESS The function completed successfully.
3461
3462 **/
3463 EFI_STATUS
3464 LoadStorage (
3465 IN FORM_BROWSER_FORMSET *FormSet,
3466 IN FORMSET_STORAGE *Storage
3467 )
3468 {
3469 EFI_STATUS Status;
3470 EFI_STRING Progress;
3471 EFI_STRING Result;
3472 CHAR16 *StrPtr;
3473
3474 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3475 return EFI_SUCCESS;
3476 }
3477
3478 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
3479 Status = gRT->GetVariable (
3480 Storage->Name,
3481 &Storage->Guid,
3482 NULL,
3483 (UINTN*)&Storage->Size,
3484 Storage->EditBuffer
3485 );
3486 return Status;
3487 }
3488
3489 if (FormSet->ConfigAccess == NULL) {
3490 return EFI_NOT_FOUND;
3491 }
3492
3493 if (Storage->ElementCount == 0) {
3494 //
3495 // Skip if there is no RequestElement
3496 //
3497 return EFI_SUCCESS;
3498 }
3499
3500 //
3501 // Request current settings from Configuration Driver
3502 //
3503 Status = FormSet->ConfigAccess->ExtractConfig (
3504 FormSet->ConfigAccess,
3505 Storage->ConfigRequest,
3506 &Progress,
3507 &Result
3508 );
3509 if (EFI_ERROR (Status)) {
3510 return Status;
3511 }
3512
3513 //
3514 // Convert Result from <ConfigAltResp> to <ConfigResp>
3515 //
3516 StrPtr = StrStr (Result, L"&GUID=");
3517 if (StrPtr != NULL) {
3518 *StrPtr = L'\0';
3519 }
3520
3521 Status = ConfigRespToStorage (Storage, Result);
3522 FreePool (Result);
3523 return Status;
3524 }
3525
3526
3527 /**
3528 Copy uncommitted data from source Storage to destination Storage.
3529
3530 @param Dst Target Storage for uncommitted data.
3531 @param Src Source Storage for uncommitted data.
3532
3533 @retval EFI_SUCCESS The function completed successfully.
3534 @retval EFI_INVALID_PARAMETER Source and destination Storage is not the same type.
3535
3536 **/
3537 EFI_STATUS
3538 CopyStorage (
3539 IN OUT FORMSET_STORAGE *Dst,
3540 IN FORMSET_STORAGE *Src
3541 )
3542 {
3543 LIST_ENTRY *Link;
3544 NAME_VALUE_NODE *Node;
3545
3546 if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {
3547 return EFI_INVALID_PARAMETER;
3548 }
3549
3550 switch (Src->Type) {
3551 case EFI_HII_VARSTORE_BUFFER:
3552 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
3553 CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);
3554 CopyMem (Dst->Buffer, Src->Buffer, Src->Size);
3555 break;
3556
3557 case EFI_HII_VARSTORE_NAME_VALUE:
3558 Link = GetFirstNode (&Src->NameValueListHead);
3559 while (!IsNull (&Src->NameValueListHead, Link)) {
3560 Node = NAME_VALUE_NODE_FROM_LINK (Link);
3561
3562 SetValueByName (Dst, Node->Name, Node->EditValue, GetSetValueWithEditBuffer);
3563 SetValueByName (Dst, Node->Name, Node->Value, GetSetValueWithBuffer);
3564
3565 Link = GetNextNode (&Src->NameValueListHead, Link);
3566 }
3567 break;
3568
3569 case EFI_HII_VARSTORE_EFI_VARIABLE:
3570 default:
3571 break;
3572 }
3573
3574 return EFI_SUCCESS;
3575 }
3576
3577 /**
3578 Get old question value from the saved formset.
3579
3580 @param Statement The question which need to get old question value.
3581 @param OldFormSet FormSet data structure saved in the list.
3582
3583 **/
3584 VOID
3585 GetOldQuestionValue (
3586 IN OUT FORM_BROWSER_STATEMENT *Statement,
3587 IN FORM_BROWSER_FORMSET *OldFormSet
3588 )
3589 {
3590 LIST_ENTRY *FormLink;
3591 LIST_ENTRY *Link;
3592 FORM_BROWSER_STATEMENT *Question;
3593 FORM_BROWSER_FORM *Form;
3594
3595 FormLink = GetFirstNode (&OldFormSet->FormListHead);
3596 while (!IsNull (&OldFormSet->FormListHead, FormLink)) {
3597 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3598 FormLink = GetNextNode (&OldFormSet->FormListHead, FormLink);
3599
3600 Link = GetFirstNode (&Form->StatementListHead);
3601 while (!IsNull (&Form->StatementListHead, Link)) {
3602 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3603 Link = GetNextNode (&Form->StatementListHead, Link);
3604
3605 if (Question->QuestionId != Statement->QuestionId) {
3606 continue;
3607 }
3608
3609 CopyMem (&Statement->HiiValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
3610 return;
3611 }
3612 }
3613 }
3614
3615 /**
3616 Get old question value from the saved formset, all these questions not have
3617 storage.
3618
3619 @param FormSet FormSet data structure which is used now.
3620 @param OldFormSet FormSet data structure saved in the list.
3621
3622 **/
3623 VOID
3624 CopyOldValueForNoStorageQst (
3625 IN OUT FORM_BROWSER_FORMSET *FormSet,
3626 IN FORM_BROWSER_FORMSET *OldFormSet
3627 )
3628 {
3629 LIST_ENTRY *FormLink;
3630 LIST_ENTRY *Link;
3631 FORM_BROWSER_STATEMENT *Question;
3632 FORM_BROWSER_FORM *Form;
3633
3634 FormLink = GetFirstNode (&FormSet->FormListHead);
3635 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3636 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3637 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3638
3639 Link = GetFirstNode (&Form->StatementListHead);
3640 while (!IsNull (&Form->StatementListHead, Link)) {
3641 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3642 Link = GetNextNode (&Form->StatementListHead, Link);
3643
3644 if (Question->Storage == NULL) {
3645 GetOldQuestionValue (Question, OldFormSet);
3646 }
3647 }
3648 }
3649 }
3650
3651 /**
3652 Get current setting of Questions.
3653
3654 @param FormSet FormSet data structure.
3655
3656 @retval EFI_SUCCESS The function completed successfully.
3657
3658 **/
3659 EFI_STATUS
3660 InitializeCurrentSetting (
3661 IN OUT FORM_BROWSER_FORMSET *FormSet
3662 )
3663 {
3664 LIST_ENTRY *Link;
3665 LIST_ENTRY *Link2;
3666 FORMSET_STORAGE *Storage;
3667 FORMSET_STORAGE *StorageSrc;
3668 FORMSET_STORAGE *OldStorage;
3669 FORM_BROWSER_FORM *Form;
3670 FORM_BROWSER_FORM *Form2;
3671 EFI_STATUS Status;
3672
3673 //
3674 // Extract default from IFR binary for no storage questions.
3675 //
3676 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);
3677
3678 //
3679 // Request current settings from Configuration Driver
3680 //
3681 Link = GetFirstNode (&FormSet->StorageListHead);
3682 while (!IsNull (&FormSet->StorageListHead, Link)) {
3683 Storage = FORMSET_STORAGE_FROM_LINK (Link);
3684
3685 OldStorage = NULL;
3686 if (gOldFormSet != NULL) {
3687 //
3688 // Try to find the Storage in backup formset gOldFormSet
3689 //
3690 Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
3691 while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
3692 StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
3693
3694 if (StorageSrc->VarStoreId == Storage->VarStoreId) {
3695 OldStorage = StorageSrc;
3696 break;
3697 }
3698
3699 Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
3700 }
3701 }
3702
3703 if (OldStorage == NULL) {
3704 //
3705 // Storage is not found in backup formset, request it from ConfigDriver
3706 //
3707 Status = LoadStorage (FormSet, Storage);
3708
3709 if (EFI_ERROR (Status)) {
3710 //
3711 // If get last time changed value failed, extract default from IFR binary
3712 //
3713 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);
3714 //
3715 // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag
3716 // in current situation.
3717 //
3718 UpdateNvInfoInForm (FormSet, FALSE);
3719 }
3720
3721 //
3722 // Now Edit Buffer is filled with default values(lower priority) or current
3723 // settings(higher priority), sychronize it to shadow Buffer
3724 //
3725 SynchronizeStorage (Storage, TRUE);
3726 } else {
3727 //
3728 // Storage found in backup formset, use it
3729 //
3730 Status = CopyStorage (Storage, OldStorage);
3731 }
3732
3733 Link = GetNextNode (&FormSet->StorageListHead, Link);
3734 }
3735
3736 //
3737 // If has old formset, get the old nv update status.
3738 //
3739 if (gOldFormSet != NULL) {
3740 Link = GetFirstNode (&FormSet->FormListHead);
3741 while (!IsNull (&FormSet->FormListHead, Link)) {
3742 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3743
3744 Link2 = GetFirstNode (&gOldFormSet->FormListHead);
3745 while (!IsNull (&gOldFormSet->FormListHead, Link2)) {
3746 Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);
3747
3748 if (Form->FormId == Form2->FormId) {
3749 Form->NvUpdateRequired = Form2->NvUpdateRequired;
3750 break;
3751 }
3752
3753 Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);
3754 }
3755 Link = GetNextNode (&FormSet->FormListHead, Link);
3756 }
3757 }
3758
3759 return EFI_SUCCESS;
3760 }
3761
3762
3763 /**
3764 Fetch the Ifr binary data of a FormSet.
3765
3766 @param Handle PackageList Handle
3767 @param FormSetGuid On input, GUID or class GUID of a formset. If not
3768 specified (NULL or zero GUID), take the first
3769 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
3770 found in package list.
3771 On output, GUID of the formset found(if not NULL).
3772 @param BinaryLength The length of the FormSet IFR binary.
3773 @param BinaryData The buffer designed to receive the FormSet.
3774
3775 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
3776 BufferLength was updated.
3777 @retval EFI_INVALID_PARAMETER The handle is unknown.
3778 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
3779 be found with the requested FormId.
3780
3781 **/
3782 EFI_STATUS
3783 GetIfrBinaryData (
3784 IN EFI_HII_HANDLE Handle,
3785 IN OUT EFI_GUID *FormSetGuid,
3786 OUT UINTN *BinaryLength,
3787 OUT UINT8 **BinaryData
3788 )
3789 {
3790 EFI_STATUS Status;
3791 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
3792 UINTN BufferSize;
3793 UINT8 *Package;
3794 UINT8 *OpCodeData;
3795 UINT32 Offset;
3796 UINT32 Offset2;
3797 UINT32 PackageListLength;
3798 EFI_HII_PACKAGE_HEADER PackageHeader;
3799 UINT8 Index;
3800 UINT8 NumberOfClassGuid;
3801 BOOLEAN ClassGuidMatch;
3802 EFI_GUID *ClassGuid;
3803 EFI_GUID *ComparingGuid;
3804
3805 OpCodeData = NULL;
3806 Package = NULL;
3807 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
3808
3809 //
3810 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
3811 //
3812 if (FormSetGuid == NULL) {
3813 ComparingGuid = &gZeroGuid;
3814 } else {
3815 ComparingGuid = FormSetGuid;
3816 }
3817
3818 //
3819 // Get HII PackageList
3820 //
3821 BufferSize = 0;
3822 HiiPackageList = NULL;
3823 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
3824 if (Status == EFI_BUFFER_TOO_SMALL) {
3825 HiiPackageList = AllocatePool (BufferSize);
3826 ASSERT (HiiPackageList != NULL);
3827
3828 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
3829 }
3830 if (EFI_ERROR (Status)) {
3831 return Status;
3832 }
3833 ASSERT (HiiPackageList != NULL);
3834
3835 //
3836 // Get Form package from this HII package List
3837 //
3838 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3839 Offset2 = 0;
3840 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
3841
3842 ClassGuidMatch = FALSE;
3843 while (Offset < PackageListLength) {
3844 Package = ((UINT8 *) HiiPackageList) + Offset;
3845 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3846
3847 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
3848 //
3849 // Search FormSet in this Form Package
3850 //
3851 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
3852 while (Offset2 < PackageHeader.Length) {
3853 OpCodeData = Package + Offset2;
3854
3855 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
3856 //
3857 // Try to compare against formset GUID
3858 //
3859 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
3860 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
3861 break;
3862 }
3863
3864 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
3865 //
3866 // Try to compare against formset class GUID
3867 //
3868 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
3869 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
3870 for (Index = 0; Index < NumberOfClassGuid; Index++) {
3871 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
3872 ClassGuidMatch = TRUE;
3873 break;
3874 }
3875 }
3876 if (ClassGuidMatch) {
3877 break;
3878 }
3879 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
3880 ClassGuidMatch = TRUE;
3881 break;
3882 }
3883 }
3884
3885 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
3886 }
3887
3888 if (Offset2 < PackageHeader.Length) {
3889 //
3890 // Target formset found
3891 //
3892 break;
3893 }
3894 }
3895
3896 Offset += PackageHeader.Length;
3897 }
3898
3899 if (Offset >= PackageListLength) {
3900 //
3901 // Form package not found in this Package List
3902 //
3903 FreePool (HiiPackageList);
3904 return EFI_NOT_FOUND;
3905 }
3906
3907 if (FormSetGuid != NULL) {
3908 //
3909 // Return the FormSet GUID
3910 //
3911 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
3912 }
3913
3914 //
3915 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
3916 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
3917 // of the Form Package.
3918 //
3919 *BinaryLength = PackageHeader.Length - Offset2;
3920 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
3921
3922 FreePool (HiiPackageList);
3923
3924 if (*BinaryData == NULL) {
3925 return EFI_OUT_OF_RESOURCES;
3926 }
3927
3928 return EFI_SUCCESS;
3929 }
3930
3931
3932 /**
3933 Initialize the internal data structure of a FormSet.
3934
3935 @param Handle PackageList Handle
3936 @param FormSetGuid On input, GUID or class GUID of a formset. If not
3937 specified (NULL or zero GUID), take the first
3938 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
3939 found in package list.
3940 On output, GUID of the formset found(if not NULL).
3941 @param FormSet FormSet data structure.
3942 @param UpdateGlobalVar Whether need to update the global variable.
3943
3944 @retval EFI_SUCCESS The function completed successfully.
3945 @retval EFI_NOT_FOUND The specified FormSet could not be found.
3946
3947 **/
3948 EFI_STATUS
3949 InitializeFormSet (
3950 IN EFI_HII_HANDLE Handle,
3951 IN OUT EFI_GUID *FormSetGuid,
3952 OUT FORM_BROWSER_FORMSET *FormSet,
3953 IN BOOLEAN UpdateGlobalVar
3954 )
3955 {
3956 EFI_STATUS Status;
3957 EFI_HANDLE DriverHandle;
3958 UINT16 Index;
3959
3960 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
3961 if (EFI_ERROR (Status)) {
3962 return Status;
3963 }
3964
3965 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
3966 FormSet->HiiHandle = Handle;
3967 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
3968
3969 //
3970 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
3971 //
3972 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
3973 if (EFI_ERROR (Status)) {
3974 return Status;
3975 }
3976 FormSet->DriverHandle = DriverHandle;
3977 Status = gBS->HandleProtocol (
3978 DriverHandle,
3979 &gEfiHiiConfigAccessProtocolGuid,
3980 (VOID **) &FormSet->ConfigAccess
3981 );
3982 if (EFI_ERROR (Status)) {
3983 //
3984 // Configuration Driver don't attach ConfigAccess protocol to its HII package
3985 // list, then there will be no configuration action required
3986 //
3987 FormSet->ConfigAccess = NULL;
3988 }
3989
3990 //
3991 // Parse the IFR binary OpCodes
3992 //
3993 Status = ParseOpCodes (FormSet);
3994 if (EFI_ERROR (Status)) {
3995 return Status;
3996 }
3997
3998 //
3999 // If not need to update the global variable, just return.
4000 //
4001 if (!UpdateGlobalVar) {
4002 return Status;
4003 }
4004
4005 //
4006 // Set VFR type by FormSet SubClass field
4007 //
4008 gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
4009 if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
4010 gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
4011 }
4012
4013 //
4014 // Set VFR type by FormSet class guid
4015 //
4016 for (Index = 0; Index < 3; Index ++) {
4017 if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
4018 gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
4019 break;
4020 }
4021 }
4022
4023 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
4024 gFrontPageHandle = FormSet->HiiHandle;
4025 gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;
4026 }
4027
4028 //
4029 // Match GUID to find out the function key setting. If match fail, use the default setting.
4030 //
4031 for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
4032 if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
4033 //
4034 // Update the function key setting.
4035 //
4036 gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
4037 }
4038 }
4039
4040 return EFI_SUCCESS;
4041 }
4042
4043
4044 /**
4045 Save globals used by previous call to SendForm(). SendForm() may be called from
4046 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
4047 So, save globals of previous call to SendForm() and restore them upon exit.
4048
4049 **/
4050 VOID
4051 SaveBrowserContext (
4052 VOID
4053 )
4054 {
4055 BROWSER_CONTEXT *Context;
4056
4057 gBrowserContextCount++;
4058 if (gBrowserContextCount == 1) {
4059 //
4060 // This is not reentry of SendForm(), no context to save
4061 //
4062 return;
4063 }
4064
4065 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
4066 ASSERT (Context != NULL);
4067
4068 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
4069
4070 //
4071 // Save FormBrowser context
4072 //
4073 Context->BannerData = gBannerData;
4074 Context->ClassOfVfr = gClassOfVfr;
4075 Context->FunctionKeySetting = gFunctionKeySetting;
4076 Context->ResetRequired = gResetRequired;
4077 Context->Direction = gDirection;
4078 Context->EnterString = gEnterString;
4079 Context->EnterCommitString = gEnterCommitString;
4080 Context->EnterEscapeString = gEnterEscapeString;
4081 Context->EscapeString = gEscapeString;
4082 Context->MoveHighlight = gMoveHighlight;
4083 Context->MakeSelection = gMakeSelection;
4084 Context->DecNumericInput = gDecNumericInput;
4085 Context->HexNumericInput = gHexNumericInput;
4086 Context->ToggleCheckBox = gToggleCheckBox;
4087 Context->PromptForData = gPromptForData;
4088 Context->PromptForPassword = gPromptForPassword;
4089 Context->PromptForNewPassword = gPromptForNewPassword;
4090 Context->ConfirmPassword = gConfirmPassword;
4091 Context->ConfirmError = gConfirmError;
4092 Context->PassowordInvalid = gPassowordInvalid;
4093 Context->PressEnter = gPressEnter;
4094 Context->EmptyString = gEmptyString;
4095 Context->AreYouSure = gAreYouSure;
4096 Context->YesResponse = gYesResponse;
4097 Context->NoResponse = gNoResponse;
4098 Context->MiniString = gMiniString;
4099 Context->PlusString = gPlusString;
4100 Context->MinusString = gMinusString;
4101 Context->AdjustNumber = gAdjustNumber;
4102 Context->SaveChanges = gSaveChanges;
4103 Context->OptionMismatch = gOptionMismatch;
4104 Context->FormSuppress = gFormSuppress;
4105 Context->PromptBlockWidth = gPromptBlockWidth;
4106 Context->OptionBlockWidth = gOptionBlockWidth;
4107 Context->HelpBlockWidth = gHelpBlockWidth;
4108 Context->OldFormSet = gOldFormSet;
4109 Context->MenuRefreshHead = gMenuRefreshHead;
4110
4111 CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
4112 CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
4113
4114 //
4115 // Insert to FormBrowser context list
4116 //
4117 InsertHeadList (&gBrowserContextList, &Context->Link);
4118 }
4119
4120
4121 /**
4122 Restore globals used by previous call to SendForm().
4123
4124 **/
4125 VOID
4126 RestoreBrowserContext (
4127 VOID
4128 )
4129 {
4130 LIST_ENTRY *Link;
4131 BROWSER_CONTEXT *Context;
4132
4133 ASSERT (gBrowserContextCount != 0);
4134 gBrowserContextCount--;
4135 if (gBrowserContextCount == 0) {
4136 //
4137 // This is not reentry of SendForm(), no context to restore
4138 //
4139 return;
4140 }
4141
4142 ASSERT (!IsListEmpty (&gBrowserContextList));
4143
4144 Link = GetFirstNode (&gBrowserContextList);
4145 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4146
4147 //
4148 // Restore FormBrowser context
4149 //
4150 gBannerData = Context->BannerData;
4151 gClassOfVfr = Context->ClassOfVfr;
4152 gFunctionKeySetting = Context->FunctionKeySetting;
4153 gResetRequired = Context->ResetRequired;
4154 gDirection = Context->Direction;
4155 gEnterString = Context->EnterString;
4156 gEnterCommitString = Context->EnterCommitString;
4157 gEnterEscapeString = Context->EnterEscapeString;
4158 gEscapeString = Context->EscapeString;
4159 gMoveHighlight = Context->MoveHighlight;
4160 gMakeSelection = Context->MakeSelection;
4161 gDecNumericInput = Context->DecNumericInput;
4162 gHexNumericInput = Context->HexNumericInput;
4163 gToggleCheckBox = Context->ToggleCheckBox;
4164 gPromptForData = Context->PromptForData;
4165 gPromptForPassword = Context->PromptForPassword;
4166 gPromptForNewPassword = Context->PromptForNewPassword;
4167 gConfirmPassword = Context->ConfirmPassword;
4168 gConfirmError = Context->ConfirmError;
4169 gPassowordInvalid = Context->PassowordInvalid;
4170 gPressEnter = Context->PressEnter;
4171 gEmptyString = Context->EmptyString;
4172 gAreYouSure = Context->AreYouSure;
4173 gYesResponse = Context->YesResponse;
4174 gNoResponse = Context->NoResponse;
4175 gMiniString = Context->MiniString;
4176 gPlusString = Context->PlusString;
4177 gMinusString = Context->MinusString;
4178 gAdjustNumber = Context->AdjustNumber;
4179 gSaveChanges = Context->SaveChanges;
4180 gOptionMismatch = Context->OptionMismatch;
4181 gFormSuppress = Context->FormSuppress;
4182 gPromptBlockWidth = Context->PromptBlockWidth;
4183 gOptionBlockWidth = Context->OptionBlockWidth;
4184 gHelpBlockWidth = Context->HelpBlockWidth;
4185 gOldFormSet = Context->OldFormSet;
4186 gMenuRefreshHead = Context->MenuRefreshHead;
4187
4188 CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
4189 CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
4190
4191 //
4192 // Remove from FormBrowser context list
4193 //
4194 RemoveEntryList (&Context->Link);
4195 gBS->FreePool (Context);
4196 }
4197
4198 /**
4199 Find the matched FormSet context in the backup maintain list based on HiiHandle.
4200
4201 @param Handle The Hii Handle.
4202
4203 @return the found FormSet context. If no found, NULL will return.
4204
4205 **/
4206 FORM_BROWSER_FORMSET *
4207 GetFormSetFromHiiHandle (
4208 EFI_HII_HANDLE Handle
4209 )
4210 {
4211 LIST_ENTRY *Link;
4212 FORM_BROWSER_FORMSET *FormSet;
4213
4214 Link = GetFirstNode (&gBrowserFormSetList);
4215 while (!IsNull (&gBrowserFormSetList, Link)) {
4216 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4217 if (FormSet->HiiHandle == Handle) {
4218 return FormSet;
4219 }
4220 Link = GetNextNode (&gBrowserFormSetList, Link);
4221 }
4222
4223 return NULL;
4224 }
4225
4226 /**
4227 Check whether the input HII handle is the FormSet that is being used.
4228
4229 @param Handle The Hii Handle.
4230
4231 @retval TRUE HII handle is being used.
4232 @retval FALSE HII handle is not being used.
4233
4234 **/
4235 BOOLEAN
4236 IsHiiHandleInBrowserContext (
4237 EFI_HII_HANDLE Handle
4238 )
4239 {
4240 LIST_ENTRY *Link;
4241 BROWSER_CONTEXT *Context;
4242
4243 //
4244 // HiiHandle is Current FormSet.
4245 //
4246 if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {
4247 return TRUE;
4248 }
4249
4250 //
4251 // Check whether HiiHandle is in BrowserContext.
4252 //
4253 Link = GetFirstNode (&gBrowserContextList);
4254 while (!IsNull (&gBrowserContextList, Link)) {
4255 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4256 if (Context->OldFormSet->HiiHandle == Handle) {
4257 //
4258 // HiiHandle is in BrowserContext
4259 //
4260 return TRUE;
4261 }
4262 Link = GetNextNode (&gBrowserContextList, Link);
4263 }
4264
4265 return FALSE;
4266 }
4267
4268 /**
4269 Find the registered HotKey based on KeyData.
4270
4271 @param[in] KeyData A pointer to a buffer that describes the keystroke
4272 information for the hot key.
4273
4274 @return The registered HotKey context. If no found, NULL will return.
4275 **/
4276 BROWSER_HOT_KEY *
4277 GetHotKeyFromRegisterList (
4278 IN EFI_INPUT_KEY *KeyData
4279 )
4280 {
4281 LIST_ENTRY *Link;
4282 BROWSER_HOT_KEY *HotKey;
4283
4284 Link = GetFirstNode (&gBrowserHotKeyList);
4285 while (!IsNull (&gBrowserHotKeyList, Link)) {
4286 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
4287 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
4288 return HotKey;
4289 }
4290 Link = GetNextNode (&gBrowserHotKeyList, Link);
4291 }
4292
4293 return NULL;
4294 }
4295
4296 /**
4297 Configure what scope the hot key will impact.
4298 All hot keys have the same scope. The mixed hot keys with the different level are not supported.
4299 If no scope is set, the default scope will be FormSet level.
4300 After all registered hot keys are removed, previous Scope can reset to another level.
4301
4302 @param[in] Scope Scope level to be set.
4303
4304 @retval EFI_SUCCESS Scope is set correctly.
4305 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE.
4306 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.
4307
4308 **/
4309 EFI_STATUS
4310 EFIAPI
4311 SetScope (
4312 IN BROWSER_SETTING_SCOPE Scope
4313 )
4314 {
4315 if (Scope >= MaxLevel) {
4316 return EFI_INVALID_PARAMETER;
4317 }
4318
4319 //
4320 // When no hot key registered in system or on the first setting,
4321 // Scope can be set.
4322 //
4323 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {
4324 gBrowserSettingScope = Scope;
4325 mBrowserScopeFirstSet = FALSE;
4326 } else if (Scope != gBrowserSettingScope) {
4327 return EFI_UNSUPPORTED;
4328 }
4329
4330 return EFI_SUCCESS;
4331 }
4332
4333 /**
4334 Register the hot key with its browser action, or unregistered the hot key.
4335 Only support hot key that is not printable character (control key, function key, etc.).
4336 If the action value is zero, the hot key will be unregistered if it has been registered.
4337 If the same hot key has been registered, the new action and help string will override the previous ones.
4338
4339 @param[in] KeyData A pointer to a buffer that describes the keystroke
4340 information for the hot key. Its type is EFI_INPUT_KEY to
4341 be supported by all ConsoleIn devices.
4342 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed.
4343 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.
4344 @param[in] HelpString Help string that describes the hot key information.
4345 Its value may be NULL for the unregistered hot key.
4346
4347 @retval EFI_SUCCESS Hot key is registered or unregistered.
4348 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.
4349 @retval EFI_NOT_FOUND KeyData is not found to be unregistered.
4350 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.
4351 **/
4352 EFI_STATUS
4353 EFIAPI
4354 RegisterHotKey (
4355 IN EFI_INPUT_KEY *KeyData,
4356 IN UINT32 Action,
4357 IN UINT16 DefaultId,
4358 IN EFI_STRING HelpString OPTIONAL
4359 )
4360 {
4361 BROWSER_HOT_KEY *HotKey;
4362
4363 //
4364 // Check input parameters.
4365 //
4366 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL ||
4367 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {
4368 return EFI_INVALID_PARAMETER;
4369 }
4370
4371 //
4372 // Check whether the input KeyData is in BrowserHotKeyList.
4373 //
4374 HotKey = GetHotKeyFromRegisterList (KeyData);
4375
4376 //
4377 // Unregister HotKey
4378 //
4379 if (Action == BROWSER_ACTION_UNREGISTER) {
4380 if (HotKey != NULL) {
4381 //
4382 // The registered HotKey is found.
4383 // Remove it from List, and free its resource.
4384 //
4385 RemoveEntryList (&HotKey->Link);
4386 FreePool (HotKey->KeyData);
4387 FreePool (HotKey->HelpString);
4388 return EFI_SUCCESS;
4389 } else {
4390 //
4391 // The registered HotKey is not found.
4392 //
4393 return EFI_NOT_FOUND;
4394 }
4395 }
4396
4397 //
4398 // Register HotKey into List.
4399 //
4400 if (HotKey == NULL) {
4401 //
4402 // Create new Key, and add it into List.
4403 //
4404 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));
4405 ASSERT (HotKey != NULL);
4406 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;
4407 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);
4408 InsertTailList (&gBrowserHotKeyList, &HotKey->Link);
4409 }
4410
4411 //
4412 // Fill HotKey information.
4413 //
4414 HotKey->Action = Action;
4415 HotKey->DefaultId = DefaultId;
4416 if (HotKey->HelpString != NULL) {
4417 FreePool (HotKey->HelpString);
4418 }
4419 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);
4420
4421 return EFI_SUCCESS;
4422 }
4423
4424 /**
4425 Register Exit handler function.
4426 When more than one handler function is registered, the latter one will override the previous one.
4427 When NULL handler is specified, the previous Exit handler will be unregistered.
4428
4429 @param[in] Handler Pointer to handler function.
4430
4431 **/
4432 VOID
4433 EFIAPI
4434 RegiserExitHandler (
4435 IN EXIT_HANDLER Handler
4436 )
4437 {
4438 ExitHandlerFunction = Handler;
4439 return;
4440 }
4441
4442 /**
4443 Create reminder to let user to choose save or discard the changed browser data.
4444 Caller can use it to actively check the changed browser data.
4445
4446 @retval BROWSER_NO_CHANGES No browser data is changed.
4447 @retval BROWSER_SAVE_CHANGES The changed browser data is saved.
4448 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.
4449
4450 **/
4451 UINT32
4452 EFIAPI
4453 SaveReminder (
4454 VOID
4455 )
4456 {
4457 LIST_ENTRY *Link;
4458 FORM_BROWSER_FORMSET *FormSet;
4459 BOOLEAN IsDataChanged;
4460 UINT32 DataSavedAction;
4461 CHAR16 *YesResponse;
4462 CHAR16 *NoResponse;
4463 CHAR16 *EmptyString;
4464 CHAR16 *ChangeReminderString;
4465 CHAR16 *SaveConfirmString;
4466 EFI_INPUT_KEY Key;
4467
4468 DataSavedAction = BROWSER_NO_CHANGES;
4469 IsDataChanged = FALSE;
4470 Link = GetFirstNode (&gBrowserFormSetList);
4471 while (!IsNull (&gBrowserFormSetList, Link)) {
4472 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4473 if (IsNvUpdateRequired (FormSet)) {
4474 IsDataChanged = TRUE;
4475 break;
4476 }
4477 Link = GetNextNode (&gBrowserFormSetList, Link);
4478 }
4479
4480 //
4481 // No data is changed. No save is required.
4482 //
4483 if (!IsDataChanged) {
4484 return DataSavedAction;
4485 }
4486
4487 //
4488 // If data is changed, prompt user
4489 //
4490 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
4491
4492 YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
4493 ASSERT (YesResponse != NULL);
4494 NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
4495 ASSERT (NoResponse != NULL);
4496 EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
4497 ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);
4498 SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);
4499
4500 do {
4501 CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);
4502 } while
4503 (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&
4504 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))
4505 );
4506
4507 //
4508 // If the user hits the YesResponse key
4509 //
4510 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {
4511 SubmitForm (NULL, NULL, SystemLevel);
4512 DataSavedAction = BROWSER_SAVE_CHANGES;
4513 } else {
4514 DiscardForm (NULL, NULL, SystemLevel);
4515 DataSavedAction = BROWSER_DISCARD_CHANGES;
4516 gResetRequired = FALSE;
4517 }
4518
4519 FreePool (YesResponse);
4520 FreePool (NoResponse);
4521 FreePool (EmptyString);
4522 FreePool (SaveConfirmString);
4523 FreePool (ChangeReminderString);
4524
4525 return DataSavedAction;
4526 }