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