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