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