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