]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
Add some security check.
[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 Value = NULL;
1142 Status = GetValueByName (Storage, Question->VariableName, &Value);
1143 if (EFI_ERROR (Status)) {
1144 return Status;
1145 }
1146
1147 ASSERT (Value != NULL);
1148 LengthStr = StrLen (Value);
1149 Status = EFI_SUCCESS;
1150 if (IsString) {
1151 //
1152 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1153 // Add string tail char L'\0' into Length
1154 //
1155 Length = StorageWidth + sizeof (CHAR16);
1156 if (Length < ((LengthStr / 4 + 1) * 2)) {
1157 Status = EFI_BUFFER_TOO_SMALL;
1158 } else {
1159 StringPtr = (CHAR16 *) Dst;
1160 ZeroMem (TemStr, sizeof (TemStr));
1161 for (Index = 0; Index < LengthStr; Index += 4) {
1162 StrnCpy (TemStr, Value + Index, 4);
1163 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1164 }
1165 //
1166 // Add tailing L'\0' character
1167 //
1168 StringPtr[Index/4] = L'\0';
1169 }
1170 } else {
1171 if (StorageWidth < ((LengthStr + 1) / 2)) {
1172 Status = EFI_BUFFER_TOO_SMALL;
1173 } else {
1174 ZeroMem (TemStr, sizeof (TemStr));
1175 for (Index = 0; Index < LengthStr; Index ++) {
1176 TemStr[0] = Value[LengthStr - Index - 1];
1177 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1178 if ((Index & 1) == 0) {
1179 Dst [Index/2] = DigitUint8;
1180 } else {
1181 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1182 }
1183 }
1184 }
1185 }
1186
1187 FreePool (Value);
1188 }
1189 } else {
1190 //
1191 // Request current settings from Configuration Driver
1192 //
1193 if (FormSet->ConfigAccess == NULL) {
1194 return EFI_NOT_FOUND;
1195 }
1196
1197 //
1198 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
1199 // <ConfigHdr> + "&" + <VariableName>
1200 //
1201 if (IsBufferStorage) {
1202 Length = StrLen (Storage->ConfigHdr);
1203 Length += StrLen (Question->BlockName);
1204 } else {
1205 Length = StrLen (Storage->ConfigHdr);
1206 Length += StrLen (Question->VariableName) + 1;
1207 }
1208 ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
1209 ASSERT (ConfigRequest != NULL);
1210
1211 StrCpy (ConfigRequest, Storage->ConfigHdr);
1212 if (IsBufferStorage) {
1213 StrCat (ConfigRequest, Question->BlockName);
1214 } else {
1215 StrCat (ConfigRequest, L"&");
1216 StrCat (ConfigRequest, Question->VariableName);
1217 }
1218
1219 Status = FormSet->ConfigAccess->ExtractConfig (
1220 FormSet->ConfigAccess,
1221 ConfigRequest,
1222 &Progress,
1223 &Result
1224 );
1225 if (EFI_ERROR (Status)) {
1226 return Status;
1227 }
1228
1229 //
1230 // Skip <ConfigRequest>
1231 //
1232 Value = Result + Length;
1233 if (IsBufferStorage) {
1234 //
1235 // Skip "&VALUE"
1236 //
1237 Value = Value + 6;
1238 }
1239 if (*Value != '=') {
1240 FreePool (Result);
1241 return EFI_NOT_FOUND;
1242 }
1243 //
1244 // Skip '=', point to value
1245 //
1246 Value = Value + 1;
1247
1248 //
1249 // Suppress <AltResp> if any
1250 //
1251 StringPtr = Value;
1252 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1253 StringPtr++;
1254 }
1255 *StringPtr = L'\0';
1256
1257 LengthStr = StrLen (Value);
1258 Status = EFI_SUCCESS;
1259 if (!IsBufferStorage && IsString) {
1260 //
1261 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
1262 // Add string tail char L'\0' into Length
1263 //
1264 Length = StorageWidth + sizeof (CHAR16);
1265 if (Length < ((LengthStr / 4 + 1) * 2)) {
1266 Status = EFI_BUFFER_TOO_SMALL;
1267 } else {
1268 StringPtr = (CHAR16 *) Dst;
1269 ZeroMem (TemStr, sizeof (TemStr));
1270 for (Index = 0; Index < LengthStr; Index += 4) {
1271 StrnCpy (TemStr, Value + Index, 4);
1272 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
1273 }
1274 //
1275 // Add tailing L'\0' character
1276 //
1277 StringPtr[Index/4] = L'\0';
1278 }
1279 } else {
1280 if (StorageWidth < ((LengthStr + 1) / 2)) {
1281 Status = EFI_BUFFER_TOO_SMALL;
1282 } else {
1283 ZeroMem (TemStr, sizeof (TemStr));
1284 for (Index = 0; Index < LengthStr; Index ++) {
1285 TemStr[0] = Value[LengthStr - Index - 1];
1286 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1287 if ((Index & 1) == 0) {
1288 Dst [Index/2] = DigitUint8;
1289 } else {
1290 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
1291 }
1292 }
1293 }
1294 }
1295
1296 if (EFI_ERROR (Status)) {
1297 FreePool (Result);
1298 return Status;
1299 }
1300
1301 //
1302 // Synchronize Edit Buffer
1303 //
1304 if (IsBufferStorage) {
1305 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
1306 } else {
1307 SetValueByName (Storage, Question->VariableName, Value);
1308 }
1309
1310 FreePool (Result);
1311 }
1312
1313 return Status;
1314 }
1315
1316
1317 /**
1318 Save Question Value to edit copy(cached) or Storage(uncached).
1319
1320 @param FormSet FormSet data structure.
1321 @param Form Form data structure.
1322 @param Question Pointer to the Question.
1323 @param Cached TRUE: set to Edit copy FALSE: set to original
1324 Storage
1325
1326 @retval EFI_SUCCESS The function completed successfully.
1327
1328 **/
1329 EFI_STATUS
1330 SetQuestionValue (
1331 IN FORM_BROWSER_FORMSET *FormSet,
1332 IN FORM_BROWSER_FORM *Form,
1333 IN OUT FORM_BROWSER_STATEMENT *Question,
1334 IN BOOLEAN Cached
1335 )
1336 {
1337 EFI_STATUS Status;
1338 BOOLEAN Enabled;
1339 BOOLEAN Pending;
1340 UINT8 *Src;
1341 EFI_TIME EfiTime;
1342 UINTN BufferLen;
1343 UINTN StorageWidth;
1344 FORMSET_STORAGE *Storage;
1345 EFI_IFR_TYPE_VALUE *QuestionValue;
1346 CHAR16 *ConfigResp;
1347 CHAR16 *Progress;
1348 CHAR16 *Value;
1349 UINTN Length;
1350 BOOLEAN IsBufferStorage;
1351 BOOLEAN IsString;
1352 UINT8 *TemBuffer;
1353 CHAR16 *TemName;
1354 CHAR16 *TemString;
1355 UINTN Index;
1356
1357 Status = EFI_SUCCESS;
1358
1359 //
1360 // Statement don't have storage, skip them
1361 //
1362 if (Question->QuestionId == 0) {
1363 return Status;
1364 }
1365
1366 //
1367 // If Question value is provided by an Expression, then it is read only
1368 //
1369 if (Question->ValueExpression != NULL) {
1370 return Status;
1371 }
1372
1373 //
1374 // Question value is provided by RTC
1375 //
1376 Storage = Question->Storage;
1377 QuestionValue = &Question->HiiValue.Value;
1378 if (Storage == NULL) {
1379 //
1380 // It's a Question without storage, or RTC date/time
1381 //
1382 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
1383 //
1384 // Date and time define the same Flags bit
1385 //
1386 switch (Question->Flags & EFI_QF_DATE_STORAGE) {
1387 case QF_DATE_STORAGE_TIME:
1388 Status = gRT->GetTime (&EfiTime, NULL);
1389 break;
1390
1391 case QF_DATE_STORAGE_WAKEUP:
1392 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
1393 break;
1394
1395 case QF_DATE_STORAGE_NORMAL:
1396 default:
1397 //
1398 // For date/time without storage
1399 //
1400 return EFI_SUCCESS;
1401 }
1402
1403 if (EFI_ERROR (Status)) {
1404 return Status;
1405 }
1406
1407 if (Question->Operand == EFI_IFR_DATE_OP) {
1408 EfiTime.Year = QuestionValue->date.Year;
1409 EfiTime.Month = QuestionValue->date.Month;
1410 EfiTime.Day = QuestionValue->date.Day;
1411 } else {
1412 EfiTime.Hour = QuestionValue->time.Hour;
1413 EfiTime.Minute = QuestionValue->time.Minute;
1414 EfiTime.Second = QuestionValue->time.Second;
1415 }
1416
1417 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
1418 Status = gRT->SetTime (&EfiTime);
1419 } else {
1420 Status = gRT->SetWakeupTime (TRUE, &EfiTime);
1421 }
1422 }
1423
1424 return Status;
1425 }
1426
1427 //
1428 // Question value is provided by EFI variable
1429 //
1430 StorageWidth = Question->StorageWidth;
1431 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1432 if (Question->BufferValue != NULL) {
1433 Src = Question->BufferValue;
1434 } else {
1435 Src = (UINT8 *) QuestionValue;
1436 }
1437
1438 Status = gRT->SetVariable (
1439 Question->VariableName,
1440 &Storage->Guid,
1441 Storage->Attributes,
1442 StorageWidth,
1443 Src
1444 );
1445 return Status;
1446 }
1447
1448 //
1449 // Question Value is provided by Buffer Storage or NameValue Storage
1450 //
1451 if (Question->BufferValue != NULL) {
1452 Src = Question->BufferValue;
1453 } else {
1454 Src = (UINT8 *) &Question->HiiValue.Value;
1455 }
1456
1457 IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
1458 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE);
1459 if (IsBufferStorage) {
1460 //
1461 // Copy to storage edit buffer
1462 //
1463 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
1464 } else {
1465 if (IsString) {
1466 //
1467 // Allocate enough string buffer.
1468 //
1469 Value = NULL;
1470 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
1471 Value = AllocateZeroPool (BufferLen);
1472 ASSERT (Value != NULL);
1473 //
1474 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1475 //
1476 TemName = (CHAR16 *) Src;
1477 TemString = Value;
1478 for (; *TemName != L'\0'; TemName++) {
1479 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1480 }
1481 } else {
1482 BufferLen = StorageWidth * 2 + 1;
1483 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
1484 ASSERT (Value != NULL);
1485 //
1486 // Convert Buffer to Hex String
1487 //
1488 TemBuffer = Src + StorageWidth - 1;
1489 TemString = Value;
1490 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1491 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1492 }
1493 }
1494
1495 Status = SetValueByName (Storage, Question->VariableName, Value);
1496 FreePool (Value);
1497 }
1498
1499 if (!Cached) {
1500 //
1501 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
1502 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
1503 //
1504 if (IsBufferStorage) {
1505 Length = StrLen (Question->BlockName) + 7;
1506 } else {
1507 Length = StrLen (Question->VariableName) + 2;
1508 }
1509 if (!IsBufferStorage && IsString) {
1510 Length += (StrLen ((CHAR16 *) Src) * 4);
1511 } else {
1512 Length += (StorageWidth * 2);
1513 }
1514 ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
1515 ASSERT (ConfigResp != NULL);
1516
1517 StrCpy (ConfigResp, Storage->ConfigHdr);
1518 if (IsBufferStorage) {
1519 StrCat (ConfigResp, Question->BlockName);
1520 StrCat (ConfigResp, L"&VALUE=");
1521 } else {
1522 StrCat (ConfigResp, L"&");
1523 StrCat (ConfigResp, Question->VariableName);
1524 StrCat (ConfigResp, L"=");
1525 }
1526
1527 Value = ConfigResp + StrLen (ConfigResp);
1528
1529 if (!IsBufferStorage && IsString) {
1530 //
1531 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
1532 //
1533 TemName = (CHAR16 *) Src;
1534 TemString = Value;
1535 for (; *TemName != L'\0'; TemName++) {
1536 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
1537 }
1538 } else {
1539 //
1540 // Convert Buffer to Hex String
1541 //
1542 TemBuffer = Src + StorageWidth - 1;
1543 TemString = Value;
1544 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
1545 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1546 }
1547 }
1548
1549 //
1550 // Convert to lower char.
1551 //
1552 for (TemString = Value; *Value != L'\0'; Value++) {
1553 if (*Value >= L'A' && *Value <= L'Z') {
1554 *Value = (CHAR16) (*Value - L'A' + L'a');
1555 }
1556 }
1557
1558 //
1559 // Submit Question Value to Configuration Driver
1560 //
1561 if (FormSet->ConfigAccess != NULL) {
1562 Status = FormSet->ConfigAccess->RouteConfig (
1563 FormSet->ConfigAccess,
1564 ConfigResp,
1565 &Progress
1566 );
1567 if (EFI_ERROR (Status)) {
1568 FreePool (ConfigResp);
1569 return Status;
1570 }
1571 }
1572 FreePool (ConfigResp);
1573
1574 //
1575 // Synchronize shadow Buffer
1576 //
1577 SynchronizeStorage (Storage);
1578 }
1579
1580 return Status;
1581 }
1582
1583
1584 /**
1585 Perform inconsistent check for a Form.
1586
1587 @param FormSet FormSet data structure.
1588 @param Form Form data structure.
1589 @param Question The Question to be validated.
1590 @param Type Validation type: InConsistent or NoSubmit
1591
1592 @retval EFI_SUCCESS Form validation pass.
1593 @retval other Form validation failed.
1594
1595 **/
1596 EFI_STATUS
1597 ValidateQuestion (
1598 IN FORM_BROWSER_FORMSET *FormSet,
1599 IN FORM_BROWSER_FORM *Form,
1600 IN FORM_BROWSER_STATEMENT *Question,
1601 IN UINTN Type
1602 )
1603 {
1604 EFI_STATUS Status;
1605 LIST_ENTRY *Link;
1606 LIST_ENTRY *ListHead;
1607 EFI_STRING PopUp;
1608 EFI_INPUT_KEY Key;
1609 FORM_EXPRESSION *Expression;
1610
1611 if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {
1612 ListHead = &Question->InconsistentListHead;
1613 } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
1614 ListHead = &Question->NoSubmitListHead;
1615 } else {
1616 return EFI_UNSUPPORTED;
1617 }
1618
1619 Link = GetFirstNode (ListHead);
1620 while (!IsNull (ListHead, Link)) {
1621 Expression = FORM_EXPRESSION_FROM_LINK (Link);
1622
1623 //
1624 // Evaluate the expression
1625 //
1626 Status = EvaluateExpression (FormSet, Form, Expression);
1627 if (EFI_ERROR (Status)) {
1628 return Status;
1629 }
1630
1631 if (Expression->Result.Value.b) {
1632 //
1633 // Condition meet, show up error message
1634 //
1635 if (Expression->Error != 0) {
1636 PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
1637 do {
1638 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);
1639 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1640 FreePool (PopUp);
1641 }
1642
1643 return EFI_NOT_READY;
1644 }
1645
1646 Link = GetNextNode (ListHead, Link);
1647 }
1648
1649 return EFI_SUCCESS;
1650 }
1651
1652
1653 /**
1654 Perform NoSubmit check for a Form.
1655
1656 @param FormSet FormSet data structure.
1657 @param Form Form data structure.
1658
1659 @retval EFI_SUCCESS Form validation pass.
1660 @retval other Form validation failed.
1661
1662 **/
1663 EFI_STATUS
1664 NoSubmitCheck (
1665 IN FORM_BROWSER_FORMSET *FormSet,
1666 IN FORM_BROWSER_FORM *Form
1667 )
1668 {
1669 EFI_STATUS Status;
1670 LIST_ENTRY *Link;
1671 FORM_BROWSER_STATEMENT *Question;
1672
1673 Link = GetFirstNode (&Form->StatementListHead);
1674 while (!IsNull (&Form->StatementListHead, Link)) {
1675 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1676
1677 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
1678 if (EFI_ERROR (Status)) {
1679 return Status;
1680 }
1681
1682 Link = GetNextNode (&Form->StatementListHead, Link);
1683 }
1684
1685 return EFI_SUCCESS;
1686 }
1687
1688
1689 /**
1690 Submit a Form.
1691
1692 @param FormSet FormSet data structure.
1693 @param Form Form data structure.
1694
1695 @retval EFI_SUCCESS The function completed successfully.
1696
1697 **/
1698 EFI_STATUS
1699 SubmitForm (
1700 IN FORM_BROWSER_FORMSET *FormSet,
1701 IN FORM_BROWSER_FORM *Form
1702 )
1703 {
1704 EFI_STATUS Status;
1705 LIST_ENTRY *Link;
1706 EFI_STRING ConfigResp;
1707 EFI_STRING Progress;
1708 FORMSET_STORAGE *Storage;
1709
1710 //
1711 // Validate the Form by NoSubmit check
1712 //
1713 Status = NoSubmitCheck (FormSet, Form);
1714 if (EFI_ERROR (Status)) {
1715 return Status;
1716 }
1717
1718 //
1719 // Submit Buffer storage or Name/Value storage
1720 //
1721 Link = GetFirstNode (&FormSet->StorageListHead);
1722 while (!IsNull (&FormSet->StorageListHead, Link)) {
1723 Storage = FORMSET_STORAGE_FROM_LINK (Link);
1724 Link = GetNextNode (&FormSet->StorageListHead, Link);
1725
1726 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
1727 continue;
1728 }
1729
1730 //
1731 // Skip if there is no RequestElement
1732 //
1733 if (Storage->ElementCount == 0) {
1734 continue;
1735 }
1736
1737 //
1738 // Prepare <ConfigResp>
1739 //
1740 Status = StorageToConfigResp (Storage, &ConfigResp);
1741 if (EFI_ERROR (Status)) {
1742 return Status;
1743 }
1744
1745 //
1746 // Send <ConfigResp> to Configuration Driver
1747 //
1748 if (FormSet->ConfigAccess != NULL) {
1749 Status = FormSet->ConfigAccess->RouteConfig (
1750 FormSet->ConfigAccess,
1751 ConfigResp,
1752 &Progress
1753 );
1754 if (EFI_ERROR (Status)) {
1755 FreePool (ConfigResp);
1756 return Status;
1757 }
1758 }
1759 FreePool (ConfigResp);
1760
1761 //
1762 // Config success, update storage shadow Buffer
1763 //
1764 SynchronizeStorage (Storage);
1765 }
1766
1767 gNvUpdateRequired = FALSE;
1768
1769 return EFI_SUCCESS;
1770 }
1771
1772
1773 /**
1774 Reset Question to its default value.
1775
1776 @param FormSet The form set.
1777 @param Form The form.
1778 @param Question The question.
1779 @param DefaultId The Class of the default.
1780
1781 @retval EFI_SUCCESS Question is reset to default value.
1782
1783 **/
1784 EFI_STATUS
1785 GetQuestionDefault (
1786 IN FORM_BROWSER_FORMSET *FormSet,
1787 IN FORM_BROWSER_FORM *Form,
1788 IN FORM_BROWSER_STATEMENT *Question,
1789 IN UINT16 DefaultId
1790 )
1791 {
1792 EFI_STATUS Status;
1793 LIST_ENTRY *Link;
1794 QUESTION_DEFAULT *Default;
1795 QUESTION_OPTION *Option;
1796 EFI_HII_VALUE *HiiValue;
1797 UINT8 Index;
1798 EFI_STRING StrValue;
1799
1800 Status = EFI_SUCCESS;
1801 StrValue = NULL;
1802
1803 //
1804 // Statement don't have storage, skip them
1805 //
1806 if (Question->QuestionId == 0) {
1807 return Status;
1808 }
1809
1810 //
1811 // There are three ways to specify default value for a Question:
1812 // 1, use nested EFI_IFR_DEFAULT (highest priority)
1813 // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
1814 // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
1815 //
1816 HiiValue = &Question->HiiValue;
1817
1818 //
1819 // EFI_IFR_DEFAULT has highest priority
1820 //
1821 if (!IsListEmpty (&Question->DefaultListHead)) {
1822 Link = GetFirstNode (&Question->DefaultListHead);
1823 while (!IsNull (&Question->DefaultListHead, Link)) {
1824 Default = QUESTION_DEFAULT_FROM_LINK (Link);
1825
1826 if (Default->DefaultId == DefaultId) {
1827 if (Default->ValueExpression != NULL) {
1828 //
1829 // Default is provided by an Expression, evaluate it
1830 //
1831 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
1832 if (EFI_ERROR (Status)) {
1833 return Status;
1834 }
1835
1836 CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE));
1837 } else {
1838 //
1839 // Default value is embedded in EFI_IFR_DEFAULT
1840 //
1841 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
1842 }
1843
1844 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
1845 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
1846 if (StrValue == NULL) {
1847 return EFI_NOT_FOUND;
1848 }
1849 Question->BufferValue = AllocateCopyPool (StrSize (StrValue), StrValue);
1850 }
1851
1852 return EFI_SUCCESS;
1853 }
1854
1855 Link = GetNextNode (&Question->DefaultListHead, Link);
1856 }
1857 }
1858
1859 //
1860 // EFI_ONE_OF_OPTION
1861 //
1862 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
1863 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
1864 //
1865 // OneOfOption could only provide Standard and Manufacturing default
1866 //
1867 Link = GetFirstNode (&Question->OptionListHead);
1868 while (!IsNull (&Question->OptionListHead, Link)) {
1869 Option = QUESTION_OPTION_FROM_LINK (Link);
1870
1871 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
1872 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
1873 ) {
1874 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
1875
1876 return EFI_SUCCESS;
1877 }
1878
1879 Link = GetNextNode (&Question->OptionListHead, Link);
1880 }
1881 }
1882 }
1883
1884 //
1885 // EFI_IFR_CHECKBOX - lowest priority
1886 //
1887 if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
1888 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
1889 //
1890 // Checkbox could only provide Standard and Manufacturing default
1891 //
1892 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
1893 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
1894 ) {
1895 HiiValue->Value.b = TRUE;
1896 } else {
1897 HiiValue->Value.b = FALSE;
1898 }
1899
1900 return EFI_SUCCESS;
1901 }
1902 }
1903
1904 //
1905 // For Questions without default
1906 //
1907 switch (Question->Operand) {
1908 case EFI_IFR_ONE_OF_OP:
1909 //
1910 // Take first oneof option as oneof's default value
1911 //
1912 if (ValueToOption (Question, HiiValue) == NULL) {
1913 Link = GetFirstNode (&Question->OptionListHead);
1914 if (!IsNull (&Question->OptionListHead, Link)) {
1915 Option = QUESTION_OPTION_FROM_LINK (Link);
1916 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
1917 }
1918 }
1919 break;
1920
1921 case EFI_IFR_ORDERED_LIST_OP:
1922 //
1923 // Take option sequence in IFR as ordered list's default value
1924 //
1925 Index = 0;
1926 Link = GetFirstNode (&Question->OptionListHead);
1927 while (!IsNull (&Question->OptionListHead, Link)) {
1928 Option = QUESTION_OPTION_FROM_LINK (Link);
1929
1930 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
1931
1932 Index++;
1933 if (Index >= Question->MaxContainers) {
1934 break;
1935 }
1936
1937 Link = GetNextNode (&Question->OptionListHead, Link);
1938 }
1939 break;
1940
1941 default:
1942 Status = EFI_NOT_FOUND;
1943 break;
1944 }
1945
1946 return Status;
1947 }
1948
1949
1950 /**
1951 Reset Questions in a Form to their default value.
1952
1953 @param FormSet FormSet data structure.
1954 @param Form The Form which to be reset.
1955 @param DefaultId The Class of the default.
1956
1957 @retval EFI_SUCCESS The function completed successfully.
1958
1959 **/
1960 EFI_STATUS
1961 ExtractFormDefault (
1962 IN FORM_BROWSER_FORMSET *FormSet,
1963 IN FORM_BROWSER_FORM *Form,
1964 IN UINT16 DefaultId
1965 )
1966 {
1967 EFI_STATUS Status;
1968 LIST_ENTRY *Link;
1969 FORM_BROWSER_STATEMENT *Question;
1970
1971 Link = GetFirstNode (&Form->StatementListHead);
1972 while (!IsNull (&Form->StatementListHead, Link)) {
1973 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1974 Link = GetNextNode (&Form->StatementListHead, Link);
1975
1976 //
1977 // If Question is disabled, don't reset it to default
1978 //
1979 if (Question->DisableExpression != NULL) {
1980 Status = EvaluateExpression (FormSet, Form, Question->DisableExpression);
1981 if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b) {
1982 continue;
1983 }
1984 }
1985
1986 //
1987 // Reset Question to its default value
1988 //
1989 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
1990 if (EFI_ERROR (Status)) {
1991 continue;
1992 }
1993
1994 //
1995 // Synchronize Buffer storage's Edit buffer
1996 //
1997 if ((Question->Storage != NULL) &&
1998 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
1999 SetQuestionValue (FormSet, Form, Question, TRUE);
2000 }
2001 }
2002
2003 return EFI_SUCCESS;
2004 }
2005
2006 /**
2007 Initialize Question's Edit copy from Storage.
2008
2009 @param Selection Selection contains the information about
2010 the Selection, form and formset to be displayed.
2011 Selection action may be updated in retrieve callback.
2012 @param FormSet FormSet data structure.
2013 @param Form Form data structure.
2014
2015 @retval EFI_SUCCESS The function completed successfully.
2016
2017 **/
2018 EFI_STATUS
2019 LoadFormConfig (
2020 IN OUT UI_MENU_SELECTION *Selection,
2021 IN FORM_BROWSER_FORMSET *FormSet,
2022 IN FORM_BROWSER_FORM *Form
2023 )
2024 {
2025 EFI_STATUS Status;
2026 LIST_ENTRY *Link;
2027 FORM_BROWSER_STATEMENT *Question;
2028 UINT8 *BufferValue;
2029 UINTN StorageWidth;
2030 EFI_HII_VALUE *HiiValue;
2031 EFI_BROWSER_ACTION_REQUEST ActionRequest;
2032
2033 Link = GetFirstNode (&Form->StatementListHead);
2034 while (!IsNull (&Form->StatementListHead, Link)) {
2035 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
2036
2037 //
2038 // Initialize local copy of Value for each Question
2039 //
2040 Status = GetQuestionValue (FormSet, Form, Question, TRUE);
2041 if (EFI_ERROR (Status)) {
2042 return Status;
2043 }
2044
2045 //
2046 // Check whether EfiVarstore with CallBack can be got.
2047 //
2048 if ((Question->QuestionId != 0) && (Question->Storage != NULL) &&
2049 (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) &&
2050 ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
2051 //
2052 // ConfigAccess can't be NULL.
2053 //
2054 if (FormSet->ConfigAccess == NULL) {
2055 return EFI_UNSUPPORTED;
2056 }
2057 //
2058 // Check QuestionValue does exist.
2059 //
2060 StorageWidth = Question->StorageWidth;
2061 if (Question->BufferValue != NULL) {
2062 BufferValue = Question->BufferValue;
2063 } else {
2064 BufferValue = (UINT8 *) &Question->HiiValue.Value;
2065 }
2066 Status = gRT->GetVariable (
2067 Question->VariableName,
2068 &Question->Storage->Guid,
2069 NULL,
2070 &StorageWidth,
2071 BufferValue
2072 );
2073
2074 if (!EFI_ERROR (Status)) {
2075 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2076 HiiValue = &Question->HiiValue;
2077 BufferValue = (UINT8 *) &Question->HiiValue.Value;
2078 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2079 //
2080 // Create String in HII database for Configuration Driver to retrieve
2081 //
2082 HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, FormSet->HiiHandle);
2083 } else if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2084 BufferValue = Question->BufferValue;
2085 }
2086
2087 Status = FormSet->ConfigAccess->Callback (
2088 FormSet->ConfigAccess,
2089 EFI_BROWSER_ACTION_RETRIEVE,
2090 Question->QuestionId,
2091 HiiValue->Type,
2092 (EFI_IFR_TYPE_VALUE *) BufferValue,
2093 &ActionRequest
2094 );
2095
2096 if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2097 //
2098 // Clean the String in HII Database
2099 //
2100 DeleteString (HiiValue->Value.string, FormSet->HiiHandle);
2101 }
2102
2103 if (!EFI_ERROR (Status)) {
2104 switch (ActionRequest) {
2105 case EFI_BROWSER_ACTION_REQUEST_RESET:
2106 gResetRequired = TRUE;
2107 break;
2108
2109 case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2110 //
2111 // Till now there is no uncommitted data, so ignore this request
2112 //
2113 break;
2114
2115 case EFI_BROWSER_ACTION_REQUEST_EXIT:
2116 Selection->Action = UI_ACTION_EXIT;
2117 break;
2118
2119 default:
2120 break;
2121 }
2122 }
2123 }
2124 }
2125
2126 Link = GetNextNode (&Form->StatementListHead, Link);
2127 }
2128
2129 return EFI_SUCCESS;
2130 }
2131
2132 /**
2133 Initialize Question's Edit copy from Storage for the whole Formset.
2134
2135 @param Selection Selection contains the information about
2136 the Selection, form and formset to be displayed.
2137 Selection action may be updated in retrieve callback.
2138 @param FormSet FormSet data structure.
2139
2140 @retval EFI_SUCCESS The function completed successfully.
2141
2142 **/
2143 EFI_STATUS
2144 LoadFormSetConfig (
2145 IN OUT UI_MENU_SELECTION *Selection,
2146 IN FORM_BROWSER_FORMSET *FormSet
2147 )
2148 {
2149 EFI_STATUS Status;
2150 LIST_ENTRY *Link;
2151 FORM_BROWSER_FORM *Form;
2152
2153 Link = GetFirstNode (&FormSet->FormListHead);
2154 while (!IsNull (&FormSet->FormListHead, Link)) {
2155 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2156
2157 //
2158 // Initialize local copy of Value for each Form
2159 //
2160 Status = LoadFormConfig (Selection, FormSet, Form);
2161 if (EFI_ERROR (Status)) {
2162 return Status;
2163 }
2164
2165 Link = GetNextNode (&FormSet->FormListHead, Link);
2166 }
2167
2168 return EFI_SUCCESS;
2169 }
2170
2171 /**
2172 Fill storage's edit copy with settings requested from Configuration Driver.
2173
2174 @param FormSet FormSet data structure.
2175 @param Storage Buffer Storage.
2176
2177 @retval EFI_SUCCESS The function completed successfully.
2178
2179 **/
2180 EFI_STATUS
2181 LoadStorage (
2182 IN FORM_BROWSER_FORMSET *FormSet,
2183 IN FORMSET_STORAGE *Storage
2184 )
2185 {
2186 EFI_STATUS Status;
2187 EFI_STRING Progress;
2188 EFI_STRING Result;
2189 CHAR16 *StrPtr;
2190
2191 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
2192 return EFI_SUCCESS;
2193 }
2194
2195 if (FormSet->ConfigAccess == NULL) {
2196 return EFI_NOT_FOUND;
2197 }
2198
2199 if (Storage->ElementCount == 0) {
2200 //
2201 // Skip if there is no RequestElement
2202 //
2203 return EFI_SUCCESS;
2204 }
2205
2206 //
2207 // Request current settings from Configuration Driver
2208 //
2209 Status = FormSet->ConfigAccess->ExtractConfig (
2210 FormSet->ConfigAccess,
2211 Storage->ConfigRequest,
2212 &Progress,
2213 &Result
2214 );
2215 if (EFI_ERROR (Status)) {
2216 return Status;
2217 }
2218
2219 //
2220 // Convert Result from <ConfigAltResp> to <ConfigResp>
2221 //
2222 StrPtr = StrStr (Result, L"ALTCFG");
2223 if (StrPtr != NULL) {
2224 *StrPtr = L'\0';
2225 }
2226
2227 Status = ConfigRespToStorage (Storage, Result);
2228 FreePool (Result);
2229 return Status;
2230 }
2231
2232
2233 /**
2234 Copy uncommitted data from source Storage to destination Storage.
2235
2236 @param Dst Target Storage for uncommitted data.
2237 @param Src Source Storage for uncommitted data.
2238
2239 @retval EFI_SUCCESS The function completed successfully.
2240 @retval EFI_INVALID_PARAMETER Source and destination Storage is not the same type.
2241
2242 **/
2243 EFI_STATUS
2244 CopyStorage (
2245 IN OUT FORMSET_STORAGE *Dst,
2246 IN FORMSET_STORAGE *Src
2247 )
2248 {
2249 LIST_ENTRY *Link;
2250 NAME_VALUE_NODE *Node;
2251
2252 if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {
2253 return EFI_INVALID_PARAMETER;
2254 }
2255
2256 switch (Src->Type) {
2257 case EFI_HII_VARSTORE_BUFFER:
2258 CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);
2259 break;
2260
2261 case EFI_HII_VARSTORE_NAME_VALUE:
2262 Link = GetFirstNode (&Src->NameValueListHead);
2263 while (!IsNull (&Src->NameValueListHead, Link)) {
2264 Node = NAME_VALUE_NODE_FROM_LINK (Link);
2265
2266 SetValueByName (Dst, Node->Name, Node->EditValue);
2267
2268 Link = GetNextNode (&Src->NameValueListHead, Link);
2269 }
2270 break;
2271
2272 case EFI_HII_VARSTORE_EFI_VARIABLE:
2273 default:
2274 break;
2275 }
2276
2277 return EFI_SUCCESS;
2278 }
2279
2280
2281 /**
2282 Get current setting of Questions.
2283
2284 @param FormSet FormSet data structure.
2285
2286 @retval EFI_SUCCESS The function completed successfully.
2287
2288 **/
2289 EFI_STATUS
2290 InitializeCurrentSetting (
2291 IN OUT FORM_BROWSER_FORMSET *FormSet
2292 )
2293 {
2294 LIST_ENTRY *Link;
2295 LIST_ENTRY *Link2;
2296 FORMSET_STORAGE *Storage;
2297 FORMSET_STORAGE *StorageSrc;
2298 FORMSET_STORAGE *OldStorage;
2299 FORM_BROWSER_FORM *Form;
2300 EFI_STATUS Status;
2301
2302 //
2303 // Extract default from IFR binary
2304 //
2305 Link = GetFirstNode (&FormSet->FormListHead);
2306 while (!IsNull (&FormSet->FormListHead, Link)) {
2307 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2308
2309 Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD);
2310
2311 Link = GetNextNode (&FormSet->FormListHead, Link);
2312 }
2313
2314 //
2315 // Request current settings from Configuration Driver
2316 //
2317 Link = GetFirstNode (&FormSet->StorageListHead);
2318 while (!IsNull (&FormSet->StorageListHead, Link)) {
2319 Storage = FORMSET_STORAGE_FROM_LINK (Link);
2320
2321 OldStorage = NULL;
2322 if (gOldFormSet != NULL) {
2323 //
2324 // Try to find the Storage in backup formset gOldFormSet
2325 //
2326 Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
2327 while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
2328 StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
2329
2330 if (StorageSrc->VarStoreId == Storage->VarStoreId) {
2331 OldStorage = StorageSrc;
2332 break;
2333 }
2334
2335 Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
2336 }
2337 }
2338
2339 if (OldStorage == NULL) {
2340 //
2341 // Storage is not found in backup formset, request it from ConfigDriver
2342 //
2343 Status = LoadStorage (FormSet, Storage);
2344 } else {
2345 //
2346 // Storage found in backup formset, use it
2347 //
2348 Status = CopyStorage (Storage, OldStorage);
2349 }
2350
2351 //
2352 // Now Edit Buffer is filled with default values(lower priority) and current
2353 // settings(higher priority), sychronize it to shadow Buffer
2354 //
2355 if (!EFI_ERROR (Status)) {
2356 SynchronizeStorage (Storage);
2357 }
2358
2359 Link = GetNextNode (&FormSet->StorageListHead, Link);
2360 }
2361
2362 return EFI_SUCCESS;
2363 }
2364
2365
2366 /**
2367 Fetch the Ifr binary data of a FormSet.
2368
2369 @param Handle PackageList Handle
2370 @param FormSetGuid On input, GUID or class GUID of a formset. If not
2371 specified (NULL or zero GUID), take the first
2372 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
2373 found in package list.
2374 On output, GUID of the formset found(if not NULL).
2375 @param BinaryLength The length of the FormSet IFR binary.
2376 @param BinaryData The buffer designed to receive the FormSet.
2377
2378 @retval EFI_SUCCESS Buffer filled with the requested FormSet.
2379 BufferLength was updated.
2380 @retval EFI_INVALID_PARAMETER The handle is unknown.
2381 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
2382 be found with the requested FormId.
2383
2384 **/
2385 EFI_STATUS
2386 GetIfrBinaryData (
2387 IN EFI_HII_HANDLE Handle,
2388 IN OUT EFI_GUID *FormSetGuid,
2389 OUT UINTN *BinaryLength,
2390 OUT UINT8 **BinaryData
2391 )
2392 {
2393 EFI_STATUS Status;
2394 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
2395 UINTN BufferSize;
2396 UINT8 *Package;
2397 UINT8 *OpCodeData;
2398 UINT32 Offset;
2399 UINT32 Offset2;
2400 UINT32 PackageListLength;
2401 EFI_HII_PACKAGE_HEADER PackageHeader;
2402 UINT8 Index;
2403 UINT8 NumberOfClassGuid;
2404 BOOLEAN ClassGuidMatch;
2405 EFI_GUID *ClassGuid;
2406 EFI_GUID *ComparingGuid;
2407
2408 OpCodeData = NULL;
2409 Package = NULL;
2410 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
2411
2412 //
2413 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
2414 //
2415 if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) {
2416 ComparingGuid = &gEfiHiiPlatformSetupFormsetGuid;
2417 } else {
2418 ComparingGuid = FormSetGuid;
2419 }
2420
2421 //
2422 // Get HII PackageList
2423 //
2424 BufferSize = 0;
2425 HiiPackageList = NULL;
2426 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
2427 if (Status == EFI_BUFFER_TOO_SMALL) {
2428 HiiPackageList = AllocatePool (BufferSize);
2429 ASSERT (HiiPackageList != NULL);
2430
2431 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
2432 }
2433 if (EFI_ERROR (Status)) {
2434 return Status;
2435 }
2436 ASSERT (HiiPackageList != NULL);
2437
2438 //
2439 // Get Form package from this HII package List
2440 //
2441 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
2442 Offset2 = 0;
2443 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
2444
2445 ClassGuidMatch = FALSE;
2446 while (Offset < PackageListLength) {
2447 Package = ((UINT8 *) HiiPackageList) + Offset;
2448 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
2449
2450 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
2451 //
2452 // Search FormSet in this Form Package
2453 //
2454 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
2455 while (Offset2 < PackageHeader.Length) {
2456 OpCodeData = Package + Offset2;
2457
2458 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
2459 //
2460 // Try to compare against formset GUID
2461 //
2462 if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
2463 break;
2464 }
2465
2466 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
2467 //
2468 // Try to compare against formset class GUID
2469 //
2470 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
2471 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
2472 for (Index = 0; Index < NumberOfClassGuid; Index++) {
2473 if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
2474 ClassGuidMatch = TRUE;
2475 break;
2476 }
2477 }
2478 if (ClassGuidMatch) {
2479 break;
2480 }
2481 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
2482 ClassGuidMatch = TRUE;
2483 break;
2484 }
2485 }
2486
2487 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
2488 }
2489
2490 if (Offset2 < PackageHeader.Length) {
2491 //
2492 // Target formset found
2493 //
2494 break;
2495 }
2496 }
2497
2498 Offset += PackageHeader.Length;
2499 }
2500
2501 if (Offset >= PackageListLength) {
2502 //
2503 // Form package not found in this Package List
2504 //
2505 FreePool (HiiPackageList);
2506 return EFI_NOT_FOUND;
2507 }
2508
2509 if (ClassGuidMatch && (FormSetGuid != NULL)) {
2510 //
2511 // Return the FormSet GUID
2512 //
2513 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
2514 }
2515
2516 //
2517 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
2518 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
2519 // of the Form Package.
2520 //
2521 *BinaryLength = PackageHeader.Length - Offset2;
2522 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
2523
2524 FreePool (HiiPackageList);
2525
2526 if (*BinaryData == NULL) {
2527 return EFI_OUT_OF_RESOURCES;
2528 }
2529
2530 return EFI_SUCCESS;
2531 }
2532
2533
2534 /**
2535 Initialize the internal data structure of a FormSet.
2536
2537 @param Handle PackageList Handle
2538 @param FormSetGuid On input, GUID or class GUID of a formset. If not
2539 specified (NULL or zero GUID), take the first
2540 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
2541 found in package list.
2542 On output, GUID of the formset found(if not NULL).
2543 @param FormSet FormSet data structure.
2544
2545 @retval EFI_SUCCESS The function completed successfully.
2546 @retval EFI_NOT_FOUND The specified FormSet could not be found.
2547
2548 **/
2549 EFI_STATUS
2550 InitializeFormSet (
2551 IN EFI_HII_HANDLE Handle,
2552 IN OUT EFI_GUID *FormSetGuid,
2553 OUT FORM_BROWSER_FORMSET *FormSet
2554 )
2555 {
2556 EFI_STATUS Status;
2557 EFI_HANDLE DriverHandle;
2558 UINT16 Index;
2559
2560 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
2561 if (EFI_ERROR (Status)) {
2562 return Status;
2563 }
2564
2565 FormSet->HiiHandle = Handle;
2566 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
2567
2568 //
2569 // Retrieve ConfigAccess Protocol associated with this HiiPackageList
2570 //
2571 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
2572 if (EFI_ERROR (Status)) {
2573 return Status;
2574 }
2575 FormSet->DriverHandle = DriverHandle;
2576 Status = gBS->HandleProtocol (
2577 DriverHandle,
2578 &gEfiHiiConfigAccessProtocolGuid,
2579 (VOID **) &FormSet->ConfigAccess
2580 );
2581 if (EFI_ERROR (Status)) {
2582 //
2583 // Configuration Driver don't attach ConfigAccess protocol to its HII package
2584 // list, then there will be no configuration action required
2585 //
2586 FormSet->ConfigAccess = NULL;
2587 }
2588
2589 //
2590 // Parse the IFR binary OpCodes
2591 //
2592 Status = ParseOpCodes (FormSet);
2593 if (EFI_ERROR (Status)) {
2594 return Status;
2595 }
2596
2597 //
2598 // Set VFR type by FormSet SubClass field
2599 //
2600 gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
2601 if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
2602 gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
2603 }
2604
2605 //
2606 // Set VFR type by FormSet class guid
2607 //
2608 for (Index = 0; Index < 3; Index ++) {
2609 if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
2610 gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
2611 break;
2612 }
2613 }
2614
2615 if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
2616 gFrontPageHandle = FormSet->HiiHandle;
2617 }
2618
2619 //
2620 // Match GUID to find out the function key setting. If match fail, use the default setting.
2621 //
2622 for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
2623 if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
2624 //
2625 // Update the function key setting.
2626 //
2627 gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
2628 //
2629 // Function key prompt can not be displayed if the function key has been disabled.
2630 //
2631 if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) {
2632 gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
2633 }
2634
2635 if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) {
2636 gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
2637 }
2638 }
2639 }
2640
2641 return Status;
2642 }
2643
2644
2645 /**
2646 Save globals used by previous call to SendForm(). SendForm() may be called from
2647 HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
2648 So, save globals of previous call to SendForm() and restore them upon exit.
2649
2650 **/
2651 VOID
2652 SaveBrowserContext (
2653 VOID
2654 )
2655 {
2656 BROWSER_CONTEXT *Context;
2657
2658 gBrowserContextCount++;
2659 if (gBrowserContextCount == 1) {
2660 //
2661 // This is not reentry of SendForm(), no context to save
2662 //
2663 return;
2664 }
2665
2666 Context = AllocatePool (sizeof (BROWSER_CONTEXT));
2667 ASSERT (Context != NULL);
2668
2669 Context->Signature = BROWSER_CONTEXT_SIGNATURE;
2670
2671 //
2672 // Save FormBrowser context
2673 //
2674 Context->BannerData = gBannerData;
2675 Context->ClassOfVfr = gClassOfVfr;
2676 Context->FunctionKeySetting = gFunctionKeySetting;
2677 Context->ResetRequired = gResetRequired;
2678 Context->NvUpdateRequired = gNvUpdateRequired;
2679 Context->Direction = gDirection;
2680 Context->FunctionNineString = gFunctionNineString;
2681 Context->FunctionTenString = gFunctionTenString;
2682 Context->EnterString = gEnterString;
2683 Context->EnterCommitString = gEnterCommitString;
2684 Context->EnterEscapeString = gEnterEscapeString;
2685 Context->EscapeString = gEscapeString;
2686 Context->SaveFailed = gSaveFailed;
2687 Context->MoveHighlight = gMoveHighlight;
2688 Context->MakeSelection = gMakeSelection;
2689 Context->DecNumericInput = gDecNumericInput;
2690 Context->HexNumericInput = gHexNumericInput;
2691 Context->ToggleCheckBox = gToggleCheckBox;
2692 Context->PromptForData = gPromptForData;
2693 Context->PromptForPassword = gPromptForPassword;
2694 Context->PromptForNewPassword = gPromptForNewPassword;
2695 Context->ConfirmPassword = gConfirmPassword;
2696 Context->ConfirmError = gConfirmError;
2697 Context->PassowordInvalid = gPassowordInvalid;
2698 Context->PressEnter = gPressEnter;
2699 Context->EmptyString = gEmptyString;
2700 Context->AreYouSure = gAreYouSure;
2701 Context->YesResponse = gYesResponse;
2702 Context->NoResponse = gNoResponse;
2703 Context->MiniString = gMiniString;
2704 Context->PlusString = gPlusString;
2705 Context->MinusString = gMinusString;
2706 Context->AdjustNumber = gAdjustNumber;
2707 Context->SaveChanges = gSaveChanges;
2708 Context->OptionMismatch = gOptionMismatch;
2709 Context->FormSuppress = gFormSuppress;
2710 Context->PromptBlockWidth = gPromptBlockWidth;
2711 Context->OptionBlockWidth = gOptionBlockWidth;
2712 Context->HelpBlockWidth = gHelpBlockWidth;
2713 Context->OldFormSet = gOldFormSet;
2714 Context->MenuRefreshHead = gMenuRefreshHead;
2715
2716 CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
2717 CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
2718
2719 //
2720 // Insert to FormBrowser context list
2721 //
2722 InsertHeadList (&gBrowserContextList, &Context->Link);
2723 }
2724
2725
2726 /**
2727 Restore globals used by previous call to SendForm().
2728
2729 **/
2730 VOID
2731 RestoreBrowserContext (
2732 VOID
2733 )
2734 {
2735 LIST_ENTRY *Link;
2736 BROWSER_CONTEXT *Context;
2737
2738 ASSERT (gBrowserContextCount != 0);
2739 gBrowserContextCount--;
2740 if (gBrowserContextCount == 0) {
2741 //
2742 // This is not reentry of SendForm(), no context to restore
2743 //
2744 return;
2745 }
2746
2747 ASSERT (!IsListEmpty (&gBrowserContextList));
2748
2749 Link = GetFirstNode (&gBrowserContextList);
2750 Context = BROWSER_CONTEXT_FROM_LINK (Link);
2751
2752 //
2753 // Restore FormBrowser context
2754 //
2755 gBannerData = Context->BannerData;
2756 gClassOfVfr = Context->ClassOfVfr;
2757 gFunctionKeySetting = Context->FunctionKeySetting;
2758 gResetRequired = Context->ResetRequired;
2759 gNvUpdateRequired = Context->NvUpdateRequired;
2760 gDirection = Context->Direction;
2761 gFunctionNineString = Context->FunctionNineString;
2762 gFunctionTenString = Context->FunctionTenString;
2763 gEnterString = Context->EnterString;
2764 gEnterCommitString = Context->EnterCommitString;
2765 gEnterEscapeString = Context->EnterEscapeString;
2766 gEscapeString = Context->EscapeString;
2767 gSaveFailed = Context->SaveFailed;
2768 gMoveHighlight = Context->MoveHighlight;
2769 gMakeSelection = Context->MakeSelection;
2770 gDecNumericInput = Context->DecNumericInput;
2771 gHexNumericInput = Context->HexNumericInput;
2772 gToggleCheckBox = Context->ToggleCheckBox;
2773 gPromptForData = Context->PromptForData;
2774 gPromptForPassword = Context->PromptForPassword;
2775 gPromptForNewPassword = Context->PromptForNewPassword;
2776 gConfirmPassword = Context->ConfirmPassword;
2777 gConfirmError = Context->ConfirmError;
2778 gPassowordInvalid = Context->PassowordInvalid;
2779 gPressEnter = Context->PressEnter;
2780 gEmptyString = Context->EmptyString;
2781 gAreYouSure = Context->AreYouSure;
2782 gYesResponse = Context->YesResponse;
2783 gNoResponse = Context->NoResponse;
2784 gMiniString = Context->MiniString;
2785 gPlusString = Context->PlusString;
2786 gMinusString = Context->MinusString;
2787 gAdjustNumber = Context->AdjustNumber;
2788 gSaveChanges = Context->SaveChanges;
2789 gOptionMismatch = Context->OptionMismatch;
2790 gFormSuppress = Context->FormSuppress;
2791 gPromptBlockWidth = Context->PromptBlockWidth;
2792 gOptionBlockWidth = Context->OptionBlockWidth;
2793 gHelpBlockWidth = Context->HelpBlockWidth;
2794 gOldFormSet = Context->OldFormSet;
2795 gMenuRefreshHead = Context->MenuRefreshHead;
2796
2797 CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
2798 CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
2799
2800 //
2801 // Remove from FormBrowser context list
2802 //
2803 RemoveEntryList (&Context->Link);
2804 gBS->FreePool (Context);
2805 }