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