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