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