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