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