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