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