]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
MdeMdeModulePkg/BootScriptExecutorDxe: Replaces absolute addressing that requires...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Setup.c
1 /** @file
2 Entry and initialization module for the browser.
3
4 Copyright (c) 2007 - 2013, 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 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;
36
37 UINTN gBrowserContextCount = 0;
38 LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
39 LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList);
40 LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);
41
42 BANNER_DATA *gBannerData;
43 EFI_HII_HANDLE gFrontPageHandle;
44 UINTN gClassOfVfr;
45 UINTN gFunctionKeySetting;
46 BOOLEAN gResetRequired;
47 EFI_HII_HANDLE gHiiHandle;
48 UINT16 gDirection;
49 EFI_SCREEN_DESCRIPTOR gScreenDimensions;
50 BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;
51 BOOLEAN mBrowserScopeFirstSet = TRUE;
52 EXIT_HANDLER ExitHandlerFunction = NULL;
53 UINTN gFooterHeight;
54
55 //
56 // Browser Global Strings
57 //
58 CHAR16 *gSaveFailed;
59 CHAR16 *gDiscardFailed;
60 CHAR16 *gDefaultFailed;
61 CHAR16 *gEnterString;
62 CHAR16 *gEnterCommitString;
63 CHAR16 *gEnterEscapeString;
64 CHAR16 *gEscapeString;
65 CHAR16 *gMoveHighlight;
66 CHAR16 *gMakeSelection;
67 CHAR16 *gDecNumericInput;
68 CHAR16 *gHexNumericInput;
69 CHAR16 *gToggleCheckBox;
70 CHAR16 *gPromptForData;
71 CHAR16 *gPromptForPassword;
72 CHAR16 *gPromptForNewPassword;
73 CHAR16 *gConfirmPassword;
74 CHAR16 *gConfirmError;
75 CHAR16 *gPassowordInvalid;
76 CHAR16 *gPressEnter;
77 CHAR16 *gEmptyString;
78 CHAR16 *gAreYouSure;
79 CHAR16 *gYesResponse;
80 CHAR16 *gNoResponse;
81 CHAR16 *gMiniString;
82 CHAR16 *gPlusString;
83 CHAR16 *gMinusString;
84 CHAR16 *gAdjustNumber;
85 CHAR16 *gSaveChanges;
86 CHAR16 *gOptionMismatch;
87 CHAR16 *gFormSuppress;
88 CHAR16 *gProtocolNotFound;
89
90 CHAR16 *mUnknownString = L"!";
91
92 CHAR16 gPromptBlockWidth;
93 CHAR16 gOptionBlockWidth;
94 CHAR16 gHelpBlockWidth;
95
96 EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
97 EFI_GUID gSetupBrowserGuid = {
98 0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}
99 };
100
101 FORM_BROWSER_FORMSET *gOldFormSet = NULL;
102
103 FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {
104 //
105 // Boot Manager
106 //
107 {
108 {
109 0x847bc3fe,
110 0xb974,
111 0x446d,
112 {
113 0x94,
114 0x49,
115 0x5a,
116 0xd5,
117 0x41,
118 0x2e,
119 0x99,
120 0x3b
121 }
122 },
123 NONE_FUNCTION_KEY_SETTING
124 },
125 //
126 // Device Manager
127 //
128 {
129 {
130 0x3ebfa8e6,
131 0x511d,
132 0x4b5b,
133 {
134 0xa9,
135 0x5f,
136 0xfb,
137 0x38,
138 0x26,
139 0xf,
140 0x1c,
141 0x27
142 }
143 },
144 NONE_FUNCTION_KEY_SETTING
145 },
146 //
147 // BMM FormSet.
148 //
149 {
150 {
151 0x642237c7,
152 0x35d4,
153 0x472d,
154 {
155 0x83,
156 0x65,
157 0x12,
158 0xe0,
159 0xcc,
160 0xf2,
161 0x7a,
162 0x22
163 }
164 },
165 NONE_FUNCTION_KEY_SETTING
166 },
167 //
168 // BMM File Explorer FormSet.
169 //
170 {
171 {
172 0x1f2d63e1,
173 0xfebd,
174 0x4dc7,
175 {
176 0x9c,
177 0xc5,
178 0xba,
179 0x2b,
180 0x1c,
181 0xef,
182 0x9c,
183 0x5b
184 }
185 },
186 NONE_FUNCTION_KEY_SETTING
187 },
188 };
189
190 /**
191 This is the routine which an external caller uses to direct the browser
192 where to obtain it's information.
193
194
195 @param This The Form Browser protocol instanse.
196 @param Handles A pointer to an array of Handles. If HandleCount > 1 we
197 display a list of the formsets for the handles specified.
198 @param HandleCount The number of Handles specified in Handle.
199 @param FormSetGuid This field points to the EFI_GUID which must match the Guid
200 field in the EFI_IFR_FORM_SET op-code for the specified
201 forms-based package. If FormSetGuid is NULL, then this
202 function will display the first found forms package.
203 @param FormId This field specifies which EFI_IFR_FORM to render as the first
204 displayable page. If this field has a value of 0x0000, then
205 the forms browser will render the specified forms in their encoded order.
206 @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
207 characters.
208 @param ActionRequest Points to the action recommended by the form.
209
210 @retval EFI_SUCCESS The function completed successfully.
211 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
212 @retval EFI_NOT_FOUND No valid forms could be found to display.
213
214 **/
215 EFI_STATUS
216 EFIAPI
217 SendForm (
218 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
219 IN EFI_HII_HANDLE *Handles,
220 IN UINTN HandleCount,
221 IN EFI_GUID *FormSetGuid, OPTIONAL
222 IN UINT16 FormId, OPTIONAL
223 IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL
224 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL
225 )
226 {
227 EFI_STATUS Status;
228 UI_MENU_SELECTION *Selection;
229 UINTN Index;
230 FORM_BROWSER_FORMSET *FormSet;
231 LIST_ENTRY *Link;
232
233 //
234 // Calculate total number of Register HotKeys.
235 //
236 Index = 0;
237 Link = GetFirstNode (&gBrowserHotKeyList);
238 while (!IsNull (&gBrowserHotKeyList, Link)) {
239 Link = GetNextNode (&gBrowserHotKeyList, Link);
240 Index ++;
241 }
242 //
243 // Show three HotKeys help information on one ROW.
244 //
245 gFooterHeight = FOOTER_HEIGHT + (Index / 3);
246
247 //
248 // Clean the history menu list.
249 //
250 InitializeListHead (&gMenuList);
251
252 //
253 // Save globals used by SendForm()
254 //
255 SaveBrowserContext ();
256
257 gResetRequired = FALSE;
258 Status = EFI_SUCCESS;
259 ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
260
261 //
262 // Seed the dimensions in the global
263 //
264 gST->ConOut->QueryMode (
265 gST->ConOut,
266 gST->ConOut->Mode->Mode,
267 &gScreenDimensions.RightColumn,
268 &gScreenDimensions.BottomRow
269 );
270
271 if (ScreenDimensions != NULL) {
272 //
273 // Check local dimension vs. global dimension.
274 //
275 if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||
276 (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)
277 ) {
278 Status = EFI_INVALID_PARAMETER;
279 goto Done;
280 } else {
281 //
282 // Local dimension validation.
283 //
284 if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&
285 (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&
286 ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&
287 (
288 (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
289 SCROLL_ARROW_HEIGHT *
290 2 +
291 FRONT_PAGE_HEADER_HEIGHT +
292 gFooterHeight +
293 1
294 )
295 ) {
296 CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
297 } else {
298 Status = EFI_INVALID_PARAMETER;
299 goto Done;
300 }
301 }
302 }
303
304 gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
305 gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);
306 gHelpBlockWidth = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);
307
308 //
309 // Initialize the strings for the browser, upon exit of the browser, the strings will be freed
310 //
311 InitializeBrowserStrings ();
312
313 //
314 // Ensure we are in Text mode
315 //
316 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
317
318 for (Index = 0; Index < HandleCount; Index++) {
319 Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
320 ASSERT (Selection != NULL);
321
322 Selection->Handle = Handles[Index];
323 if (FormSetGuid != NULL) {
324 CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
325 Selection->FormId = FormId;
326 } else {
327 CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID));
328 }
329
330 do {
331 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
332 ASSERT (FormSet != NULL);
333
334 //
335 // Initialize internal data structures of FormSet
336 //
337 Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet, TRUE);
338 if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
339 DestroyFormSet (FormSet);
340 break;
341 }
342 Selection->FormSet = FormSet;
343
344 //
345 // Try to find pre FormSet in the maintain backup list.
346 //
347 gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle);
348
349 //
350 // Display this formset
351 //
352 gCurrentSelection = Selection;
353
354 Status = SetupBrowser (Selection);
355
356 gCurrentSelection = NULL;
357
358 if (EFI_ERROR (Status)) {
359 break;
360 }
361
362 } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
363
364 if (gOldFormSet != NULL) {
365 //
366 // If no data is changed, don't need to save current FormSet into the maintain list.
367 //
368 if (!IsNvUpdateRequired (gOldFormSet)) {
369 RemoveEntryList (&gOldFormSet->Link);
370 DestroyFormSet (gOldFormSet);
371 }
372 gOldFormSet = NULL;
373 }
374
375 FreePool (Selection);
376 }
377
378 if (ActionRequest != NULL) {
379 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
380 if (gResetRequired) {
381 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
382 }
383 }
384
385 FreeBrowserStrings ();
386 UiFreeMenuList(&gMenuList);
387
388 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
389 gST->ConOut->ClearScreen (gST->ConOut);
390
391 Done:
392 //
393 // Restore globals used by SendForm()
394 //
395 RestoreBrowserContext ();
396
397 return Status;
398 }
399
400
401 /**
402 This function is called by a callback handler to retrieve uncommitted state
403 data from the browser.
404
405 @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL
406 instance.
407 @param ResultsDataSize A pointer to the size of the buffer associated
408 with ResultsData.
409 @param ResultsData A string returned from an IFR browser or
410 equivalent. The results string will have no
411 routing information in them.
412 @param RetrieveData A BOOLEAN field which allows an agent to retrieve
413 (if RetrieveData = TRUE) data from the uncommitted
414 browser state information or set (if RetrieveData
415 = FALSE) data in the uncommitted browser state
416 information.
417 @param VariableGuid An optional field to indicate the target variable
418 GUID name to use.
419 @param VariableName An optional field to indicate the target
420 human-readable variable name.
421
422 @retval EFI_SUCCESS The results have been distributed or are awaiting
423 distribution.
424 @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to
425 contain the results data.
426
427 **/
428 EFI_STATUS
429 EFIAPI
430 BrowserCallback (
431 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This,
432 IN OUT UINTN *ResultsDataSize,
433 IN OUT EFI_STRING ResultsData,
434 IN BOOLEAN RetrieveData,
435 IN CONST EFI_GUID *VariableGuid, OPTIONAL
436 IN CONST CHAR16 *VariableName OPTIONAL
437 )
438 {
439 EFI_STATUS Status;
440 LIST_ENTRY *Link;
441 FORMSET_STORAGE *Storage;
442 FORM_BROWSER_FORMSET *FormSet;
443 BOOLEAN Found;
444 CHAR16 *ConfigResp;
445 CHAR16 *StrPtr;
446 UINTN BufferSize;
447 UINTN TmpSize;
448
449 if (ResultsDataSize == NULL || ResultsData == NULL) {
450 return EFI_INVALID_PARAMETER;
451 }
452
453 if (gCurrentSelection == NULL) {
454 return EFI_NOT_READY;
455 }
456
457 Storage = NULL;
458 ConfigResp = NULL;
459 FormSet = gCurrentSelection->FormSet;
460
461 //
462 // Find target storage
463 //
464 Link = GetFirstNode (&FormSet->StorageListHead);
465 if (IsNull (&FormSet->StorageListHead, Link)) {
466 return EFI_UNSUPPORTED;
467 }
468
469 if (VariableGuid != NULL) {
470 //
471 // Try to find target storage
472 //
473 Found = FALSE;
474 while (!IsNull (&FormSet->StorageListHead, Link)) {
475 Storage = FORMSET_STORAGE_FROM_LINK (Link);
476 Link = GetNextNode (&FormSet->StorageListHead, Link);
477
478 if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
479 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
480 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
481 //
482 // Buffer storage require both GUID and Name
483 //
484 if (VariableName == NULL) {
485 return EFI_NOT_FOUND;
486 }
487
488 if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
489 continue;
490 }
491 }
492 Found = TRUE;
493 break;
494 }
495 }
496
497 if (!Found) {
498 return EFI_NOT_FOUND;
499 }
500 } else {
501 //
502 // GUID/Name is not specified, take the first storage in FormSet
503 //
504 Storage = FORMSET_STORAGE_FROM_LINK (Link);
505 }
506
507 if (RetrieveData) {
508 //
509 // Skip if there is no RequestElement
510 //
511 if (Storage->ElementCount == 0) {
512 return EFI_SUCCESS;
513 }
514
515 //
516 // Generate <ConfigResp>
517 //
518 Status = StorageToConfigResp (Storage, &ConfigResp, FALSE);
519 if (EFI_ERROR (Status)) {
520 return Status;
521 }
522
523 //
524 // Skip <ConfigHdr> and '&' to point to <ConfigBody>
525 //
526 StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;
527
528 BufferSize = StrSize (StrPtr);
529 if (*ResultsDataSize < BufferSize) {
530 *ResultsDataSize = BufferSize;
531
532 FreePool (ConfigResp);
533 return EFI_BUFFER_TOO_SMALL;
534 }
535
536 *ResultsDataSize = BufferSize;
537 CopyMem (ResultsData, StrPtr, BufferSize);
538
539 FreePool (ConfigResp);
540 } else {
541 //
542 // Prepare <ConfigResp>
543 //
544 TmpSize = StrLen (ResultsData);
545 BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);
546 ConfigResp = AllocateZeroPool (BufferSize);
547 ASSERT (ConfigResp != NULL);
548
549 StrCpy (ConfigResp, Storage->ConfigHdr);
550 StrCat (ConfigResp, L"&");
551 StrCat (ConfigResp, ResultsData);
552
553 //
554 // Update Browser uncommited data
555 //
556 Status = ConfigRespToStorage (Storage, ConfigResp);
557 if (EFI_ERROR (Status)) {
558 return Status;
559 }
560 }
561
562 return EFI_SUCCESS;
563 }
564
565 /**
566 Initialize Setup Browser driver.
567
568 @param ImageHandle The image handle.
569 @param SystemTable The system table.
570
571 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
572 @return Other value if failed to initialize the Setup Browser module.
573
574 **/
575 EFI_STATUS
576 EFIAPI
577 InitializeSetup (
578 IN EFI_HANDLE ImageHandle,
579 IN EFI_SYSTEM_TABLE *SystemTable
580 )
581 {
582 EFI_STATUS Status;
583 EFI_INPUT_KEY DefaultHotKey;
584 EFI_STRING HelpString;
585
586 //
587 // Locate required Hii relative protocols
588 //
589 Status = gBS->LocateProtocol (
590 &gEfiHiiDatabaseProtocolGuid,
591 NULL,
592 (VOID **) &mHiiDatabase
593 );
594 ASSERT_EFI_ERROR (Status);
595
596 Status = gBS->LocateProtocol (
597 &gEfiHiiStringProtocolGuid,
598 NULL,
599 (VOID **) &mHiiString
600 );
601 ASSERT_EFI_ERROR (Status);
602
603 Status = gBS->LocateProtocol (
604 &gEfiHiiConfigRoutingProtocolGuid,
605 NULL,
606 (VOID **) &mHiiConfigRouting
607 );
608 ASSERT_EFI_ERROR (Status);
609
610 Status = gBS->LocateProtocol (
611 &gEfiDevicePathFromTextProtocolGuid,
612 NULL,
613 (VOID **) &mPathFromText
614 );
615
616 //
617 // Publish our HII data
618 //
619 gHiiHandle = HiiAddPackages (
620 &gSetupBrowserGuid,
621 ImageHandle,
622 SetupBrowserStrings,
623 NULL
624 );
625 ASSERT (gHiiHandle != NULL);
626
627 //
628 // Initialize Driver private data
629 //
630 gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
631 ASSERT (gBannerData != NULL);
632
633 //
634 // Initialize generic help strings.
635 //
636 gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);
637 gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle);
638 gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle);
639
640 //
641 // Install FormBrowser2 protocol
642 //
643 mPrivateData.Handle = NULL;
644 Status = gBS->InstallProtocolInterface (
645 &mPrivateData.Handle,
646 &gEfiFormBrowser2ProtocolGuid,
647 EFI_NATIVE_INTERFACE,
648 &mPrivateData.FormBrowser2
649 );
650 ASSERT_EFI_ERROR (Status);
651
652 //
653 // Install default HotKey F10 for Save
654 //
655 DefaultHotKey.UnicodeChar = CHAR_NULL;
656 HelpString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);
657 DefaultHotKey.ScanCode = SCAN_F10;
658 RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString);
659 FreePool (HelpString);
660 //
661 // Install default HotKey F9 for Reset To Defaults
662 //
663 DefaultHotKey.ScanCode = SCAN_F9;
664 HelpString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);
665 RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString);
666 FreePool (HelpString);
667
668 //
669 // Install FormBrowserEx protocol
670 //
671 mPrivateData.Handle = NULL;
672 Status = gBS->InstallProtocolInterface (
673 &mPrivateData.Handle,
674 &gEfiFormBrowserExProtocolGuid,
675 EFI_NATIVE_INTERFACE,
676 &mPrivateData.FormBrowserEx
677 );
678 ASSERT_EFI_ERROR (Status);
679
680 return Status;
681 }
682
683
684 /**
685 Create a new string in HII Package List.
686
687 @param String The String to be added
688 @param HiiHandle The package list in the HII database to insert the
689 specified string.
690
691 @return The output string.
692
693 **/
694 EFI_STRING_ID
695 NewString (
696 IN CHAR16 *String,
697 IN EFI_HII_HANDLE HiiHandle
698 )
699 {
700 EFI_STRING_ID StringId;
701
702 StringId = HiiSetString (HiiHandle, 0, String, NULL);
703 ASSERT (StringId != 0);
704
705 return StringId;
706 }
707
708
709 /**
710 Delete a string from HII Package List.
711
712 @param StringId Id of the string in HII database.
713 @param HiiHandle The HII package list handle.
714
715 @retval EFI_SUCCESS The string was deleted successfully.
716
717 **/
718 EFI_STATUS
719 DeleteString (
720 IN EFI_STRING_ID StringId,
721 IN EFI_HII_HANDLE HiiHandle
722 )
723 {
724 CHAR16 NullChar;
725
726 NullChar = CHAR_NULL;
727 HiiSetString (HiiHandle, StringId, &NullChar, NULL);
728 return EFI_SUCCESS;
729 }
730
731
732 /**
733 Get the string based on the StringId and HII Package List Handle.
734
735 @param Token The String's ID.
736 @param HiiHandle The package list in the HII database to search for
737 the specified string.
738
739 @return The output string.
740
741 **/
742 CHAR16 *
743 GetToken (
744 IN EFI_STRING_ID Token,
745 IN EFI_HII_HANDLE HiiHandle
746 )
747 {
748 EFI_STRING String;
749
750 if (HiiHandle == NULL) {
751 return NULL;
752 }
753
754 String = HiiGetString (HiiHandle, Token, NULL);
755 if (String == NULL) {
756 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
757 ASSERT (String != NULL);
758 }
759 return (CHAR16 *) String;
760 }
761
762
763 /**
764 Allocate new memory and then copy the Unicode string Source to Destination.
765
766 @param Dest Location to copy string
767 @param Src String to copy
768
769 **/
770 VOID
771 NewStringCpy (
772 IN OUT CHAR16 **Dest,
773 IN CHAR16 *Src
774 )
775 {
776 if (*Dest != NULL) {
777 FreePool (*Dest);
778 }
779 *Dest = AllocateCopyPool (StrSize (Src), Src);
780 ASSERT (*Dest != NULL);
781 }
782
783
784 /**
785 Allocate new memory and concatinate Source on the end of Destination.
786
787 @param Dest String to added to the end of.
788 @param Src String to concatinate.
789
790 **/
791 VOID
792 NewStringCat (
793 IN OUT CHAR16 **Dest,
794 IN CHAR16 *Src
795 )
796 {
797 CHAR16 *NewString;
798 UINTN TmpSize;
799
800 if (*Dest == NULL) {
801 NewStringCpy (Dest, Src);
802 return;
803 }
804
805 TmpSize = StrSize (*Dest);
806 NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);
807 ASSERT (NewString != NULL);
808
809 StrCpy (NewString, *Dest);
810 StrCat (NewString, Src);
811
812 FreePool (*Dest);
813 *Dest = NewString;
814 }
815
816
817 /**
818 Synchronize or restore Storage's Edit copy and Shadow copy.
819
820 @param Storage The Storage to be synchronized.
821 @param SyncOrRestore Sync the buffer to editbuffer or Restore the
822 editbuffer to buffer
823 if TRUE, copy the editbuffer to the buffer.
824 if FALSE, copy the buffer to the editbuffer.
825
826 **/
827 VOID
828 SynchronizeStorage (
829 IN FORMSET_STORAGE *Storage,
830 IN BOOLEAN SyncOrRestore
831 )
832 {
833 LIST_ENTRY *Link;
834 NAME_VALUE_NODE *Node;
835
836 switch (Storage->Type) {
837 case EFI_HII_VARSTORE_BUFFER:
838 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
839 if (SyncOrRestore) {
840 CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);
841 } else {
842 CopyMem (Storage->EditBuffer, Storage->Buffer, Storage->Size);
843 }
844 break;
845
846 case EFI_HII_VARSTORE_NAME_VALUE:
847 Link = GetFirstNode (&Storage->NameValueListHead);
848 while (!IsNull (&Storage->NameValueListHead, Link)) {
849 Node = NAME_VALUE_NODE_FROM_LINK (Link);
850
851 if (SyncOrRestore) {
852 NewStringCpy (&Node->Value, Node->EditValue);
853 } else {
854 NewStringCpy (&Node->EditValue, Node->Value);
855 }
856
857 Link = GetNextNode (&Storage->NameValueListHead, Link);
858 }
859 break;
860
861 case EFI_HII_VARSTORE_EFI_VARIABLE:
862 default:
863 break;
864 }
865 }
866
867
868 /**
869 Get Value for given Name from a NameValue Storage.
870
871 @param Storage The NameValue Storage.
872 @param Name The Name.
873 @param Value The retured Value.
874 @param GetValueFrom Where to get source value, from EditValue or Value.
875
876 @retval EFI_SUCCESS Value found for given Name.
877 @retval EFI_NOT_FOUND No such Name found in NameValue storage.
878
879 **/
880 EFI_STATUS
881 GetValueByName (
882 IN FORMSET_STORAGE *Storage,
883 IN CHAR16 *Name,
884 IN OUT CHAR16 **Value,
885 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
886 )
887 {
888 LIST_ENTRY *Link;
889 NAME_VALUE_NODE *Node;
890
891 if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) {
892 return EFI_INVALID_PARAMETER;
893 }
894
895 *Value = NULL;
896
897 Link = GetFirstNode (&Storage->NameValueListHead);
898 while (!IsNull (&Storage->NameValueListHead, Link)) {
899 Node = NAME_VALUE_NODE_FROM_LINK (Link);
900
901 if (StrCmp (Name, Node->Name) == 0) {
902 if (GetValueFrom == GetSetValueWithEditBuffer) {
903 NewStringCpy (Value, Node->EditValue);
904 } else {
905 NewStringCpy (Value, Node->Value);
906 }
907 return EFI_SUCCESS;
908 }
909
910 Link = GetNextNode (&Storage->NameValueListHead, Link);
911 }
912
913 return EFI_NOT_FOUND;
914 }
915
916
917 /**
918 Set Value of given Name in a NameValue Storage.
919
920 @param Storage The NameValue Storage.
921 @param Name The Name.
922 @param Value The Value to set.
923 @param SetValueTo Whether update editValue or Value.
924
925 @retval EFI_SUCCESS Value found for given Name.
926 @retval EFI_NOT_FOUND No such Name found in NameValue storage.
927
928 **/
929 EFI_STATUS
930 SetValueByName (
931 IN FORMSET_STORAGE *Storage,
932 IN CHAR16 *Name,
933 IN CHAR16 *Value,
934 IN GET_SET_QUESTION_VALUE_WITH SetValueTo
935 )
936 {
937 LIST_ENTRY *Link;
938 NAME_VALUE_NODE *Node;
939 CHAR16 *Buffer;
940
941 if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) {
942 return EFI_INVALID_PARAMETER;
943 }
944
945 Link = GetFirstNode (&Storage->NameValueListHead);
946 while (!IsNull (&Storage->NameValueListHead, Link)) {
947 Node = NAME_VALUE_NODE_FROM_LINK (Link);
948
949 if (StrCmp (Name, Node->Name) == 0) {
950 if (SetValueTo == GetSetValueWithEditBuffer) {
951 Buffer = Node->EditValue;
952 } else {
953 Buffer = Node->Value;
954 }
955 if (Buffer != NULL) {
956 FreePool (Buffer);
957 }
958 Buffer = AllocateCopyPool (StrSize (Value), Value);
959 ASSERT (Buffer != NULL);
960 if (SetValueTo == GetSetValueWithEditBuffer) {
961 Node->EditValue = Buffer;
962 } else {
963 Node->Value = Buffer;
964 }
965 return EFI_SUCCESS;
966 }
967
968 Link = GetNextNode (&Storage->NameValueListHead, Link);
969 }
970
971 return EFI_NOT_FOUND;
972 }
973
974
975 /**
976 Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
977
978 @param Buffer The Storage to be conveted.
979 @param ConfigResp The returned <ConfigResp>.
980 @param SingleForm Whether update data for single form or formset level.
981
982 @retval EFI_SUCCESS Convert success.
983 @retval EFI_INVALID_PARAMETER Incorrect storage type.
984
985 **/
986 EFI_STATUS
987 StorageToConfigResp (
988 IN VOID *Buffer,
989 IN CHAR16 **ConfigResp,
990 IN BOOLEAN SingleForm
991 )
992 {
993 EFI_STATUS Status;
994 EFI_STRING Progress;
995 LIST_ENTRY *Link;
996 NAME_VALUE_NODE *Node;
997 CHAR16 *ConfigRequest;
998 FORMSET_STORAGE *Storage;
999 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
1000
1001 Status = EFI_SUCCESS;
1002 if (SingleForm) {
1003 ConfigInfo = (FORM_BROWSER_CONFIG_REQUEST *) Buffer;
1004 Storage = ConfigInfo->Storage;
1005 ConfigRequest = ConfigInfo->ConfigRequest;
1006 } else {
1007 Storage = (FORMSET_STORAGE *) Buffer;
1008 ConfigRequest = Storage->ConfigRequest;
1009 }
1010
1011 switch (Storage->Type) {
1012 case EFI_HII_VARSTORE_BUFFER:
1013 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
1014 Status = mHiiConfigRouting->BlockToConfig (
1015 mHiiConfigRouting,
1016 ConfigRequest,
1017 Storage->EditBuffer,
1018 Storage->Size,
1019 ConfigResp,
1020 &Progress
1021 );
1022 break;
1023
1024 case EFI_HII_VARSTORE_NAME_VALUE:
1025 *ConfigResp = NULL;
1026 NewStringCat (ConfigResp, Storage->ConfigHdr);
1027
1028 Link = GetFirstNode (&Storage->NameValueListHead);
1029 while (!IsNull (&Storage->NameValueListHead, Link)) {
1030 Node = NAME_VALUE_NODE_FROM_LINK (Link);
1031
1032 if (StrStr (ConfigRequest, Node->Name) != NULL) {
1033 NewStringCat (ConfigResp, L"&");
1034 NewStringCat (ConfigResp, Node->Name);
1035 NewStringCat (ConfigResp, L"=");
1036 NewStringCat (ConfigResp, Node->EditValue);
1037 }
1038 Link = GetNextNode (&Storage->NameValueListHead, Link);
1039 }
1040 break;
1041
1042 case EFI_HII_VARSTORE_EFI_VARIABLE:
1043 default:
1044 Status = EFI_INVALID_PARAMETER;
1045 break;
1046 }
1047
1048 return Status;
1049 }
1050
1051
1052 /**
1053 Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
1054
1055 @param Storage The Storage to receive the settings.
1056 @param ConfigResp The <ConfigResp> to be converted.
1057
1058 @retval EFI_SUCCESS Convert success.
1059 @retval EFI_INVALID_PARAMETER Incorrect storage type.
1060
1061 **/
1062 EFI_STATUS
1063 ConfigRespToStorage (
1064 IN FORMSET_STORAGE *Storage,
1065 IN CHAR16 *ConfigResp
1066 )
1067 {
1068 EFI_STATUS Status;
1069 EFI_STRING Progress;
1070 UINTN BufferSize;
1071 CHAR16 *StrPtr;
1072 CHAR16 *Name;
1073 CHAR16 *Value;
1074
1075 Status = EFI_SUCCESS;
1076
1077 switch (Storage->Type) {
1078 case EFI_HII_VARSTORE_BUFFER:
1079 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
1080 BufferSize = Storage->Size;
1081 Status = mHiiConfigRouting->ConfigToBlock (
1082 mHiiConfigRouting,
1083 ConfigResp,
1084 Storage->EditBuffer,
1085 &BufferSize,
1086 &Progress
1087 );
1088 break;
1089
1090 case EFI_HII_VARSTORE_NAME_VALUE:
1091 StrPtr = StrStr (ConfigResp, L"PATH");
1092 if (StrPtr == NULL) {
1093 break;
1094 }
1095 StrPtr = StrStr (ConfigResp, L"&");
1096 while (StrPtr != NULL) {
1097 //
1098 // Skip '&'
1099 //
1100 StrPtr = StrPtr + 1;
1101 Name = StrPtr;
1102 StrPtr = StrStr (StrPtr, L"=");
1103 if (StrPtr == NULL) {
1104 break;
1105 }
1106 *StrPtr = 0;
1107
1108 //
1109 // Skip '='
1110 //
1111 StrPtr = StrPtr + 1;
1112 Value = StrPtr;
1113 StrPtr = StrStr (StrPtr, L"&");
1114 if (StrPtr != NULL) {
1115 *StrPtr = 0;
1116 }
1117 SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer);
1118 }
1119 break;
1120
1121 case EFI_HII_VARSTORE_EFI_VARIABLE:
1122 default:
1123 Status = EFI_INVALID_PARAMETER;
1124 break;
1125 }
1126
1127 return Status;
1128 }
1129
1130
1131 /**
1132 Get Question's current Value.
1133
1134 @param FormSet FormSet data structure.
1135 @param Form Form data structure.
1136 @param Question Question to be initialized.
1137 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver.
1138
1139 @retval EFI_SUCCESS The function completed successfully.
1140
1141 **/
1142 EFI_STATUS
1143 GetQuestionValue (
1144 IN FORM_BROWSER_FORMSET *FormSet,
1145 IN FORM_BROWSER_FORM *Form,
1146 IN OUT FORM_BROWSER_STATEMENT *Question,
1147 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom
1148 )
1149 {
1150 EFI_STATUS Status;
1151 BOOLEAN Enabled;
1152 BOOLEAN Pending;
1153 UINT8 *Dst;
1154 UINTN StorageWidth;
1155 EFI_TIME EfiTime;
1156 FORMSET_STORAGE *Storage;
1157 EFI_IFR_TYPE_VALUE *QuestionValue;
1158 CHAR16 *ConfigRequest;
1159 CHAR16 *Progress;
1160 CHAR16 *Result;
1161 CHAR16 *Value;
1162 CHAR16 *StringPtr;
1163 UINTN Length;
1164 UINTN Index;
1165 UINTN LengthStr;
1166 BOOLEAN IsBufferStorage;
1167 BOOLEAN IsString;
1168 CHAR16 TemStr[5];
1169 UINT8 DigitUint8;
1170 UINT8 *TemBuffer;
1171
1172 Status = EFI_SUCCESS;
1173 Value = NULL;
1174 Result = NULL;
1175
1176 if (GetValueFrom >= GetSetValueWithMax) {
1177 return EFI_INVALID_PARAMETER;
1178 }
1179
1180 //
1181 // Statement don't have storage, skip them
1182 //
1183 if (Question->QuestionId == 0) {
1184 return Status;
1185 }
1186
1187 //
1188 // Question value is provided by an Expression, evaluate it
1189 //
1190 if (Question->ValueExpression != NULL) {
1191 Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
1192 if (!EFI_ERROR (Status)) {
1193 if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
1194 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
1195 if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) {
1196 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen);
1197 Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen;
1198 } else {
1199 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth);
1200 Question->HiiValue.BufferLen = Question->StorageWidth;
1201 }
1202 FreePool (Question->ValueExpression->Result.Buffer);
1203 }
1204 Question->HiiValue.Type = Question->ValueExpression->Result.Type;
1205 CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
1206 }
1207 return Status;
1208 }
1209
1210 //
1211 // Get question value by read expression.
1212 //
1213 if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1214 Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
1215 if (!EFI_ERROR (Status) &&
1216 ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) {
1217 //
1218 // Only update question value to the valid result.
1219 //
1220 if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
1221 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL);
1222 if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) {
1223 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen);
1224 Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen;
1225 } else {
1226 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth);
1227 Question->HiiValue.BufferLen = Question->StorageWidth;
1228 }
1229 FreePool (Question->ReadExpression->Result.Buffer);
1230 }
1231 Question->HiiValue.Type = Question->ReadExpression->Result.Type;
1232 CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
1233 return EFI_SUCCESS;
1234 }
1235 }
1236
1237 //
1238 // Question value is provided by RTC
1239 //
1240 Storage = Question->Storage;
1241 QuestionValue = &Question->HiiValue.Value;
1242 if (Storage == NULL) {
1243 //
1244 // It's a Question without storage, or RTC date/time
1245 //
1246 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1247 //
1248 // Date and time define the same Flags bit
1249 //
1250 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1251 case QF_DATE_STORAGE_TIME:
1252 Status = gRT->GetTime (&EfiTime, NULL);
1253 break;
1254
1255 case QF_DATE_STORAGE_WAKEUP:
1256 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1257 break;
1258
1259 case QF_DATE_STORAGE_NORMAL:
1260 default:
1261 //
1262 // For date/time without storage
1263 //
1264 return EFI_SUCCESS;
1265 }
1266
1267 if (EFI_ERROR (Status)) {
1268 return Status;
1269 }
1270
1271 if (Question->Operand == EFI_IFR_DATE_OP) {
1272 QuestionValue->date.Year = EfiTime.Year;
1273 QuestionValue->date.Month = EfiTime.Month;
1274 QuestionValue->date.Day = EfiTime.Day;
1275 } else {
1276 QuestionValue->time.Hour = EfiTime.Hour;
1277 QuestionValue->time.Minute = EfiTime.Minute;
1278 QuestionValue->time.Second = EfiTime.Second;
1279 }
1280 }
1281
1282 return EFI_SUCCESS;
1283 }
1284
1285 //
1286 // Question value is provided by EFI variable
1287 //
1288 StorageWidth = Question->StorageWidth;
1289 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1290 if (Question->BufferValue != NULL) {
1291 Dst = Question->BufferValue;
1292 } else {
1293 Dst = (UINT8 *) QuestionValue;
1294 }
1295
1296 Status = gRT->GetVariable (
1297 Question->VariableName,
1298 &Storage->Guid,
1299 NULL,
1300 &StorageWidth,
1301 Dst
1302 );
1303 //
1304 // Always return success, even this EFI variable doesn't exist
1305 //
1306 return EFI_SUCCESS;
1307 }
1308
1309 //
1310 // Question Value is provided by Buffer Storage or NameValue Storage
1311 //
1312 if (Question->BufferValue != NULL) {
1313 //
1314 // This Question is password or orderedlist
1315 //
1316 Dst = Question->BufferValue;
1317 } else {
1318 //
1319 // Other type of Questions
1320 //
1321 Dst = (UINT8 *) &Question->HiiValue.Value;
1322 }
1323
1324 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1325 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1326 IsBufferStorage = TRUE;
1327 } else {
1328 IsBufferStorage = FALSE;
1329 }
1330 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1331 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) {
1332 if (IsBufferStorage) {
1333 if (GetValueFrom == GetSetValueWithEditBuffer) {
1334 //
1335 // Copy from storage Edit buffer
1336 //
1337 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1338 } else {
1339 //
1340 // Copy from storage Edit buffer
1341 //
1342 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1343 }
1344 } else {
1345 Value = NULL;
1346 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom);
1347 if (EFI_ERROR (Status)) {
1348 return Status;
1349 }
1350
1351 ASSERT (Value != NULL);
1352 LengthStr = StrLen (Value);
1353 Status = EFI_SUCCESS;
1354 if (IsString) {
1355 //
1356 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1357 // Add string tail char L'\0' into Length
1358 //
1359 Length = StorageWidth + sizeof (CHAR16);
1360 if (Length < ((LengthStr / 4 + 1) * 2)) {
1361 Status = EFI_BUFFER_TOO_SMALL;
1362 } else {
1363 StringPtr = (CHAR16 *) Dst;
1364 ZeroMem (TemStr, sizeof (TemStr));
1365 for (Index = 0; Index < LengthStr; Index += 4) {
1366 StrnCpy (TemStr, Value + Index, 4);
1367 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1368 }
1369 //
1370 // Add tailing L'\0' character
1371 //
1372 StringPtr[Index/4] = L'\0';
1373 }
1374 } else {
1375 if (StorageWidth < ((LengthStr + 1) / 2)) {
1376 Status = EFI_BUFFER_TOO_SMALL;
1377 } else {
1378 ZeroMem (TemStr, sizeof (TemStr));
1379 for (Index = 0; Index < LengthStr; Index ++) {
1380 TemStr[0] = Value[LengthStr - Index - 1];
1381 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1382 if ((Index & 1) == 0) {
1383 Dst [Index/2] = DigitUint8;
1384 } else {
1385 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1386 }
1387 }
1388 }
1389 }
1390
1391 FreePool (Value);
1392 }
1393 } else {
1394 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
1395 //
1396 // Request current settings from Configuration Driver
1397 //
1398 if (FormSet->ConfigAccess == NULL) {
1399 return EFI_NOT_FOUND;
1400 }
1401
1402 //
1403 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
1404 // <ConfigHdr> + "&" + <VariableName>
1405 //
1406 if (IsBufferStorage) {
1407 Length = StrLen (Storage->ConfigHdr);
1408 Length += StrLen (Question->BlockName);
1409 } else {
1410 Length = StrLen (Storage->ConfigHdr);
1411 Length += StrLen (Question->VariableName) + 1;
1412 }
1413 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
1414 ASSERT (ConfigRequest != NULL);
1415
1416 StrCpy (ConfigRequest, Storage->ConfigHdr);
1417 if (IsBufferStorage) {
1418 StrCat (ConfigRequest, Question->BlockName);
1419 } else {
1420 StrCat (ConfigRequest, L"&");
1421 StrCat (ConfigRequest, Question->VariableName);
1422 }
1423
1424 Status = FormSet->ConfigAccess->ExtractConfig (
1425 FormSet->ConfigAccess,
1426 ConfigRequest,
1427 &Progress,
1428 &Result
1429 );
1430 FreePool (ConfigRequest);
1431 if (EFI_ERROR (Status)) {
1432 return Status;
1433 }
1434
1435 //
1436 // Skip <ConfigRequest>
1437 //
1438 if (IsBufferStorage) {
1439 Value = StrStr (Result, L"&VALUE");
1440 if (Value == NULL) {
1441 FreePool (Result);
1442 return EFI_NOT_FOUND;
1443 }
1444 //
1445 // Skip "&VALUE"
1446 //
1447 Value = Value + 6;
1448 } else {
1449 Value = Result + Length;
1450 }
1451 if (*Value != '=') {
1452 FreePool (Result);
1453 return EFI_NOT_FOUND;
1454 }
1455 //
1456 // Skip '=', point to value
1457 //
1458 Value = Value + 1;
1459
1460 //
1461 // Suppress <AltResp> if any
1462 //
1463 StringPtr = Value;
1464 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1465 StringPtr++;
1466 }
1467 *StringPtr = L'\0';
1468
1469 LengthStr = StrLen (Value);
1470 Status = EFI_SUCCESS;
1471 if (!IsBufferStorage && IsString) {
1472 //
1473 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1474 // Add string tail char L'\0' into Length
1475 //
1476 Length = StorageWidth + sizeof (CHAR16);
1477 if (Length < ((LengthStr / 4 + 1) * 2)) {
1478 Status = EFI_BUFFER_TOO_SMALL;
1479 } else {
1480 StringPtr = (CHAR16 *) Dst;
1481 ZeroMem (TemStr, sizeof (TemStr));
1482 for (Index = 0; Index < LengthStr; Index += 4) {
1483 StrnCpy (TemStr, Value + Index, 4);
1484 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1485 }
1486 //
1487 // Add tailing L'\0' character
1488 //
1489 StringPtr[Index/4] = L'\0';
1490 }
1491 } else {
1492 if (StorageWidth < ((LengthStr + 1) / 2)) {
1493 Status = EFI_BUFFER_TOO_SMALL;
1494 } else {
1495 ZeroMem (TemStr, sizeof (TemStr));
1496 for (Index = 0; Index < LengthStr; Index ++) {
1497 TemStr[0] = Value[LengthStr - Index - 1];
1498 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1499 if ((Index & 1) == 0) {
1500 Dst [Index/2] = DigitUint8;
1501 } else {
1502 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1503 }
1504 }
1505 }
1506 }
1507
1508 if (EFI_ERROR (Status)) {
1509 FreePool (Result);
1510 return Status;
1511 }
1512 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1513 TemBuffer = NULL;
1514 TemBuffer = AllocateZeroPool (Storage->Size);
1515 if (TemBuffer == NULL) {
1516 Status = EFI_OUT_OF_RESOURCES;
1517 return Status;
1518 }
1519 Length = Storage->Size;
1520 Status = gRT->GetVariable (
1521 Storage->Name,
1522 &Storage->Guid,
1523 NULL,
1524 &Length,
1525 TemBuffer
1526 );
1527 if (EFI_ERROR (Status)) {
1528 FreePool (TemBuffer);
1529 return Status;
1530 }
1531
1532 CopyMem (Dst, TemBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
1533
1534 FreePool (TemBuffer);
1535 }
1536
1537 //
1538 // Synchronize Edit Buffer
1539 //
1540 if (IsBufferStorage) {
1541 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
1542 } else {
1543 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer);
1544 }
1545
1546 if (Result != NULL) {
1547 FreePool (Result);
1548 }
1549 }
1550
1551 return Status;
1552 }
1553
1554
1555 /**
1556 Save Question Value to edit copy(cached) or Storage(uncached).
1557
1558 @param FormSet FormSet data structure.
1559 @param Form Form data structure.
1560 @param Question Pointer to the Question.
1561 @param SetValueTo Update the question value to editbuffer , buffer or hii driver.
1562
1563 @retval EFI_SUCCESS The function completed successfully.
1564
1565 **/
1566 EFI_STATUS
1567 SetQuestionValue (
1568 IN FORM_BROWSER_FORMSET *FormSet,
1569 IN FORM_BROWSER_FORM *Form,
1570 IN OUT FORM_BROWSER_STATEMENT *Question,
1571 IN GET_SET_QUESTION_VALUE_WITH SetValueTo
1572 )
1573 {
1574 EFI_STATUS Status;
1575 BOOLEAN Enabled;
1576 BOOLEAN Pending;
1577 UINT8 *Src;
1578 EFI_TIME EfiTime;
1579 UINTN BufferLen;
1580 UINTN StorageWidth;
1581 FORMSET_STORAGE *Storage;
1582 EFI_IFR_TYPE_VALUE *QuestionValue;
1583 CHAR16 *ConfigResp;
1584 CHAR16 *Progress;
1585 CHAR16 *Value;
1586 UINTN Length;
1587 BOOLEAN IsBufferStorage;
1588 BOOLEAN IsString;
1589 UINT8 *TemBuffer;
1590 CHAR16 *TemName;
1591 CHAR16 *TemString;
1592 UINTN Index;
1593
1594 Status = EFI_SUCCESS;
1595
1596 if (SetValueTo >= GetSetValueWithMax) {
1597 return EFI_INVALID_PARAMETER;
1598 }
1599
1600 //
1601 // Statement don't have storage, skip them
1602 //
1603 if (Question->QuestionId == 0) {
1604 return Status;
1605 }
1606
1607 //
1608 // If Question value is provided by an Expression, then it is read only
1609 //
1610 if (Question->ValueExpression != NULL) {
1611 return Status;
1612 }
1613
1614 //
1615 // Before set question value, evaluate its write expression.
1616 //
1617 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
1618 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
1619 if (EFI_ERROR (Status)) {
1620 return Status;
1621 }
1622 }
1623
1624 //
1625 // Question value is provided by RTC
1626 //
1627 Storage = Question->Storage;
1628 QuestionValue = &Question->HiiValue.Value;
1629 if (Storage == NULL) {
1630 //
1631 // It's a Question without storage, or RTC date/time
1632 //
1633 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1634 //
1635 // Date and time define the same Flags bit
1636 //
1637 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1638 case QF_DATE_STORAGE_TIME:
1639 Status = gRT->GetTime (&EfiTime, NULL);
1640 break;
1641
1642 case QF_DATE_STORAGE_WAKEUP:
1643 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1644 break;
1645
1646 case QF_DATE_STORAGE_NORMAL:
1647 default:
1648 //
1649 // For date/time without storage
1650 //
1651 return EFI_SUCCESS;
1652 }
1653
1654 if (EFI_ERROR (Status)) {
1655 return Status;
1656 }
1657
1658 if (Question->Operand == EFI_IFR_DATE_OP) {
1659 EfiTime.Year = QuestionValue->date.Year;
1660 EfiTime.Month = QuestionValue->date.Month;
1661 EfiTime.Day = QuestionValue->date.Day;
1662 } else {
1663 EfiTime.Hour = QuestionValue->time.Hour;
1664 EfiTime.Minute = QuestionValue->time.Minute;
1665 EfiTime.Second = QuestionValue->time.Second;
1666 }
1667
1668 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
1669 Status = gRT->SetTime (&EfiTime);
1670 } else {
1671 Status = gRT->SetWakeupTime (TRUE, &EfiTime);
1672 }
1673 }
1674
1675 return Status;
1676 }
1677
1678 //
1679 // Question value is provided by EFI variable
1680 //
1681 StorageWidth = Question->StorageWidth;
1682 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1683 if (Question->BufferValue != NULL) {
1684 Src = Question->BufferValue;
1685 } else {
1686 Src = (UINT8 *) QuestionValue;
1687 }
1688
1689 Status = gRT->SetVariable (
1690 Question->VariableName,
1691 &Storage->Guid,
1692 Storage->Attributes,
1693 StorageWidth,
1694 Src
1695 );
1696 return Status;
1697 }
1698
1699 //
1700 // Question Value is provided by Buffer Storage or NameValue Storage
1701 //
1702 if (Question->BufferValue != NULL) {
1703 Src = Question->BufferValue;
1704 } else {
1705 Src = (UINT8 *) &Question->HiiValue.Value;
1706 }
1707
1708 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
1709 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1710 IsBufferStorage = TRUE;
1711 } else {
1712 IsBufferStorage = FALSE;
1713 }
1714 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1715
1716 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) {
1717 if (IsBufferStorage) {
1718 if (SetValueTo == GetSetValueWithEditBuffer) {
1719 //
1720 // Copy to storage edit buffer
1721 //
1722 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1723 } else if (SetValueTo == GetSetValueWithBuffer) {
1724 //
1725 // Copy to storage edit buffer
1726 //
1727 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1728 }
1729 } else {
1730 if (IsString) {
1731 //
1732 // Allocate enough string buffer.
1733 //
1734 Value = NULL;
1735 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
1736 Value = AllocateZeroPool (BufferLen);
1737 ASSERT (Value != NULL);
1738 //
1739 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1740 //
1741 TemName = (CHAR16 *) Src;
1742 TemString = Value;
1743 for (; *TemName != L'\0'; TemName++) {
1744 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1745 }
1746 } else {
1747 BufferLen = StorageWidth * 2 + 1;
1748 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
1749 ASSERT (Value != NULL);
1750 //
1751 // Convert Buffer to Hex String
1752 //
1753 TemBuffer = Src + StorageWidth - 1;
1754 TemString = Value;
1755 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1756 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1757 }
1758 }
1759
1760 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo);
1761 FreePool (Value);
1762 }
1763 } else if (SetValueTo == GetSetValueWithHiiDriver) {
1764 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
1765 //
1766 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
1767 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
1768 //
1769 if (IsBufferStorage) {
1770 Length = StrLen (Question->BlockName) + 7;
1771 } else {
1772 Length = StrLen (Question->VariableName) + 2;
1773 }
1774 if (!IsBufferStorage && IsString) {
1775 Length += (StrLen ((CHAR16 *) Src) * 4);
1776 } else {
1777 Length += (StorageWidth * 2);
1778 }
1779 ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
1780 ASSERT (ConfigResp != NULL);
1781
1782 StrCpy (ConfigResp, Storage->ConfigHdr);
1783 if (IsBufferStorage) {
1784 StrCat (ConfigResp, Question->BlockName);
1785 StrCat (ConfigResp, L"&VALUE=");
1786 } else {
1787 StrCat (ConfigResp, L"&");
1788 StrCat (ConfigResp, Question->VariableName);
1789 StrCat (ConfigResp, L"=");
1790 }
1791
1792 Value = ConfigResp + StrLen (ConfigResp);
1793
1794 if (!IsBufferStorage && IsString) {
1795 //
1796 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1797 //
1798 TemName = (CHAR16 *) Src;
1799 TemString = Value;
1800 for (; *TemName != L'\0'; TemName++) {
1801 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1802 }
1803 } else {
1804 //
1805 // Convert Buffer to Hex String
1806 //
1807 TemBuffer = Src + StorageWidth - 1;
1808 TemString = Value;
1809 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1810 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1811 }
1812 }
1813
1814 //
1815 // Convert to lower char.
1816 //
1817 for (TemString = Value; *Value != L'\0'; Value++) {
1818 if (*Value >= L'A' && *Value <= L'Z') {
1819 *Value = (CHAR16) (*Value - L'A' + L'a');
1820 }
1821 }
1822
1823 //
1824 // Submit Question Value to Configuration Driver
1825 //
1826 if (FormSet->ConfigAccess != NULL) {
1827 Status = FormSet->ConfigAccess->RouteConfig (
1828 FormSet->ConfigAccess,
1829 ConfigResp,
1830 &Progress
1831 );
1832 if (EFI_ERROR (Status)) {
1833 FreePool (ConfigResp);
1834 return Status;
1835 }
1836 }
1837 FreePool (ConfigResp);
1838
1839 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
1840 TemBuffer = NULL;
1841 TemBuffer = AllocateZeroPool(Storage->Size);
1842 if (TemBuffer == NULL) {
1843 Status = EFI_OUT_OF_RESOURCES;
1844 return Status;
1845 }
1846 Length = Storage->Size;
1847 Status = gRT->GetVariable (
1848 Storage->Name,
1849 &Storage->Guid,
1850 NULL,
1851 &Length,
1852 TemBuffer
1853 );
1854
1855 CopyMem (TemBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1856
1857 Status = gRT->SetVariable (
1858 Storage->Name,
1859 &Storage->Guid,
1860 Storage->Attributes,
1861 Storage->Size,
1862 TemBuffer
1863 );
1864 FreePool (TemBuffer);
1865 if (EFI_ERROR (Status)){
1866 return Status;
1867 }
1868 }
1869 //
1870 // Sync storage, from editbuffer to buffer.
1871 //
1872 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1873 }
1874
1875 return Status;
1876 }
1877
1878
1879 /**
1880 Perform inconsistent check for a Form.
1881
1882 @param FormSet FormSet data structure.
1883 @param Form Form data structure.
1884 @param Question The Question to be validated.
1885 @param Type Validation type: InConsistent or NoSubmit
1886
1887 @retval EFI_SUCCESS Form validation pass.
1888 @retval other Form validation failed.
1889
1890 **/
1891 EFI_STATUS
1892 ValidateQuestion (
1893 IN FORM_BROWSER_FORMSET *FormSet,
1894 IN FORM_BROWSER_FORM *Form,
1895 IN FORM_BROWSER_STATEMENT *Question,
1896 IN UINTN Type
1897 )
1898 {
1899 EFI_STATUS Status;
1900 LIST_ENTRY *Link;
1901 LIST_ENTRY *ListHead;
1902 EFI_STRING PopUp;
1903 EFI_INPUT_KEY Key;
1904 FORM_EXPRESSION *Expression;
1905
1906 if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {
1907 ListHead = &Question->InconsistentListHead;
1908 } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
1909 ListHead = &Question->NoSubmitListHead;
1910 } else {
1911 return EFI_UNSUPPORTED;
1912 }
1913
1914 Link = GetFirstNode (ListHead);
1915 while (!IsNull (ListHead, Link)) {
1916 Expression = FORM_EXPRESSION_FROM_LINK (Link);
1917
1918 //
1919 // Evaluate the expression
1920 //
1921 Status = EvaluateExpression (FormSet, Form, Expression);
1922 if (EFI_ERROR (Status)) {
1923 return Status;
1924 }
1925
1926 if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {
1927 //
1928 // Condition meet, show up error message
1929 //
1930 if (Expression->Error != 0) {
1931 PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
1932 do {
1933 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);
1934 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1935 FreePool (PopUp);
1936 }
1937
1938 return EFI_NOT_READY;
1939 }
1940
1941 Link = GetNextNode (ListHead, Link);
1942 }
1943
1944 return EFI_SUCCESS;
1945 }
1946
1947
1948 /**
1949 Perform NoSubmit check for each Form in FormSet.
1950
1951 @param FormSet FormSet data structure.
1952 @param CurrentForm Current input form data structure.
1953
1954 @retval EFI_SUCCESS Form validation pass.
1955 @retval other Form validation failed.
1956
1957 **/
1958 EFI_STATUS
1959 NoSubmitCheck (
1960 IN FORM_BROWSER_FORMSET *FormSet,
1961 IN FORM_BROWSER_FORM *CurrentForm
1962 )
1963 {
1964 EFI_STATUS Status;
1965 LIST_ENTRY *Link;
1966 FORM_BROWSER_STATEMENT *Question;
1967 FORM_BROWSER_FORM *Form;
1968 LIST_ENTRY *LinkForm;
1969
1970 LinkForm = GetFirstNode (&FormSet->FormListHead);
1971 while (!IsNull (&FormSet->FormListHead, LinkForm)) {
1972 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm);
1973 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm);
1974
1975 if (CurrentForm != NULL && CurrentForm != Form) {
1976 continue;
1977 }
1978
1979 Link = GetFirstNode (&Form->StatementListHead);
1980 while (!IsNull (&Form->StatementListHead, Link)) {
1981 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1982
1983 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
1984 if (EFI_ERROR (Status)) {
1985 return Status;
1986 }
1987
1988 Link = GetNextNode (&Form->StatementListHead, Link);
1989 }
1990 }
1991
1992 return EFI_SUCCESS;
1993 }
1994
1995 /**
1996 Fill storage's edit copy with settings requested from Configuration Driver.
1997
1998 @param FormSet FormSet data structure.
1999 @param ConfigInfo The config info related to this form.
2000 @param SyncOrRestore Sync the buffer to editbuffer or Restore the
2001 editbuffer to buffer
2002 if TRUE, copy the editbuffer to the buffer.
2003 if FALSE, copy the buffer to the editbuffer.
2004
2005 @retval EFI_SUCCESS The function completed successfully.
2006
2007 **/
2008 EFI_STATUS
2009 SynchronizeStorageForForm (
2010 IN FORM_BROWSER_FORMSET *FormSet,
2011 IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo,
2012 IN BOOLEAN SyncOrRestore
2013 )
2014 {
2015 EFI_STATUS Status;
2016 EFI_STRING Progress;
2017 EFI_STRING Result;
2018 UINTN BufferSize;
2019 LIST_ENTRY *Link;
2020 NAME_VALUE_NODE *Node;
2021 UINT8 *Src;
2022 UINT8 *Dst;
2023
2024 Status = EFI_SUCCESS;
2025 Result = NULL;
2026 if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) {
2027 return EFI_NOT_FOUND;
2028 }
2029
2030 if (ConfigInfo->ElementCount == 0) {
2031 //
2032 // Skip if there is no RequestElement
2033 //
2034 return EFI_SUCCESS;
2035 }
2036
2037 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2038 (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2039 BufferSize = ConfigInfo->Storage->Size;
2040
2041 if (SyncOrRestore) {
2042 Src = ConfigInfo->Storage->EditBuffer;
2043 Dst = ConfigInfo->Storage->Buffer;
2044 } else {
2045 Src = ConfigInfo->Storage->Buffer;
2046 Dst = ConfigInfo->Storage->EditBuffer;
2047 }
2048
2049 Status = mHiiConfigRouting->BlockToConfig(
2050 mHiiConfigRouting,
2051 ConfigInfo->ConfigRequest,
2052 Src,
2053 BufferSize,
2054 &Result,
2055 &Progress
2056 );
2057 if (EFI_ERROR (Status)) {
2058 return Status;
2059 }
2060
2061 Status = mHiiConfigRouting->ConfigToBlock (
2062 mHiiConfigRouting,
2063 Result,
2064 Dst,
2065 &BufferSize,
2066 &Progress
2067 );
2068 if (Result != NULL) {
2069 FreePool (Result);
2070 }
2071 } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2072 Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead);
2073 while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) {
2074 Node = NAME_VALUE_NODE_FROM_LINK (Link);
2075
2076 if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) {
2077 if (SyncOrRestore) {
2078 NewStringCpy (&Node->Value, Node->EditValue);
2079 } else {
2080 NewStringCpy (&Node->EditValue, Node->Value);
2081 }
2082 }
2083
2084 Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link);
2085 }
2086 }
2087
2088 return Status;
2089 }
2090
2091 /**
2092 When discard the question value, call the callback function with Changed type
2093 to inform the hii driver.
2094
2095 @param FormSet FormSet data structure.
2096 @param Form Form data structure.
2097
2098 **/
2099 VOID
2100 SendDiscardInfoToDriver (
2101 IN FORM_BROWSER_FORMSET *FormSet,
2102 IN FORM_BROWSER_FORM *Form
2103 )
2104 {
2105 LIST_ENTRY *Link;
2106 FORM_BROWSER_STATEMENT *Question;
2107 EFI_STATUS Status;
2108 EFI_HII_VALUE HiiValue;
2109 UINT8 *BufferValue;
2110 BOOLEAN ValueChanged;
2111 EFI_IFR_TYPE_VALUE *TypeValue;
2112 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2113
2114 ValueChanged = FALSE;
2115 BufferValue = NULL;
2116
2117 if(!Form->NvUpdateRequired) {
2118 return;
2119 }
2120
2121 Link = GetFirstNode (&Form->StatementListHead);
2122 while (!IsNull (&Form->StatementListHead, Link)) {
2123 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2124 Link = GetNextNode (&Form->StatementListHead, Link);
2125
2126 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2127 continue;
2128 }
2129
2130 if (Question->Operand == EFI_IFR_PASSWORD_OP) {
2131 continue;
2132 }
2133
2134 if (Question->BufferValue != NULL) {
2135 BufferValue = AllocateZeroPool (Question->StorageWidth);
2136 ASSERT (BufferValue != NULL);
2137 CopyMem (BufferValue, Question->BufferValue, Question->StorageWidth);
2138 } else {
2139 HiiValue.Type = Question->HiiValue.Type;
2140 CopyMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE));
2141 }
2142
2143 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);
2144 if (EFI_ERROR (Status)) {
2145 if (BufferValue != NULL) {
2146 FreePool (BufferValue);
2147 BufferValue = NULL;
2148 }
2149 continue;
2150 }
2151
2152 if (Question->BufferValue != NULL) {
2153 if (CompareMem (BufferValue, Question->BufferValue, Question->StorageWidth)) {
2154 ValueChanged = TRUE;
2155 }
2156 } else {
2157 if (CompareMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE))) {
2158 ValueChanged = TRUE;
2159 }
2160 }
2161
2162 if (BufferValue != NULL) {
2163 FreePool (BufferValue);
2164 BufferValue = NULL;
2165 }
2166
2167 if (!ValueChanged) {
2168 continue;
2169 }
2170
2171 ValueChanged = FALSE;
2172
2173 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
2174 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;
2175 } else {
2176 TypeValue = &Question->HiiValue.Value;
2177 }
2178
2179 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2180 FormSet->ConfigAccess->Callback (
2181 FormSet->ConfigAccess,
2182 EFI_BROWSER_ACTION_CHANGED,
2183 Question->QuestionId,
2184 Question->HiiValue.Type,
2185 TypeValue,
2186 &ActionRequest
2187 );
2188 }
2189 }
2190
2191 /**
2192 Validate the FormSet. If the formset is not validate, remove it from the list.
2193
2194 @param FormSet The input FormSet which need to validate.
2195
2196 @retval TRUE The handle is validate.
2197 @retval FALSE The handle is invalidate.
2198
2199 **/
2200 BOOLEAN
2201 ValidateFormSet (
2202 FORM_BROWSER_FORMSET *FormSet
2203 )
2204 {
2205 EFI_HII_HANDLE *HiiHandles;
2206 UINTN Index;
2207 BOOLEAN Find;
2208
2209 ASSERT (FormSet != NULL);
2210 Find = FALSE;
2211 //
2212 // Get all the Hii handles
2213 //
2214 HiiHandles = HiiGetHiiHandles (NULL);
2215 ASSERT (HiiHandles != NULL);
2216
2217 //
2218 // Search for formset of each class type
2219 //
2220 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
2221 if (HiiHandles[Index] == FormSet->HiiHandle) {
2222 Find = TRUE;
2223 break;
2224 }
2225 }
2226
2227 if (!Find) {
2228 RemoveEntryList (&FormSet->Link);
2229 DestroyFormSet (FormSet);
2230 }
2231
2232 FreePool (HiiHandles);
2233
2234 return Find;
2235 }
2236
2237 /**
2238 Discard data based on the input setting scope (Form, FormSet or System).
2239
2240 @param FormSet FormSet data structure.
2241 @param Form Form data structure.
2242 @param SettingScope Setting Scope for Discard action.
2243
2244 @retval EFI_SUCCESS The function completed successfully.
2245 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2246
2247 **/
2248 EFI_STATUS
2249 DiscardForm (
2250 IN FORM_BROWSER_FORMSET *FormSet,
2251 IN FORM_BROWSER_FORM *Form,
2252 IN BROWSER_SETTING_SCOPE SettingScope
2253 )
2254 {
2255 LIST_ENTRY *Link;
2256 FORMSET_STORAGE *Storage;
2257 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2258 FORM_BROWSER_FORMSET *LocalFormSet;
2259
2260 //
2261 // Check the supported setting level.
2262 //
2263 if (SettingScope >= MaxLevel) {
2264 return EFI_UNSUPPORTED;
2265 }
2266
2267 if (SettingScope == FormLevel && Form->NvUpdateRequired) {
2268 ConfigInfo = NULL;
2269 Link = GetFirstNode (&Form->ConfigRequestHead);
2270 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2271 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2272 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2273
2274 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2275 continue;
2276 }
2277
2278 //
2279 // Skip if there is no RequestElement
2280 //
2281 if (ConfigInfo->ElementCount == 0) {
2282 continue;
2283 }
2284
2285 //
2286 // Prepare <ConfigResp>
2287 //
2288 SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE);
2289
2290 //
2291 // Call callback with Changed type to inform the driver.
2292 //
2293 SendDiscardInfoToDriver (FormSet, Form);
2294 }
2295
2296 Form->NvUpdateRequired = FALSE;
2297 } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
2298
2299 //
2300 // Discard Buffer storage or Name/Value storage
2301 //
2302 Link = GetFirstNode (&FormSet->StorageListHead);
2303 while (!IsNull (&FormSet->StorageListHead, Link)) {
2304 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2305 Link = GetNextNode (&FormSet->StorageListHead, Link);
2306
2307 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2308 continue;
2309 }
2310
2311 //
2312 // Skip if there is no RequestElement
2313 //
2314 if (Storage->ElementCount == 0) {
2315 continue;
2316 }
2317
2318 SynchronizeStorage(Storage, FALSE);
2319 }
2320
2321 Link = GetFirstNode (&FormSet->FormListHead);
2322 while (!IsNull (&FormSet->FormListHead, Link)) {
2323 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2324 Link = GetNextNode (&FormSet->FormListHead, Link);
2325
2326 //
2327 // Call callback with Changed type to inform the driver.
2328 //
2329 SendDiscardInfoToDriver (FormSet, Form);
2330 }
2331
2332 UpdateNvInfoInForm (FormSet, FALSE);
2333 } else if (SettingScope == SystemLevel) {
2334 //
2335 // System Level Discard.
2336 //
2337
2338 //
2339 // Discard changed value for each FormSet in the maintain list.
2340 //
2341 Link = GetFirstNode (&gBrowserFormSetList);
2342 while (!IsNull (&gBrowserFormSetList, Link)) {
2343 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2344 Link = GetNextNode (&gBrowserFormSetList, Link);
2345 if (!ValidateFormSet(LocalFormSet)) {
2346 continue;
2347 }
2348 DiscardForm (LocalFormSet, NULL, FormSetLevel);
2349 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2350 //
2351 // Remove maintain backup list after discard except for the current using FormSet.
2352 //
2353 RemoveEntryList (&LocalFormSet->Link);
2354 DestroyFormSet (LocalFormSet);
2355 }
2356 }
2357 }
2358
2359 return EFI_SUCCESS;
2360 }
2361
2362 /**
2363 Submit data based on the input Setting level (Form, FormSet or System).
2364
2365 @param FormSet FormSet data structure.
2366 @param Form Form data structure.
2367 @param SettingScope Setting Scope for Submit action.
2368
2369 @retval EFI_SUCCESS The function completed successfully.
2370 @retval EFI_UNSUPPORTED Unsupport SettingScope.
2371
2372 **/
2373 EFI_STATUS
2374 SubmitForm (
2375 IN FORM_BROWSER_FORMSET *FormSet,
2376 IN FORM_BROWSER_FORM *Form,
2377 IN BROWSER_SETTING_SCOPE SettingScope
2378 )
2379 {
2380 EFI_STATUS Status;
2381 LIST_ENTRY *Link;
2382 EFI_STRING ConfigResp;
2383 EFI_STRING Progress;
2384 FORMSET_STORAGE *Storage;
2385 UINTN BufferSize;
2386 UINT8 *TmpBuf;
2387 FORM_BROWSER_FORMSET *LocalFormSet;
2388 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo;
2389
2390 //
2391 // Check the supported setting level.
2392 //
2393 if (SettingScope >= MaxLevel) {
2394 return EFI_UNSUPPORTED;
2395 }
2396
2397 //
2398 // Validate the Form by NoSubmit check
2399 //
2400 Status = EFI_SUCCESS;
2401 if (SettingScope == FormLevel) {
2402 Status = NoSubmitCheck (FormSet, Form);
2403 } else if (SettingScope == FormSetLevel) {
2404 Status = NoSubmitCheck (FormSet, NULL);
2405 }
2406 if (EFI_ERROR (Status)) {
2407 return Status;
2408 }
2409
2410 if (SettingScope == FormLevel && Form->NvUpdateRequired) {
2411 ConfigInfo = NULL;
2412 Link = GetFirstNode (&Form->ConfigRequestHead);
2413 while (!IsNull (&Form->ConfigRequestHead, Link)) {
2414 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link);
2415 Link = GetNextNode (&Form->ConfigRequestHead, Link);
2416
2417 Storage = ConfigInfo->Storage;
2418 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2419 continue;
2420 }
2421
2422 //
2423 // Skip if there is no RequestElement
2424 //
2425 if (ConfigInfo->ElementCount == 0) {
2426 continue;
2427 }
2428
2429 //
2430 // 1. Prepare <ConfigResp>
2431 //
2432 Status = StorageToConfigResp (ConfigInfo, &ConfigResp, TRUE);
2433 if (EFI_ERROR (Status)) {
2434 return Status;
2435 }
2436
2437 //
2438 // 2. Set value to hii driver or efi variable.
2439 //
2440 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2441 Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2442 //
2443 // Send <ConfigResp> to Configuration Driver
2444 //
2445 if (FormSet->ConfigAccess != NULL) {
2446 Status = FormSet->ConfigAccess->RouteConfig (
2447 FormSet->ConfigAccess,
2448 ConfigResp,
2449 &Progress
2450 );
2451 if (EFI_ERROR (Status)) {
2452 FreePool (ConfigResp);
2453 return Status;
2454 }
2455 }
2456 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
2457 TmpBuf = NULL;
2458 TmpBuf = AllocateZeroPool(Storage->Size);
2459 if (TmpBuf == NULL) {
2460 Status = EFI_OUT_OF_RESOURCES;
2461 return Status;
2462 }
2463
2464 BufferSize = Storage->Size;
2465 Status = gRT->GetVariable (
2466 Storage->Name,
2467 &Storage->Guid,
2468 NULL,
2469 &BufferSize,
2470 TmpBuf
2471 );
2472 if (EFI_ERROR (Status)) {
2473 FreePool (TmpBuf);
2474 FreePool (ConfigResp);
2475 return Status;
2476 }
2477 ASSERT (BufferSize == Storage->Size);
2478 Status = mHiiConfigRouting->ConfigToBlock (
2479 mHiiConfigRouting,
2480 ConfigResp,
2481 TmpBuf,
2482 &BufferSize,
2483 &Progress
2484 );
2485 if (EFI_ERROR (Status)) {
2486 FreePool (TmpBuf);
2487 FreePool (ConfigResp);
2488 return Status;
2489 }
2490
2491 Status = gRT->SetVariable (
2492 Storage->Name,
2493 &Storage->Guid,
2494 Storage->Attributes,
2495 Storage->Size,
2496 TmpBuf
2497 );
2498 FreePool (TmpBuf);
2499 if (EFI_ERROR (Status)) {
2500 FreePool (ConfigResp);
2501 return Status;
2502 }
2503 }
2504 FreePool (ConfigResp);
2505 //
2506 // 3. Config success, update storage shadow Buffer, only update the data belong to this form.
2507 //
2508 SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE);
2509 }
2510
2511 //
2512 // 4. Update the NV flag.
2513 //
2514 Form->NvUpdateRequired = FALSE;
2515 } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {
2516 //
2517 // Submit Buffer storage or Name/Value storage
2518 //
2519 Link = GetFirstNode (&FormSet->StorageListHead);
2520 while (!IsNull (&FormSet->StorageListHead, Link)) {
2521 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2522 Link = GetNextNode (&FormSet->StorageListHead, Link);
2523
2524 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2525 continue;
2526 }
2527
2528 //
2529 // Skip if there is no RequestElement
2530 //
2531 if (Storage->ElementCount == 0) {
2532 continue;
2533 }
2534
2535 //
2536 // 1. Prepare <ConfigResp>
2537 //
2538 Status = StorageToConfigResp (Storage, &ConfigResp, FALSE);
2539 if (EFI_ERROR (Status)) {
2540 return Status;
2541 }
2542
2543 if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||
2544 Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2545
2546 //
2547 // 2. Send <ConfigResp> to Configuration Driver
2548 //
2549 if (FormSet->ConfigAccess != NULL) {
2550 Status = FormSet->ConfigAccess->RouteConfig (
2551 FormSet->ConfigAccess,
2552 ConfigResp,
2553 &Progress
2554 );
2555 if (EFI_ERROR (Status)) {
2556 FreePool (ConfigResp);
2557 return Status;
2558 }
2559 }
2560 } else if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
2561 //
2562 // 1&2. Set the edit data to the variable.
2563 //
2564 TmpBuf = NULL;
2565 TmpBuf = AllocateZeroPool (Storage->Size);
2566 if (TmpBuf == NULL) {
2567 Status = EFI_OUT_OF_RESOURCES;
2568 return Status;
2569 }
2570 BufferSize = Storage->Size;
2571 Status = gRT->GetVariable (
2572 Storage->Name,
2573 &Storage->Guid,
2574 NULL,
2575 &BufferSize,
2576 TmpBuf
2577 );
2578 ASSERT (BufferSize == Storage->Size);
2579 Status = mHiiConfigRouting->ConfigToBlock (
2580 mHiiConfigRouting,
2581 ConfigResp,
2582 TmpBuf,
2583 &BufferSize,
2584 &Progress
2585 );
2586 if (EFI_ERROR (Status)) {
2587 FreePool (TmpBuf);
2588 FreePool (ConfigResp);
2589 return Status;
2590 }
2591
2592 Status = gRT->SetVariable (
2593 Storage->Name,
2594 &Storage->Guid,
2595 Storage->Attributes,
2596 Storage->Size,
2597 TmpBuf
2598 );
2599 if (EFI_ERROR (Status)) {
2600 FreePool (TmpBuf);
2601 FreePool (ConfigResp);
2602 return Status;
2603 }
2604 FreePool (TmpBuf);
2605 }
2606 FreePool (ConfigResp);
2607 //
2608 // 3. Config success, update storage shadow Buffer
2609 //
2610 SynchronizeStorage (Storage, TRUE);
2611 }
2612
2613 //
2614 // 4. Update the NV flag.
2615 //
2616 UpdateNvInfoInForm (FormSet, FALSE);
2617 } else if (SettingScope == SystemLevel) {
2618 //
2619 // System Level Save.
2620 //
2621
2622 //
2623 // Save changed value for each FormSet in the maintain list.
2624 //
2625 Link = GetFirstNode (&gBrowserFormSetList);
2626 while (!IsNull (&gBrowserFormSetList, Link)) {
2627 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
2628 Link = GetNextNode (&gBrowserFormSetList, Link);
2629 if (!ValidateFormSet(LocalFormSet)) {
2630 continue;
2631 }
2632 SubmitForm (LocalFormSet, NULL, FormSetLevel);
2633 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) {
2634 //
2635 // Remove maintain backup list after save except for the current using FormSet.
2636 //
2637 RemoveEntryList (&LocalFormSet->Link);
2638 DestroyFormSet (LocalFormSet);
2639 }
2640 }
2641 }
2642
2643 return EFI_SUCCESS;
2644 }
2645
2646 /**
2647 Get Question default value from AltCfg string.
2648
2649 @param FormSet The form set.
2650 @param Question The question.
2651 @param DefaultId The default Id.
2652
2653 @retval EFI_SUCCESS Question is reset to default value.
2654
2655 **/
2656 EFI_STATUS
2657 GetDefaultValueFromAltCfg (
2658 IN FORM_BROWSER_FORMSET *FormSet,
2659 IN OUT FORM_BROWSER_STATEMENT *Question,
2660 IN UINT16 DefaultId
2661 )
2662 {
2663 BOOLEAN IsBufferStorage;
2664 BOOLEAN IsString;
2665 UINTN Length;
2666 FORMSET_STORAGE *Storage;
2667 CHAR16 *ConfigRequest;
2668 CHAR16 *Progress;
2669 CHAR16 *Result;
2670 CHAR16 *ConfigResp;
2671 CHAR16 *Value;
2672 CHAR16 *StringPtr;
2673 UINTN LengthStr;
2674 UINT8 *Dst;
2675 CHAR16 TemStr[5];
2676 UINTN Index;
2677 UINT8 DigitUint8;
2678 EFI_STATUS Status;
2679
2680 Status = EFI_NOT_FOUND;
2681 Length = 0;
2682 Dst = NULL;
2683 ConfigRequest = NULL;
2684 Result = NULL;
2685 ConfigResp = NULL;
2686 Value = NULL;
2687 Storage = Question->Storage;
2688
2689 if ((Storage == NULL) ||
2690 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) ||
2691 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {
2692 return Status;
2693 }
2694
2695 //
2696 // Question Value is provided by Buffer Storage or NameValue Storage
2697 //
2698 if (Question->BufferValue != NULL) {
2699 //
2700 // This Question is password or orderedlist
2701 //
2702 Dst = Question->BufferValue;
2703 } else {
2704 //
2705 // Other type of Questions
2706 //
2707 Dst = (UINT8 *) &Question->HiiValue.Value;
2708 }
2709
2710 IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
2711 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
2712
2713 //
2714 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
2715 // <ConfigHdr> + "&" + <VariableName>
2716 //
2717 if (IsBufferStorage) {
2718 Length = StrLen (Storage->ConfigHdr);
2719 Length += StrLen (Question->BlockName);
2720 } else {
2721 Length = StrLen (Storage->ConfigHdr);
2722 Length += StrLen (Question->VariableName) + 1;
2723 }
2724 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
2725 ASSERT (ConfigRequest != NULL);
2726
2727 StrCpy (ConfigRequest, Storage->ConfigHdr);
2728 if (IsBufferStorage) {
2729 StrCat (ConfigRequest, Question->BlockName);
2730 } else {
2731 StrCat (ConfigRequest, L"&");
2732 StrCat (ConfigRequest, Question->VariableName);
2733 }
2734
2735 Status = FormSet->ConfigAccess->ExtractConfig (
2736 FormSet->ConfigAccess,
2737 ConfigRequest,
2738 &Progress,
2739 &Result
2740 );
2741 if (EFI_ERROR (Status)) {
2742 goto Done;
2743 }
2744
2745 //
2746 // Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
2747 // Get the default configuration string according to the default ID.
2748 //
2749 Status = mHiiConfigRouting->GetAltConfig (
2750 mHiiConfigRouting,
2751 Result,
2752 &Storage->Guid,
2753 Storage->Name,
2754 NULL,
2755 &DefaultId, // it can be NULL to get the current setting.
2756 &ConfigResp
2757 );
2758
2759 //
2760 // The required setting can't be found. So, it is not required to be validated and set.
2761 //
2762 if (EFI_ERROR (Status)) {
2763 goto Done;
2764 }
2765
2766 //
2767 // Skip <ConfigRequest>
2768 //
2769 if (IsBufferStorage) {
2770 Value = StrStr (ConfigResp, L"&VALUE");
2771 ASSERT (Value != NULL);
2772 //
2773 // Skip "&VALUE"
2774 //
2775 Value = Value + 6;
2776 } else {
2777 Value = StrStr (ConfigResp, Question->VariableName);
2778 ASSERT (Value != NULL);
2779
2780 Value = Value + StrLen (Question->VariableName);
2781 }
2782 if (*Value != '=') {
2783 Status = EFI_NOT_FOUND;
2784 goto Done;
2785 }
2786 //
2787 // Skip '=', point to value
2788 //
2789 Value = Value + 1;
2790
2791 //
2792 // Suppress <AltResp> if any
2793 //
2794 StringPtr = Value;
2795 while (*StringPtr != L'\0' && *StringPtr != L'&') {
2796 StringPtr++;
2797 }
2798 *StringPtr = L'\0';
2799
2800 LengthStr = StrLen (Value);
2801 if (!IsBufferStorage && IsString) {
2802 StringPtr = (CHAR16 *) Dst;
2803 ZeroMem (TemStr, sizeof (TemStr));
2804 for (Index = 0; Index < LengthStr; Index += 4) {
2805 StrnCpy (TemStr, Value + Index, 4);
2806 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
2807 }
2808 //
2809 // Add tailing L'\0' character
2810 //
2811 StringPtr[Index/4] = L'\0';
2812 } else {
2813 ZeroMem (TemStr, sizeof (TemStr));
2814 for (Index = 0; Index < LengthStr; Index ++) {
2815 TemStr[0] = Value[LengthStr - Index - 1];
2816 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
2817 if ((Index & 1) == 0) {
2818 Dst [Index/2] = DigitUint8;
2819 } else {
2820 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
2821 }
2822 }
2823 }
2824
2825 Done:
2826 if (ConfigRequest != NULL){
2827 FreePool (ConfigRequest);
2828 }
2829
2830 if (ConfigResp != NULL) {
2831 FreePool (ConfigResp);
2832 }
2833
2834 if (Result != NULL) {
2835 FreePool (Result);
2836 }
2837
2838 return Status;
2839 }
2840
2841 /**
2842 Get default Id value used for browser.
2843
2844 @param DefaultId The default id value used by hii.
2845
2846 @retval Browser used default value.
2847
2848 **/
2849 INTN
2850 GetDefaultIdForCallBack (
2851 UINTN DefaultId
2852 )
2853 {
2854 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
2855 return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
2856 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2857 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
2858 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
2859 return EFI_BROWSER_ACTION_DEFAULT_SAFE;
2860 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {
2861 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
2862 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {
2863 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
2864 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {
2865 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
2866 } else {
2867 return -1;
2868 }
2869 }
2870
2871 /**
2872 Reset Question to its default value.
2873
2874 @param FormSet The form set.
2875 @param Form The form.
2876 @param Question The question.
2877 @param DefaultId The Class of the default.
2878
2879 @retval EFI_SUCCESS Question is reset to default value.
2880
2881 **/
2882 EFI_STATUS
2883 GetQuestionDefault (
2884 IN FORM_BROWSER_FORMSET *FormSet,
2885 IN FORM_BROWSER_FORM *Form,
2886 IN FORM_BROWSER_STATEMENT *Question,
2887 IN UINT16 DefaultId
2888 )
2889 {
2890 EFI_STATUS Status;
2891 LIST_ENTRY *Link;
2892 QUESTION_DEFAULT *Default;
2893 QUESTION_OPTION *Option;
2894 EFI_HII_VALUE *HiiValue;
2895 UINT8 Index;
2896 EFI_STRING StrValue;
2897 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2898 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2899 INTN Action;
2900
2901 Status = EFI_NOT_FOUND;
2902 StrValue = NULL;
2903
2904 //
2905 // Statement don't have storage, skip them
2906 //
2907 if (Question->QuestionId == 0) {
2908 return Status;
2909 }
2910
2911 //
2912 // There are Five ways to specify default value for a Question:
2913 // 1, use call back function (highest priority)
2914 // 2, use ExtractConfig function
2915 // 3, use nested EFI_IFR_DEFAULT
2916 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
2917 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
2918 //
2919 HiiValue = &Question->HiiValue;
2920
2921 //
2922 // Get Question defaut value from call back function.
2923 //
2924 ConfigAccess = FormSet->ConfigAccess;
2925 Action = GetDefaultIdForCallBack (DefaultId);
2926 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
2927 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2928 Status = ConfigAccess->Callback (
2929 ConfigAccess,
2930 Action,
2931 Question->QuestionId,
2932 HiiValue->Type,
2933 &HiiValue->Value,
2934 &ActionRequest
2935 );
2936 if (!EFI_ERROR (Status)) {
2937 return Status;
2938 }
2939 }
2940
2941 //
2942 // Get default value from altcfg string.
2943 //
2944 if (ConfigAccess != NULL) {
2945 Status = GetDefaultValueFromAltCfg(FormSet, Question, DefaultId);
2946 if (!EFI_ERROR (Status)) {
2947 return Status;
2948 }
2949 }
2950
2951 //
2952 // EFI_IFR_DEFAULT has highest priority
2953 //
2954 if (!IsListEmpty (&Question->DefaultListHead)) {
2955 Link = GetFirstNode (&Question->DefaultListHead);
2956 while (!IsNull (&Question->DefaultListHead, Link)) {
2957 Default = QUESTION_DEFAULT_FROM_LINK (Link);
2958
2959 if (Default->DefaultId == DefaultId) {
2960 if (Default->ValueExpression != NULL) {
2961 //
2962 // Default is provided by an Expression, evaluate it
2963 //
2964 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
2965 if (EFI_ERROR (Status)) {
2966 return Status;
2967 }
2968
2969 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
2970 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL);
2971 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
2972 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
2973 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
2974 } else {
2975 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
2976 Question->HiiValue.BufferLen = Question->StorageWidth;
2977 }
2978 FreePool (Default->ValueExpression->Result.Buffer);
2979 }
2980 HiiValue->Type = Default->ValueExpression->Result.Type;
2981 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
2982 } else {
2983 //
2984 // Default value is embedded in EFI_IFR_DEFAULT
2985 //
2986 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
2987 }
2988
2989 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2990 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
2991 if (StrValue == NULL) {
2992 return EFI_NOT_FOUND;
2993 }
2994 if (Question->StorageWidth > StrSize (StrValue)) {
2995 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue));
2996 } else {
2997 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth);
2998 }
2999 }
3000
3001 return EFI_SUCCESS;
3002 }
3003
3004 Link = GetNextNode (&Question->DefaultListHead, Link);
3005 }
3006 }
3007
3008 //
3009 // EFI_ONE_OF_OPTION
3010 //
3011 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
3012 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3013 //
3014 // OneOfOption could only provide Standard and Manufacturing default
3015 //
3016 Link = GetFirstNode (&Question->OptionListHead);
3017 while (!IsNull (&Question->OptionListHead, Link)) {
3018 Option = QUESTION_OPTION_FROM_LINK (Link);
3019 Link = GetNextNode (&Question->OptionListHead, Link);
3020
3021 if ((Option->SuppressExpression != NULL) &&
3022 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3023 continue;
3024 }
3025
3026 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
3027 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
3028 ) {
3029 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3030
3031 return EFI_SUCCESS;
3032 }
3033 }
3034 }
3035 }
3036
3037 //
3038 // EFI_IFR_CHECKBOX - lowest priority
3039 //
3040 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
3041 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3042 //
3043 // Checkbox could only provide Standard and Manufacturing default
3044 //
3045 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
3046 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
3047 ) {
3048 HiiValue->Value.b = TRUE;
3049 } else {
3050 HiiValue->Value.b = FALSE;
3051 }
3052
3053 return EFI_SUCCESS;
3054 }
3055 }
3056
3057 //
3058 // For Questions without default
3059 //
3060 Status = EFI_NOT_FOUND;
3061 switch (Question->Operand) {
3062 case EFI_IFR_NUMERIC_OP:
3063 //
3064 // Take minimum value as numeric default value
3065 //
3066 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
3067 HiiValue->Value.u64 = Question->Minimum;
3068 Status = EFI_SUCCESS;
3069 }
3070 break;
3071
3072 case EFI_IFR_ONE_OF_OP:
3073 //
3074 // Take first oneof option as oneof's default value
3075 //
3076 if (ValueToOption (Question, HiiValue) == NULL) {
3077 Link = GetFirstNode (&Question->OptionListHead);
3078 while (!IsNull (&Question->OptionListHead, Link)) {
3079 Option = QUESTION_OPTION_FROM_LINK (Link);
3080 Link = GetNextNode (&Question->OptionListHead, Link);
3081
3082 if ((Option->SuppressExpression != NULL) &&
3083 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3084 continue;
3085 }
3086
3087 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
3088 Status = EFI_SUCCESS;
3089 break;
3090 }
3091 }
3092 break;
3093
3094 case EFI_IFR_ORDERED_LIST_OP:
3095 //
3096 // Take option sequence in IFR as ordered list's default value
3097 //
3098 Index = 0;
3099 Link = GetFirstNode (&Question->OptionListHead);
3100 while (!IsNull (&Question->OptionListHead, Link)) {
3101 Status = EFI_SUCCESS;
3102 Option = QUESTION_OPTION_FROM_LINK (Link);
3103 Link = GetNextNode (&Question->OptionListHead, Link);
3104
3105 if ((Option->SuppressExpression != NULL) &&
3106 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
3107 continue;
3108 }
3109
3110 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
3111
3112 Index++;
3113 if (Index >= Question->MaxContainers) {
3114 break;
3115 }
3116 }
3117 break;
3118
3119 default:
3120 break;
3121 }
3122
3123 return Status;
3124 }
3125
3126
3127 /**
3128 Reset Questions to their initial value or default value in a Form, Formset or System.
3129
3130 GetDefaultValueScope parameter decides which questions will reset
3131 to its default value.
3132
3133 @param FormSet FormSet data structure.
3134 @param Form Form data structure.
3135 @param DefaultId The Class of the default.
3136 @param SettingScope Setting Scope for Default action.
3137 @param GetDefaultValueScope Get default value scope.
3138 @param Storage Get default value only for this storage.
3139 @param RetrieveValueFirst Whether call the retrieve call back to
3140 get the initial value before get default
3141 value.
3142
3143 @retval EFI_SUCCESS The function completed successfully.
3144 @retval EFI_UNSUPPORTED Unsupport SettingScope.
3145
3146 **/
3147 EFI_STATUS
3148 ExtractDefault (
3149 IN FORM_BROWSER_FORMSET *FormSet,
3150 IN FORM_BROWSER_FORM *Form,
3151 IN UINT16 DefaultId,
3152 IN BROWSER_SETTING_SCOPE SettingScope,
3153 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope,
3154 IN FORMSET_STORAGE *Storage OPTIONAL,
3155 IN BOOLEAN RetrieveValueFirst
3156 )
3157 {
3158 EFI_STATUS Status;
3159 LIST_ENTRY *FormLink;
3160 LIST_ENTRY *Link;
3161 FORM_BROWSER_STATEMENT *Question;
3162 FORM_BROWSER_FORMSET *BackUpFormSet;
3163 FORM_BROWSER_FORMSET *LocalFormSet;
3164 EFI_HII_HANDLE *HiiHandles;
3165 UINTN Index;
3166 EFI_GUID ZeroGuid;
3167
3168 Status = EFI_SUCCESS;
3169
3170 //
3171 // Check the supported setting level.
3172 //
3173 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) {
3174 return EFI_UNSUPPORTED;
3175 }
3176
3177 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) {
3178 return EFI_UNSUPPORTED;
3179 }
3180
3181 if (SettingScope == FormLevel) {
3182 //
3183 // Extract Form default
3184 //
3185 Link = GetFirstNode (&Form->StatementListHead);
3186 while (!IsNull (&Form->StatementListHead, Link)) {
3187 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3188 Link = GetNextNode (&Form->StatementListHead, Link);
3189
3190 //
3191 // If get default value only for this storage, check the storage first.
3192 //
3193 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) {
3194 continue;
3195 }
3196
3197 //
3198 // If get default value only for no storage question, just skip the question which has storage.
3199 //
3200 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) {
3201 continue;
3202 }
3203
3204 //
3205 // If Question is disabled, don't reset it to default
3206 //
3207 if (Question->Expression != NULL) {
3208 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) {
3209 continue;
3210 }
3211 }
3212
3213 if (RetrieveValueFirst) {
3214 //
3215 // Call the Retrieve call back to get the initial question value.
3216 //
3217 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question);
3218 }
3219
3220 //
3221 // If not request to get the initial value or get initial value fail, then get default value.
3222 //
3223 if (!RetrieveValueFirst || EFI_ERROR (Status)) {
3224 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
3225 if (EFI_ERROR (Status)) {
3226 continue;
3227 }
3228 }
3229
3230 //
3231 // Synchronize Buffer storage's Edit buffer
3232 //
3233 if ((Question->Storage != NULL) &&
3234 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
3235 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3236 //
3237 // Update Form NV flag.
3238 //
3239 Form->NvUpdateRequired = TRUE;
3240 }
3241 }
3242 } else if (SettingScope == FormSetLevel) {
3243 FormLink = GetFirstNode (&FormSet->FormListHead);
3244 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3245 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3246 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3247 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3248 }
3249 } else if (SettingScope == SystemLevel) {
3250 //
3251 // Open all FormSet by locate HII packages.
3252 // Initiliaze the maintain FormSet to store default data as back up data.
3253 //
3254 BackUpFormSet = gOldFormSet;
3255 gOldFormSet = NULL;
3256
3257 //
3258 // Get all the Hii handles
3259 //
3260 HiiHandles = HiiGetHiiHandles (NULL);
3261 ASSERT (HiiHandles != NULL);
3262
3263 //
3264 // Search for formset of each class type
3265 //
3266 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
3267 //
3268 // Check HiiHandles[Index] does exist in global maintain list.
3269 //
3270 if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {
3271 continue;
3272 }
3273
3274 //
3275 // Initilize FormSet Setting
3276 //
3277 LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
3278 ASSERT (LocalFormSet != NULL);
3279 ZeroMem (&ZeroGuid, sizeof (ZeroGuid));
3280 Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE);
3281 if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {
3282 DestroyFormSet (LocalFormSet);
3283 continue;
3284 }
3285 Status = InitializeCurrentSetting (LocalFormSet);
3286 if (EFI_ERROR (Status)) {
3287 DestroyFormSet (LocalFormSet);
3288 continue;
3289 }
3290 //
3291 // Initilize Questions' Value
3292 //
3293 Status = LoadFormSetConfig (NULL, LocalFormSet);
3294 if (EFI_ERROR (Status)) {
3295 DestroyFormSet (LocalFormSet);
3296 continue;
3297 }
3298
3299 //
3300 // Add FormSet into the maintain list.
3301 //
3302 InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);
3303 }
3304
3305 //
3306 // Free resources, and restore gOldFormSet and gClassOfVfr
3307 //
3308 FreePool (HiiHandles);
3309 gOldFormSet = BackUpFormSet;
3310
3311 //
3312 // Set Default Value for each FormSet in the maintain list.
3313 //
3314 Link = GetFirstNode (&gBrowserFormSetList);
3315 while (!IsNull (&gBrowserFormSetList, Link)) {
3316 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
3317 Link = GetNextNode (&gBrowserFormSetList, Link);
3318 if (!ValidateFormSet(LocalFormSet)) {
3319 continue;
3320 }
3321 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst);
3322 }
3323 }
3324
3325 return EFI_SUCCESS;
3326 }
3327
3328 /**
3329 Initialize Question's Edit copy from Storage.
3330
3331 @param Selection Selection contains the information about
3332 the Selection, form and formset to be displayed.
3333 Selection action may be updated in retrieve callback.
3334 If Selection is NULL, only initialize Question value.
3335 @param FormSet FormSet data structure.
3336 @param Form Form data structure.
3337
3338 @retval EFI_SUCCESS The function completed successfully.
3339
3340 **/
3341 EFI_STATUS
3342 LoadFormConfig (
3343 IN OUT UI_MENU_SELECTION *Selection,
3344 IN FORM_BROWSER_FORMSET *FormSet,
3345 IN FORM_BROWSER_FORM *Form
3346 )
3347 {
3348 EFI_STATUS Status;
3349 LIST_ENTRY *Link;
3350 FORM_BROWSER_STATEMENT *Question;
3351 UINT8 *BufferValue;
3352 UINTN StorageWidth;
3353
3354 Link = GetFirstNode (&Form->StatementListHead);
3355 while (!IsNull (&Form->StatementListHead, Link)) {
3356 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3357
3358 //
3359 // Initialize local copy of Value for each Question
3360 //
3361 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
3362 if (EFI_ERROR (Status)) {
3363 return Status;
3364 }
3365
3366 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) {
3367 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
3368 }
3369
3370 //
3371 // Call the Retrieve call back function for all questions.
3372 //
3373 if ((FormSet->ConfigAccess != NULL) && (Selection != NULL) &&
3374 ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
3375 //
3376 // Check QuestionValue does exist.
3377 //
3378 StorageWidth = Question->StorageWidth;
3379 if (Question->BufferValue != NULL) {
3380 BufferValue = Question->BufferValue;
3381 } else {
3382 BufferValue = (UINT8 *) &Question->HiiValue.Value;
3383 }
3384
3385 //
3386 // For efivarstore storage, initial question value first.
3387 //
3388 if ((Question->Storage != NULL) && (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
3389 Status = gRT->GetVariable (
3390 Question->VariableName,
3391 &Question->Storage->Guid,
3392 NULL,
3393 &StorageWidth,
3394 BufferValue
3395 );
3396 }
3397
3398 Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);
3399 }
3400
3401 Link = GetNextNode (&Form->StatementListHead, Link);
3402 }
3403
3404 return EFI_SUCCESS;
3405 }
3406
3407 /**
3408 Initialize Question's Edit copy from Storage for the whole Formset.
3409
3410 @param Selection Selection contains the information about
3411 the Selection, form and formset to be displayed.
3412 Selection action may be updated in retrieve callback.
3413 If Selection is NULL, only initialize Question value.
3414 @param FormSet FormSet data structure.
3415
3416 @retval EFI_SUCCESS The function completed successfully.
3417
3418 **/
3419 EFI_STATUS
3420 LoadFormSetConfig (
3421 IN OUT UI_MENU_SELECTION *Selection,
3422 IN FORM_BROWSER_FORMSET *FormSet
3423 )
3424 {
3425 EFI_STATUS Status;
3426 LIST_ENTRY *Link;
3427 FORM_BROWSER_FORM *Form;
3428
3429 Link = GetFirstNode (&FormSet->FormListHead);
3430 while (!IsNull (&FormSet->FormListHead, Link)) {
3431 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3432
3433 //
3434 // Initialize local copy of Value for each Form
3435 //
3436 Status = LoadFormConfig (Selection, FormSet, Form);
3437 if (EFI_ERROR (Status)) {
3438 return Status;
3439 }
3440
3441 Link = GetNextNode (&FormSet->FormListHead, Link);
3442 }
3443
3444 return EFI_SUCCESS;
3445 }
3446
3447 /**
3448 Fill storage's edit copy with settings requested from Configuration Driver.
3449
3450 @param FormSet FormSet data structure.
3451 @param Storage Buffer Storage.
3452
3453 @retval EFI_SUCCESS The function completed successfully.
3454
3455 **/
3456 EFI_STATUS
3457 LoadStorage (
3458 IN FORM_BROWSER_FORMSET *FormSet,
3459 IN FORMSET_STORAGE *Storage
3460 )
3461 {
3462 EFI_STATUS Status;
3463 EFI_STRING Progress;
3464 EFI_STRING Result;
3465 CHAR16 *StrPtr;
3466
3467 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
3468 return EFI_SUCCESS;
3469 }
3470
3471 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {
3472 Status = gRT->GetVariable (
3473 Storage->Name,
3474 &Storage->Guid,
3475 NULL,
3476 (UINTN*)&Storage->Size,
3477 Storage->EditBuffer
3478 );
3479 return Status;
3480 }
3481
3482 if (FormSet->ConfigAccess == NULL) {
3483 return EFI_NOT_FOUND;
3484 }
3485
3486 if (Storage->ElementCount == 0) {
3487 //
3488 // Skip if there is no RequestElement
3489 //
3490 return EFI_SUCCESS;
3491 }
3492
3493 //
3494 // Request current settings from Configuration Driver
3495 //
3496 Status = FormSet->ConfigAccess->ExtractConfig (
3497 FormSet->ConfigAccess,
3498 Storage->ConfigRequest,
3499 &Progress,
3500 &Result
3501 );
3502 if (EFI_ERROR (Status)) {
3503 return Status;
3504 }
3505
3506 //
3507 // Convert Result from <ConfigAltResp> to <ConfigResp>
3508 //
3509 StrPtr = StrStr (Result, L"&GUID=");
3510 if (StrPtr != NULL) {
3511 *StrPtr = L'\0';
3512 }
3513
3514 Status = ConfigRespToStorage (Storage, Result);
3515 FreePool (Result);
3516 return Status;
3517 }
3518
3519
3520 /**
3521 Copy uncommitted data from source Storage to destination Storage.
3522
3523 @param Dst Target Storage for uncommitted data.
3524 @param Src Source Storage for uncommitted data.
3525
3526 @retval EFI_SUCCESS The function completed successfully.
3527 @retval EFI_INVALID_PARAMETER Source and destination Storage is not the same type.
3528
3529 **/
3530 EFI_STATUS
3531 CopyStorage (
3532 IN OUT FORMSET_STORAGE *Dst,
3533 IN FORMSET_STORAGE *Src
3534 )
3535 {
3536 LIST_ENTRY *Link;
3537 NAME_VALUE_NODE *Node;
3538
3539 if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {
3540 return EFI_INVALID_PARAMETER;
3541 }
3542
3543 switch (Src->Type) {
3544 case EFI_HII_VARSTORE_BUFFER:
3545 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
3546 CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);
3547 CopyMem (Dst->Buffer, Src->Buffer, Src->Size);
3548 break;
3549
3550 case EFI_HII_VARSTORE_NAME_VALUE:
3551 Link = GetFirstNode (&Src->NameValueListHead);
3552 while (!IsNull (&Src->NameValueListHead, Link)) {
3553 Node = NAME_VALUE_NODE_FROM_LINK (Link);
3554
3555 SetValueByName (Dst, Node->Name, Node->EditValue, GetSetValueWithEditBuffer);
3556 SetValueByName (Dst, Node->Name, Node->Value, GetSetValueWithBuffer);
3557
3558 Link = GetNextNode (&Src->NameValueListHead, Link);
3559 }
3560 break;
3561
3562 case EFI_HII_VARSTORE_EFI_VARIABLE:
3563 default:
3564 break;
3565 }
3566
3567 return EFI_SUCCESS;
3568 }
3569
3570 /**
3571 Get old question value from the saved formset.
3572
3573 @param Statement The question which need to get old question value.
3574 @param OldFormSet FormSet data structure saved in the list.
3575
3576 **/
3577 VOID
3578 GetOldQuestionValue (
3579 IN OUT FORM_BROWSER_STATEMENT *Statement,
3580 IN FORM_BROWSER_FORMSET *OldFormSet
3581 )
3582 {
3583 LIST_ENTRY *FormLink;
3584 LIST_ENTRY *Link;
3585 FORM_BROWSER_STATEMENT *Question;
3586 FORM_BROWSER_FORM *Form;
3587
3588 FormLink = GetFirstNode (&OldFormSet->FormListHead);
3589 while (!IsNull (&OldFormSet->FormListHead, FormLink)) {
3590 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3591 FormLink = GetNextNode (&OldFormSet->FormListHead, FormLink);
3592
3593 Link = GetFirstNode (&Form->StatementListHead);
3594 while (!IsNull (&Form->StatementListHead, Link)) {
3595 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3596 Link = GetNextNode (&Form->StatementListHead, Link);
3597
3598 if (Question->QuestionId != Statement->QuestionId) {
3599 continue;
3600 }
3601
3602 CopyMem (&Statement->HiiValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));
3603 return;
3604 }
3605 }
3606 }
3607
3608 /**
3609 Get old question value from the saved formset, all these questions not have
3610 storage.
3611
3612 @param FormSet FormSet data structure which is used now.
3613 @param OldFormSet FormSet data structure saved in the list.
3614
3615 **/
3616 VOID
3617 CopyOldValueForNoStorageQst (
3618 IN OUT FORM_BROWSER_FORMSET *FormSet,
3619 IN FORM_BROWSER_FORMSET *OldFormSet
3620 )
3621 {
3622 LIST_ENTRY *FormLink;
3623 LIST_ENTRY *Link;
3624 FORM_BROWSER_STATEMENT *Question;
3625 FORM_BROWSER_FORM *Form;
3626
3627 FormLink = GetFirstNode (&FormSet->FormListHead);
3628 while (!IsNull (&FormSet->FormListHead, FormLink)) {
3629 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
3630 FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
3631
3632 Link = GetFirstNode (&Form->StatementListHead);
3633 while (!IsNull (&Form->StatementListHead, Link)) {
3634 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
3635 Link = GetNextNode (&Form->StatementListHead, Link);
3636
3637 if (Question->Storage == NULL) {
3638 GetOldQuestionValue (Question, OldFormSet);
3639 }
3640 }
3641 }
3642 }
3643
3644 /**
3645 Get current setting of Questions.
3646
3647 @param FormSet FormSet data structure.
3648
3649 @retval EFI_SUCCESS The function completed successfully.
3650
3651 **/
3652 EFI_STATUS
3653 InitializeCurrentSetting (
3654 IN OUT FORM_BROWSER_FORMSET *FormSet
3655 )
3656 {
3657 LIST_ENTRY *Link;
3658 LIST_ENTRY *Link2;
3659 FORMSET_STORAGE *Storage;
3660 FORMSET_STORAGE *StorageSrc;
3661 FORMSET_STORAGE *OldStorage;
3662 FORM_BROWSER_FORM *Form;
3663 FORM_BROWSER_FORM *Form2;
3664 EFI_STATUS Status;
3665
3666 //
3667 // Extract default from IFR binary for no storage questions.
3668 //
3669 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE);
3670
3671 //
3672 // Request current settings from Configuration Driver
3673 //
3674 Link = GetFirstNode (&FormSet->StorageListHead);
3675 while (!IsNull (&FormSet->StorageListHead, Link)) {
3676 Storage = FORMSET_STORAGE_FROM_LINK (Link);
3677
3678 OldStorage = NULL;
3679 if (gOldFormSet != NULL) {
3680 //
3681 // Try to find the Storage in backup formset gOldFormSet
3682 //
3683 Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
3684 while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
3685 StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
3686
3687 if (StorageSrc->VarStoreId == Storage->VarStoreId) {
3688 OldStorage = StorageSrc;
3689 break;
3690 }
3691
3692 Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
3693 }
3694 }
3695
3696 if (OldStorage == NULL) {
3697 //
3698 // Storage is not found in backup formset, request it from ConfigDriver
3699 //
3700 Status = LoadStorage (FormSet, Storage);
3701
3702 if (EFI_ERROR (Status)) {
3703 //
3704 // If get last time changed value failed, extract default from IFR binary
3705 //
3706 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);
3707 //
3708 // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag
3709 // in current situation.
3710 //
3711 UpdateNvInfoInForm (FormSet, FALSE);
3712 }
3713
3714 //
3715 // Now Edit Buffer is filled with default values(lower priority) or current
3716 // settings(higher priority), sychronize it to shadow Buffer
3717 //
3718 SynchronizeStorage (Storage, TRUE);
3719 } else {
3720 //
3721 // Storage found in backup formset, use it
3722 //
3723 Status = CopyStorage (Storage, OldStorage);
3724 }
3725
3726 Link = GetNextNode (&FormSet->StorageListHead, Link);
3727 }
3728
3729 //
3730 // If has old formset, get the old nv update status.
3731 //
3732 if (gOldFormSet != NULL) {
3733 Link = GetFirstNode (&FormSet->FormListHead);
3734 while (!IsNull (&FormSet->FormListHead, Link)) {
3735 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
3736
3737 Link2 = GetFirstNode (&gOldFormSet->FormListHead);
3738 while (!IsNull (&gOldFormSet->FormListHead, Link2)) {
3739 Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);
3740
3741 if (Form->FormId == Form2->FormId) {
3742 Form->NvUpdateRequired = Form2->NvUpdateRequired;
3743 break;
3744 }
3745
3746 Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);
3747 }
3748 Link = GetNextNode (&FormSet->FormListHead, Link);
3749 }
3750 }
3751
3752 return EFI_SUCCESS;
3753 }
3754
3755
3756 /**
3757 Fetch the Ifr binary data of a FormSet.
3758
3759 @param Handle PackageList Handle
3760 @param FormSetGuid On input, GUID or class GUID of a formset. If not
3761 specified (NULL or zero GUID), take the first
3762 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
3763 found in package list.
3764 On output, GUID of the formset found(if not NULL).
3765 @param BinaryLength The length of the FormSet IFR binary.
3766 @param BinaryData The buffer designed to receive the FormSet.
3767
3768 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
3769 BufferLength was updated.
3770 @retval EFI_INVALID_PARAMETER The handle is unknown.
3771 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
3772 be found with the requested FormId.
3773
3774 **/
3775 EFI_STATUS
3776 GetIfrBinaryData (
3777 IN EFI_HII_HANDLE Handle,
3778 IN OUT EFI_GUID *FormSetGuid,
3779 OUT UINTN *BinaryLength,
3780 OUT UINT8 **BinaryData
3781 )
3782 {
3783 EFI_STATUS Status;
3784 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
3785 UINTN BufferSize;
3786 UINT8 *Package;
3787 UINT8 *OpCodeData;
3788 UINT32 Offset;
3789 UINT32 Offset2;
3790 UINT32 PackageListLength;
3791 EFI_HII_PACKAGE_HEADER PackageHeader;
3792 UINT8 Index;
3793 UINT8 NumberOfClassGuid;
3794 BOOLEAN ClassGuidMatch;
3795 EFI_GUID *ClassGuid;
3796 EFI_GUID *ComparingGuid;
3797
3798 OpCodeData = NULL;
3799 Package = NULL;
3800 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
3801
3802 //
3803 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
3804 //
3805 if (FormSetGuid == NULL) {
3806 ComparingGuid = &gZeroGuid;
3807 } else {
3808 ComparingGuid = FormSetGuid;
3809 }
3810
3811 //
3812 // Get HII PackageList
3813 //
3814 BufferSize = 0;
3815 HiiPackageList = NULL;
3816 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
3817 if (Status == EFI_BUFFER_TOO_SMALL) {
3818 HiiPackageList = AllocatePool (BufferSize);
3819 ASSERT (HiiPackageList != NULL);
3820
3821 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
3822 }
3823 if (EFI_ERROR (Status)) {
3824 return Status;
3825 }
3826 ASSERT (HiiPackageList != NULL);
3827
3828 //
3829 // Get Form package from this HII package List
3830 //
3831 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3832 Offset2 = 0;
3833 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
3834
3835 ClassGuidMatch = FALSE;
3836 while (Offset < PackageListLength) {
3837 Package = ((UINT8 *) HiiPackageList) + Offset;
3838 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3839
3840 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
3841 //
3842 // Search FormSet in this Form Package
3843 //
3844 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
3845 while (Offset2 < PackageHeader.Length) {
3846 OpCodeData = Package + Offset2;
3847
3848 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
3849 //
3850 // Try to compare against formset GUID
3851 //
3852 if (CompareGuid (FormSetGuid, &gZeroGuid) ||
3853 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
3854 break;
3855 }
3856
3857 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
3858 //
3859 // Try to compare against formset class GUID
3860 //
3861 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
3862 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
3863 for (Index = 0; Index < NumberOfClassGuid; Index++) {
3864 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
3865 ClassGuidMatch = TRUE;
3866 break;
3867 }
3868 }
3869 if (ClassGuidMatch) {
3870 break;
3871 }
3872 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
3873 ClassGuidMatch = TRUE;
3874 break;
3875 }
3876 }
3877
3878 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
3879 }
3880
3881 if (Offset2 < PackageHeader.Length) {
3882 //
3883 // Target formset found
3884 //
3885 break;
3886 }
3887 }
3888
3889 Offset += PackageHeader.Length;
3890 }
3891
3892 if (Offset >= PackageListLength) {
3893 //
3894 // Form package not found in this Package List
3895 //
3896 FreePool (HiiPackageList);
3897 return EFI_NOT_FOUND;
3898 }
3899
3900 if (FormSetGuid != NULL) {
3901 //
3902 // Return the FormSet GUID
3903 //
3904 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
3905 }
3906
3907 //
3908 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
3909 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
3910 // of the Form Package.
3911 //
3912 *BinaryLength = PackageHeader.Length - Offset2;
3913 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
3914
3915 FreePool (HiiPackageList);
3916
3917 if (*BinaryData == NULL) {
3918 return EFI_OUT_OF_RESOURCES;
3919 }
3920
3921 return EFI_SUCCESS;
3922 }
3923
3924
3925 /**
3926 Initialize the internal data structure of a FormSet.
3927
3928 @param Handle PackageList Handle
3929 @param FormSetGuid On input, GUID or class GUID of a formset. If not
3930 specified (NULL or zero GUID), take the first
3931 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
3932 found in package list.
3933 On output, GUID of the formset found(if not NULL).
3934 @param FormSet FormSet data structure.
3935 @param UpdateGlobalVar Whether need to update the global variable.
3936
3937 @retval EFI_SUCCESS The function completed successfully.
3938 @retval EFI_NOT_FOUND The specified FormSet could not be found.
3939
3940 **/
3941 EFI_STATUS
3942 InitializeFormSet (
3943 IN EFI_HII_HANDLE Handle,
3944 IN OUT EFI_GUID *FormSetGuid,
3945 OUT FORM_BROWSER_FORMSET *FormSet,
3946 IN BOOLEAN UpdateGlobalVar
3947 )
3948 {
3949 EFI_STATUS Status;
3950 EFI_HANDLE DriverHandle;
3951 UINT16 Index;
3952
3953 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
3954 if (EFI_ERROR (Status)) {
3955 return Status;
3956 }
3957
3958 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;
3959 FormSet->HiiHandle = Handle;
3960 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
3961
3962 //
3963 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
3964 //
3965 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
3966 if (EFI_ERROR (Status)) {
3967 return Status;
3968 }
3969 FormSet->DriverHandle = DriverHandle;
3970 Status = gBS->HandleProtocol (
3971 DriverHandle,
3972 &gEfiHiiConfigAccessProtocolGuid,
3973 (VOID **) &FormSet->ConfigAccess
3974 );
3975 if (EFI_ERROR (Status)) {
3976 //
3977 // Configuration Driver don't attach ConfigAccess protocol to its HII package
3978 // list, then there will be no configuration action required
3979 //
3980 FormSet->ConfigAccess = NULL;
3981 }
3982
3983 //
3984 // Parse the IFR binary OpCodes
3985 //
3986 Status = ParseOpCodes (FormSet);
3987 if (EFI_ERROR (Status)) {
3988 return Status;
3989 }
3990
3991 //
3992 // If not need to update the global variable, just return.
3993 //
3994 if (!UpdateGlobalVar) {
3995 return Status;
3996 }
3997
3998 //
3999 // Set VFR type by FormSet SubClass field
4000 //
4001 gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
4002 if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
4003 gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
4004 }
4005
4006 //
4007 // Set VFR type by FormSet class guid
4008 //
4009 for (Index = 0; Index < 3; Index ++) {
4010 if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
4011 gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
4012 break;
4013 }
4014 }
4015
4016 gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING;
4017
4018 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
4019 gFrontPageHandle = FormSet->HiiHandle;
4020 gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;
4021 }
4022
4023 //
4024 // Match GUID to find out the function key setting. If match fail, use the default setting.
4025 //
4026 for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
4027 if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
4028 //
4029 // Update the function key setting.
4030 //
4031 gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
4032 }
4033 }
4034
4035 return EFI_SUCCESS;
4036 }
4037
4038
4039 /**
4040 Save globals used by previous call to SendForm(). SendForm() may be called from
4041 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
4042 So, save globals of previous call to SendForm() and restore them upon exit.
4043
4044 **/
4045 VOID
4046 SaveBrowserContext (
4047 VOID
4048 )
4049 {
4050 BROWSER_CONTEXT *Context;
4051
4052 gBrowserContextCount++;
4053 if (gBrowserContextCount == 1) {
4054 //
4055 // This is not reentry of SendForm(), no context to save
4056 //
4057 return;
4058 }
4059
4060 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
4061 ASSERT (Context != NULL);
4062
4063 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
4064
4065 //
4066 // Save FormBrowser context
4067 //
4068 Context->BannerData = gBannerData;
4069 Context->ClassOfVfr = gClassOfVfr;
4070 Context->FunctionKeySetting = gFunctionKeySetting;
4071 Context->ResetRequired = gResetRequired;
4072 Context->Direction = gDirection;
4073 Context->EnterString = gEnterString;
4074 Context->EnterCommitString = gEnterCommitString;
4075 Context->EnterEscapeString = gEnterEscapeString;
4076 Context->EscapeString = gEscapeString;
4077 Context->MoveHighlight = gMoveHighlight;
4078 Context->MakeSelection = gMakeSelection;
4079 Context->DecNumericInput = gDecNumericInput;
4080 Context->HexNumericInput = gHexNumericInput;
4081 Context->ToggleCheckBox = gToggleCheckBox;
4082 Context->PromptForData = gPromptForData;
4083 Context->PromptForPassword = gPromptForPassword;
4084 Context->PromptForNewPassword = gPromptForNewPassword;
4085 Context->ConfirmPassword = gConfirmPassword;
4086 Context->ConfirmError = gConfirmError;
4087 Context->PassowordInvalid = gPassowordInvalid;
4088 Context->PressEnter = gPressEnter;
4089 Context->EmptyString = gEmptyString;
4090 Context->AreYouSure = gAreYouSure;
4091 Context->YesResponse = gYesResponse;
4092 Context->NoResponse = gNoResponse;
4093 Context->MiniString = gMiniString;
4094 Context->PlusString = gPlusString;
4095 Context->MinusString = gMinusString;
4096 Context->AdjustNumber = gAdjustNumber;
4097 Context->SaveChanges = gSaveChanges;
4098 Context->OptionMismatch = gOptionMismatch;
4099 Context->FormSuppress = gFormSuppress;
4100 Context->PromptBlockWidth = gPromptBlockWidth;
4101 Context->OptionBlockWidth = gOptionBlockWidth;
4102 Context->HelpBlockWidth = gHelpBlockWidth;
4103 Context->OldFormSet = gOldFormSet;
4104 Context->MenuRefreshHead = gMenuRefreshHead;
4105 Context->ProtocolNotFound = gProtocolNotFound;
4106
4107 CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
4108 CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
4109
4110 //
4111 // Insert to FormBrowser context list
4112 //
4113 InsertHeadList (&gBrowserContextList, &Context->Link);
4114 }
4115
4116
4117 /**
4118 Restore globals used by previous call to SendForm().
4119
4120 **/
4121 VOID
4122 RestoreBrowserContext (
4123 VOID
4124 )
4125 {
4126 LIST_ENTRY *Link;
4127 BROWSER_CONTEXT *Context;
4128
4129 ASSERT (gBrowserContextCount != 0);
4130 gBrowserContextCount--;
4131 if (gBrowserContextCount == 0) {
4132 //
4133 // This is not reentry of SendForm(), no context to restore
4134 //
4135 return;
4136 }
4137
4138 ASSERT (!IsListEmpty (&gBrowserContextList));
4139
4140 Link = GetFirstNode (&gBrowserContextList);
4141 Context = BROWSER_CONTEXT_FROM_LINK (Link);
4142
4143 //
4144 // Restore FormBrowser context
4145 //
4146 gBannerData = Context->BannerData;
4147 gClassOfVfr = Context->ClassOfVfr;
4148 gFunctionKeySetting = Context->FunctionKeySetting;
4149 gResetRequired = Context->ResetRequired;
4150 gDirection = Context->Direction;
4151 gEnterString = Context->EnterString;
4152 gEnterCommitString = Context->EnterCommitString;
4153 gEnterEscapeString = Context->EnterEscapeString;
4154 gEscapeString = Context->EscapeString;
4155 gMoveHighlight = Context->MoveHighlight;
4156 gMakeSelection = Context->MakeSelection;
4157 gDecNumericInput = Context->DecNumericInput;
4158 gHexNumericInput = Context->HexNumericInput;
4159 gToggleCheckBox = Context->ToggleCheckBox;
4160 gPromptForData = Context->PromptForData;
4161 gPromptForPassword = Context->PromptForPassword;
4162 gPromptForNewPassword = Context->PromptForNewPassword;
4163 gConfirmPassword = Context->ConfirmPassword;
4164 gConfirmError = Context->ConfirmError;
4165 gPassowordInvalid = Context->PassowordInvalid;
4166 gPressEnter = Context->PressEnter;
4167 gEmptyString = Context->EmptyString;
4168 gAreYouSure = Context->AreYouSure;
4169 gYesResponse = Context->YesResponse;
4170 gNoResponse = Context->NoResponse;
4171 gMiniString = Context->MiniString;
4172 gPlusString = Context->PlusString;
4173 gMinusString = Context->MinusString;
4174 gAdjustNumber = Context->AdjustNumber;
4175 gSaveChanges = Context->SaveChanges;
4176 gOptionMismatch = Context->OptionMismatch;
4177 gFormSuppress = Context->FormSuppress;
4178 gPromptBlockWidth = Context->PromptBlockWidth;
4179 gOptionBlockWidth = Context->OptionBlockWidth;
4180 gHelpBlockWidth = Context->HelpBlockWidth;
4181 gOldFormSet = Context->OldFormSet;
4182 gMenuRefreshHead = Context->MenuRefreshHead;
4183 gProtocolNotFound = Context->ProtocolNotFound;
4184
4185 CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
4186 CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
4187
4188 //
4189 // Remove from FormBrowser context list
4190 //
4191 RemoveEntryList (&Context->Link);
4192 gBS->FreePool (Context);
4193 }
4194
4195 /**
4196 Find the matched FormSet context in the backup maintain list based on HiiHandle.
4197
4198 @param Handle The Hii Handle.
4199
4200 @return the found FormSet context. If no found, NULL will return.
4201
4202 **/
4203 FORM_BROWSER_FORMSET *
4204 GetFormSetFromHiiHandle (
4205 EFI_HII_HANDLE Handle
4206 )
4207 {
4208 LIST_ENTRY *Link;
4209 FORM_BROWSER_FORMSET *FormSet;
4210
4211 Link = GetFirstNode (&gBrowserFormSetList);
4212 while (!IsNull (&gBrowserFormSetList, Link)) {
4213 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
4214 Link = GetNextNode (&gBrowserFormSetList, Link);
4215 if (!ValidateFormSet(FormSet)) {
4216 continue;
4217 }
4218 if (FormSet->HiiHandle == Handle) {
4219 return FormSet;
4220 }
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 Link = GetNextNode (&gBrowserFormSetList, Link);
4474 if (!ValidateFormSet(FormSet)) {
4475 continue;
4476 }
4477 if (IsNvUpdateRequired (FormSet)) {
4478 IsDataChanged = TRUE;
4479 break;
4480 }
4481 }
4482
4483 //
4484 // No data is changed. No save is required.
4485 //
4486 if (!IsDataChanged) {
4487 return DataSavedAction;
4488 }
4489
4490 //
4491 // If data is changed, prompt user
4492 //
4493 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
4494
4495 YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);
4496 ASSERT (YesResponse != NULL);
4497 NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);
4498 ASSERT (NoResponse != NULL);
4499 EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
4500 ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);
4501 SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);
4502
4503 do {
4504 CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);
4505 } while
4506 (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&
4507 ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))
4508 );
4509
4510 //
4511 // If the user hits the YesResponse key
4512 //
4513 if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {
4514 SubmitForm (NULL, NULL, SystemLevel);
4515 DataSavedAction = BROWSER_SAVE_CHANGES;
4516 } else {
4517 DiscardForm (NULL, NULL, SystemLevel);
4518 DataSavedAction = BROWSER_DISCARD_CHANGES;
4519 gResetRequired = FALSE;
4520 }
4521
4522 FreePool (YesResponse);
4523 FreePool (NoResponse);
4524 FreePool (EmptyString);
4525 FreePool (SaveConfirmString);
4526 FreePool (ChangeReminderString);
4527
4528 return DataSavedAction;
4529 }