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