1 /** @file 2 Entry and initialization module for the browser. 3 4 Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Setup.h" 16 17 SETUP_DRIVER_PRIVATE_DATA mPrivateData = { 18 SETUP_DRIVER_SIGNATURE, 19 NULL, 20 { 21 SendForm, 22 BrowserCallback 23 }, 24 { 25 SetScope, 26 RegisterHotKey, 27 RegiserExitHandler, 28 SaveReminder 29 }, 30 { 31 BROWSER_EXTENSION2_VERSION_1_1, 32 SetScope, 33 RegisterHotKey, 34 RegiserExitHandler, 35 IsBrowserDataModified, 36 ExecuteAction, 37 {NULL,NULL}, 38 {NULL,NULL}, 39 IsResetRequired 40 } 41 }; 42 43 EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; 44 EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; 45 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText; 46 EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay; 47 48 UINTN gBrowserContextCount = 0; 49 LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList); 50 LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList); 51 LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList); 52 LIST_ENTRY gBrowserStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList); 53 LIST_ENTRY gBrowserSaveFailFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserSaveFailFormSetList); 54 55 BOOLEAN mSystemSubmit = FALSE; 56 BOOLEAN gResetRequired; 57 BOOLEAN gExitRequired; 58 BOOLEAN gFlagReconnect; 59 BOOLEAN gCallbackReconnect; 60 BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel; 61 BOOLEAN mBrowserScopeFirstSet = TRUE; 62 EXIT_HANDLER ExitHandlerFunction = NULL; 63 FORM_BROWSER_FORMSET *mSystemLevelFormSet; 64 65 // 66 // Browser Global Strings 67 // 68 CHAR16 *gEmptyString; 69 CHAR16 *mUnknownString = L"!"; 70 71 extern EFI_GUID mCurrentFormSetGuid; 72 extern EFI_HII_HANDLE mCurrentHiiHandle; 73 extern UINT16 mCurrentFormId; 74 extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData; 75 76 /** 77 Create a menu with specified formset GUID and form ID, and add it as a child 78 of the given parent menu. 79 80 @param HiiHandle Hii handle related to this formset. 81 @param FormSetGuid The Formset Guid of menu to be added. 82 @param FormId The Form ID of menu to be added. 83 @param QuestionId The question id of this menu to be added. 84 85 @return A pointer to the newly added menu or NULL if memory is insufficient. 86 87 **/ 88 FORM_ENTRY_INFO * 89 UiAddMenuList ( 90 IN EFI_HII_HANDLE HiiHandle, 91 IN EFI_GUID *FormSetGuid, 92 IN UINT16 FormId, 93 IN UINT16 QuestionId 94 ) 95 { 96 FORM_ENTRY_INFO *MenuList; 97 98 MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); 99 if (MenuList == NULL) { 100 return NULL; 101 } 102 103 MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE; 104 105 MenuList->HiiHandle = HiiHandle; 106 CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); 107 MenuList->FormId = FormId; 108 MenuList->QuestionId = QuestionId; 109 110 // 111 // If parent is not specified, it is the root Form of a Formset 112 // 113 InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); 114 115 return MenuList; 116 } 117 118 /** 119 Return the form id for the input hiihandle and formset. 120 121 @param HiiHandle HiiHandle for FormSet. 122 @param FormSetGuid The Formset GUID of the menu to search. 123 124 @return First form's id for this form set. 125 126 **/ 127 EFI_FORM_ID 128 GetFirstFormId ( 129 IN EFI_HII_HANDLE HiiHandle, 130 IN EFI_GUID *FormSetGuid 131 ) 132 { 133 LIST_ENTRY *Link; 134 FORM_BROWSER_FORM *Form; 135 136 Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead); 137 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 138 139 return Form->FormId; 140 } 141 142 /** 143 Search Menu with given FormSetGuid and FormId in all cached menu list. 144 145 @param HiiHandle HiiHandle for FormSet. 146 @param FormSetGuid The Formset GUID of the menu to search. 147 @param FormId The Form ID of menu to search. 148 149 @return A pointer to menu found or NULL if not found. 150 151 **/ 152 FORM_ENTRY_INFO * 153 UiFindMenuList ( 154 IN EFI_HII_HANDLE HiiHandle, 155 IN EFI_GUID *FormSetGuid, 156 IN UINT16 FormId 157 ) 158 { 159 LIST_ENTRY *Link; 160 FORM_ENTRY_INFO *MenuList; 161 FORM_ENTRY_INFO *RetMenu; 162 EFI_FORM_ID FirstFormId; 163 164 RetMenu = NULL; 165 166 Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); 167 while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) { 168 MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); 169 Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link); 170 171 // 172 // If already find the menu, free the menus behind it. 173 // 174 if (RetMenu != NULL) { 175 RemoveEntryList (&MenuList->Link); 176 FreePool (MenuList); 177 continue; 178 } 179 180 // 181 // Find the same FromSet. 182 // 183 if (MenuList->HiiHandle == HiiHandle) { 184 if (IsZeroGuid (&MenuList->FormSetGuid)) { 185 // 186 // FormSetGuid is not specified. 187 // 188 RetMenu = MenuList; 189 } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) { 190 if (MenuList->FormId == FormId) { 191 RetMenu = MenuList; 192 } else if (FormId == 0 || MenuList->FormId == 0 ) { 193 FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid); 194 if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) { 195 RetMenu = MenuList; 196 } 197 } 198 } 199 } 200 } 201 202 return RetMenu; 203 } 204 205 /** 206 Find parent menu for current menu. 207 208 @param CurrentMenu Current Menu 209 @param SettingLevel Whether find parent menu in Form Level or Formset level. 210 In form level, just find the parent menu; 211 In formset level, find the parent menu which has different 212 formset guid value. 213 214 @retval The parent menu for current menu. 215 **/ 216 FORM_ENTRY_INFO * 217 UiFindParentMenu ( 218 IN FORM_ENTRY_INFO *CurrentMenu, 219 IN BROWSER_SETTING_SCOPE SettingLevel 220 ) 221 { 222 FORM_ENTRY_INFO *ParentMenu; 223 LIST_ENTRY *Link; 224 225 ASSERT (SettingLevel == FormLevel || SettingLevel == FormSetLevel); 226 227 if (CurrentMenu == NULL) { 228 return NULL; 229 } 230 231 ParentMenu = NULL; 232 Link = &CurrentMenu->Link; 233 234 while (Link->BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { 235 ParentMenu = FORM_ENTRY_INFO_FROM_LINK (Link->BackLink); 236 237 if (SettingLevel == FormLevel) { 238 // 239 // For FormLevel, just find the parent menu, return. 240 // 241 break; 242 } 243 244 if (!CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) { 245 // 246 // For SystemLevel, must find the menu which has different formset. 247 // 248 break; 249 } 250 251 Link = Link->BackLink; 252 } 253 254 // 255 // Not find the parent menu, just return NULL. 256 // 257 if (Link->BackLink == &mPrivateData.FormBrowserEx2.FormViewHistoryHead) { 258 return NULL; 259 } 260 261 return ParentMenu; 262 } 263 264 /** 265 Free Menu list linked list. 266 267 @param MenuListHead One Menu list point in the menu list. 268 269 **/ 270 VOID 271 UiFreeMenuList ( 272 LIST_ENTRY *MenuListHead 273 ) 274 { 275 FORM_ENTRY_INFO *MenuList; 276 277 while (!IsListEmpty (MenuListHead)) { 278 MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink); 279 RemoveEntryList (&MenuList->Link); 280 281 FreePool (MenuList); 282 } 283 } 284 285 /** 286 Copy current Menu list to the new menu list. 287 288 @param NewMenuListHead New create Menu list. 289 @param CurrentMenuListHead Current Menu list. 290 291 **/ 292 VOID 293 UiCopyMenuList ( 294 OUT LIST_ENTRY *NewMenuListHead, 295 IN LIST_ENTRY *CurrentMenuListHead 296 ) 297 { 298 LIST_ENTRY *Link; 299 FORM_ENTRY_INFO *MenuList; 300 FORM_ENTRY_INFO *NewMenuEntry; 301 302 // 303 // If new menu list not empty, free it first. 304 // 305 UiFreeMenuList (NewMenuListHead); 306 307 Link = GetFirstNode (CurrentMenuListHead); 308 while (!IsNull (CurrentMenuListHead, Link)) { 309 MenuList = FORM_ENTRY_INFO_FROM_LINK (Link); 310 Link = GetNextNode (CurrentMenuListHead, Link); 311 312 NewMenuEntry = AllocateZeroPool (sizeof (FORM_ENTRY_INFO)); 313 ASSERT (NewMenuEntry != NULL); 314 NewMenuEntry->Signature = FORM_ENTRY_INFO_SIGNATURE; 315 NewMenuEntry->HiiHandle = MenuList->HiiHandle; 316 CopyMem (&NewMenuEntry->FormSetGuid, &MenuList->FormSetGuid, sizeof (EFI_GUID)); 317 NewMenuEntry->FormId = MenuList->FormId; 318 NewMenuEntry->QuestionId = MenuList->QuestionId; 319 320 InsertTailList (NewMenuListHead, &NewMenuEntry->Link); 321 } 322 } 323 324 /** 325 Load all hii formset to the browser. 326 327 **/ 328 VOID 329 LoadAllHiiFormset ( 330 VOID 331 ) 332 { 333 FORM_BROWSER_FORMSET *LocalFormSet; 334 EFI_HII_HANDLE *HiiHandles; 335 UINTN Index; 336 EFI_GUID ZeroGuid; 337 EFI_STATUS Status; 338 FORM_BROWSER_FORMSET *OldFormset; 339 340 OldFormset = mSystemLevelFormSet; 341 342 // 343 // Get all the Hii handles 344 // 345 HiiHandles = HiiGetHiiHandles (NULL); 346 ASSERT (HiiHandles != NULL); 347 348 // 349 // Search for formset of each class type 350 // 351 for (Index = 0; HiiHandles[Index] != NULL; Index++) { 352 // 353 // Check HiiHandles[Index] does exist in global maintain list. 354 // 355 if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) { 356 continue; 357 } 358 359 // 360 // Initilize FormSet Setting 361 // 362 LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); 363 ASSERT (LocalFormSet != NULL); 364 mSystemLevelFormSet = LocalFormSet; 365 366 ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); 367 Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet); 368 if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) { 369 DestroyFormSet (LocalFormSet); 370 continue; 371 } 372 InitializeCurrentSetting (LocalFormSet); 373 374 // 375 // Initilize Questions' Value 376 // 377 Status = LoadFormSetConfig (NULL, LocalFormSet); 378 if (EFI_ERROR (Status)) { 379 DestroyFormSet (LocalFormSet); 380 continue; 381 } 382 } 383 384 // 385 // Free resources, and restore gOldFormSet and gClassOfVfr 386 // 387 FreePool (HiiHandles); 388 389 mSystemLevelFormSet = OldFormset; 390 } 391 392 /** 393 Pop up the error info. 394 395 @param BrowserStatus The input browser status. 396 @param HiiHandle The Hiihandle for this opcode. 397 @param OpCode The opcode use to get the erro info and timeout value. 398 @param ErrorString Error string used by BROWSER_NO_SUBMIT_IF. 399 400 **/ 401 UINT32 402 PopupErrorMessage ( 403 IN UINT32 BrowserStatus, 404 IN EFI_HII_HANDLE HiiHandle, 405 IN EFI_IFR_OP_HEADER *OpCode, OPTIONAL 406 IN CHAR16 *ErrorString 407 ) 408 { 409 FORM_DISPLAY_ENGINE_STATEMENT *Statement; 410 USER_INPUT UserInputData; 411 412 Statement = NULL; 413 414 if (OpCode != NULL) { 415 Statement = AllocateZeroPool (sizeof(FORM_DISPLAY_ENGINE_STATEMENT)); 416 ASSERT (Statement != NULL); 417 Statement->OpCode = OpCode; 418 gDisplayFormData.HighLightedStatement = Statement; 419 } 420 421 // 422 // Used to compatible with old display engine. 423 // New display engine not use this field. 424 // 425 gDisplayFormData.ErrorString = ErrorString; 426 gDisplayFormData.BrowserStatus = BrowserStatus; 427 428 if (HiiHandle != NULL) { 429 gDisplayFormData.HiiHandle = HiiHandle; 430 } 431 432 mFormDisplay->FormDisplay (&gDisplayFormData, &UserInputData); 433 434 gDisplayFormData.BrowserStatus = BROWSER_SUCCESS; 435 gDisplayFormData.ErrorString = NULL; 436 437 if (OpCode != NULL) { 438 FreePool (Statement); 439 } 440 441 return UserInputData.Action; 442 } 443 444 /** 445 This is the routine which an external caller uses to direct the browser 446 where to obtain it's information. 447 448 449 @param This The Form Browser protocol instanse. 450 @param Handles A pointer to an array of Handles. If HandleCount > 1 we 451 display a list of the formsets for the handles specified. 452 @param HandleCount The number of Handles specified in Handle. 453 @param FormSetGuid This field points to the EFI_GUID which must match the Guid 454 field in the EFI_IFR_FORM_SET op-code for the specified 455 forms-based package. If FormSetGuid is NULL, then this 456 function will display the first found forms package. 457 @param FormId This field specifies which EFI_IFR_FORM to render as the first 458 displayable page. If this field has a value of 0x0000, then 459 the forms browser will render the specified forms in their encoded order. 460 @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in 461 characters. 462 @param ActionRequest Points to the action recommended by the form. 463 464 @retval EFI_SUCCESS The function completed successfully. 465 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. 466 @retval EFI_NOT_FOUND No valid forms could be found to display. 467 468 **/ 469 EFI_STATUS 470 EFIAPI 471 SendForm ( 472 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, 473 IN EFI_HII_HANDLE *Handles, 474 IN UINTN HandleCount, 475 IN EFI_GUID *FormSetGuid, OPTIONAL 476 IN UINT16 FormId, OPTIONAL 477 IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL 478 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL 479 ) 480 { 481 EFI_STATUS Status; 482 UI_MENU_SELECTION *Selection; 483 UINTN Index; 484 FORM_BROWSER_FORMSET *FormSet; 485 FORM_ENTRY_INFO *MenuList; 486 BOOLEAN RetVal; 487 488 // 489 // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED. 490 // 491 if (mFormDisplay == NULL) { 492 DEBUG ((DEBUG_ERROR, "Fatal Error! EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found!")); 493 return EFI_UNSUPPORTED; 494 } 495 496 // 497 // Save globals used by SendForm() 498 // 499 SaveBrowserContext (); 500 501 gFlagReconnect = FALSE; 502 gResetRequired = FALSE; 503 gExitRequired = FALSE; 504 gCallbackReconnect = FALSE; 505 Status = EFI_SUCCESS; 506 gEmptyString = L""; 507 gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions; 508 509 for (Index = 0; Index < HandleCount; Index++) { 510 Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); 511 ASSERT (Selection != NULL); 512 513 Selection->Handle = Handles[Index]; 514 if (FormSetGuid != NULL) { 515 CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); 516 Selection->FormId = FormId; 517 } else { 518 CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID)); 519 } 520 521 do { 522 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); 523 ASSERT (FormSet != NULL); 524 525 // 526 // Validate the HiiHandle 527 // if validate failed, find the first validate parent HiiHandle. 528 // 529 if (!ValidateHiiHandle(Selection->Handle)) { 530 FindNextMenu (Selection, FormSetLevel); 531 } 532 533 // 534 // Initialize internal data structures of FormSet 535 // 536 Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); 537 if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) { 538 DestroyFormSet (FormSet); 539 break; 540 } 541 Selection->FormSet = FormSet; 542 mSystemLevelFormSet = FormSet; 543 544 // 545 // Display this formset 546 // 547 gCurrentSelection = Selection; 548 549 Status = SetupBrowser (Selection); 550 551 gCurrentSelection = NULL; 552 mSystemLevelFormSet = NULL; 553 554 if (gFlagReconnect || gCallbackReconnect) { 555 RetVal = ReconnectController (FormSet->DriverHandle); 556 if (!RetVal) { 557 PopupErrorMessage(BROWSER_RECONNECT_FAIL, NULL, NULL, NULL); 558 } 559 gFlagReconnect = FALSE; 560 gCallbackReconnect = FALSE; 561 } 562 563 // 564 // If no data is changed, don't need to save current FormSet into the maintain list. 565 // 566 if (!IsNvUpdateRequiredForFormSet (FormSet)) { 567 CleanBrowserStorage(FormSet); 568 RemoveEntryList (&FormSet->Link); 569 DestroyFormSet (FormSet); 570 } 571 572 if (EFI_ERROR (Status)) { 573 break; 574 } 575 } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); 576 577 FreePool (Selection); 578 } 579 580 if (ActionRequest != NULL) { 581 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 582 if (gResetRequired) { 583 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; 584 } 585 } 586 587 mFormDisplay->ExitDisplay(); 588 589 // 590 // Clear the menu history data. 591 // 592 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { 593 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); 594 RemoveEntryList (&MenuList->Link); 595 FreePool (MenuList); 596 } 597 598 // 599 // Restore globals used by SendForm() 600 // 601 RestoreBrowserContext (); 602 603 return Status; 604 } 605 606 /** 607 Get or set data to the storage. 608 609 @param ResultsDataSize The size of the buffer associatedwith ResultsData. 610 @param ResultsData A string returned from an IFR browser or 611 equivalent. The results string will have no 612 routing information in them. 613 @param RetrieveData A BOOLEAN field which allows an agent to retrieve 614 (if RetrieveData = TRUE) data from the uncommitted 615 browser state information or set (if RetrieveData 616 = FALSE) data in the uncommitted browser state 617 information. 618 @param Storage The pointer to the storage. 619 620 @retval EFI_SUCCESS The results have been distributed or are awaiting 621 distribution. 622 623 **/ 624 EFI_STATUS 625 ProcessStorage ( 626 IN OUT UINTN *ResultsDataSize, 627 IN OUT EFI_STRING *ResultsData, 628 IN BOOLEAN RetrieveData, 629 IN BROWSER_STORAGE *Storage 630 ) 631 { 632 CHAR16 *ConfigResp; 633 EFI_STATUS Status; 634 CHAR16 *StrPtr; 635 UINTN BufferSize; 636 UINTN TmpSize; 637 UINTN MaxLen; 638 FORMSET_STORAGE *BrowserStorage; 639 640 if (RetrieveData) { 641 // 642 // Generate <ConfigResp> 643 // 644 Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE); 645 if (EFI_ERROR (Status)) { 646 return Status; 647 } 648 649 // 650 // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody. 651 // Also need to consider add "\0" at first time. 652 // 653 StrPtr = StrStr (ConfigResp, L"PATH"); 654 ASSERT (StrPtr != NULL); 655 StrPtr = StrStr (StrPtr, L"&"); 656 StrPtr += 1; 657 BufferSize = StrSize (StrPtr); 658 659 // 660 // Copy the data if the input buffer is bigger enough. 661 // 662 if (*ResultsDataSize >= BufferSize) { 663 StrCpyS (*ResultsData, *ResultsDataSize / sizeof (CHAR16), StrPtr); 664 } 665 666 *ResultsDataSize = BufferSize; 667 FreePool (ConfigResp); 668 } else { 669 // 670 // Prepare <ConfigResp> 671 // 672 BrowserStorage = GetFstStgFromBrsStg (Storage); 673 ASSERT (BrowserStorage != NULL); 674 TmpSize = StrLen (*ResultsData); 675 BufferSize = (TmpSize + StrLen (BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16); 676 MaxLen = BufferSize / sizeof (CHAR16); 677 ConfigResp = AllocateZeroPool (BufferSize); 678 ASSERT (ConfigResp != NULL); 679 680 StrCpyS (ConfigResp, MaxLen, BrowserStorage->ConfigHdr); 681 StrCatS (ConfigResp, MaxLen, L"&"); 682 StrCatS (ConfigResp, MaxLen, *ResultsData); 683 684 // 685 // Update Browser uncommited data 686 // 687 Status = ConfigRespToStorage (Storage, ConfigResp); 688 FreePool (ConfigResp); 689 if (EFI_ERROR (Status)) { 690 return Status; 691 } 692 } 693 694 return EFI_SUCCESS; 695 } 696 697 /** 698 This routine called this service in the browser to retrieve or set certain uncommitted 699 state information that resides in the open formsets. 700 701 @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL 702 instance. 703 @param ResultsDataSize A pointer to the size of the buffer associated 704 with ResultsData. 705 @param ResultsData A string returned from an IFR browser or 706 equivalent. The results string will have no 707 routing information in them. 708 @param RetrieveData A BOOLEAN field which allows an agent to retrieve 709 (if RetrieveData = TRUE) data from the uncommitted 710 browser state information or set (if RetrieveData 711 = FALSE) data in the uncommitted browser state 712 information. 713 @param VariableGuid An optional field to indicate the target variable 714 GUID name to use. 715 @param VariableName An optional field to indicate the target 716 human-readable variable name. 717 718 @retval EFI_SUCCESS The results have been distributed or are awaiting 719 distribution. 720 @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to 721 contain the results data. 722 723 **/ 724 EFI_STATUS 725 EFIAPI 726 BrowserCallback ( 727 IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, 728 IN OUT UINTN *ResultsDataSize, 729 IN OUT EFI_STRING ResultsData, 730 IN BOOLEAN RetrieveData, 731 IN CONST EFI_GUID *VariableGuid, OPTIONAL 732 IN CONST CHAR16 *VariableName OPTIONAL 733 ) 734 { 735 EFI_STATUS Status; 736 LIST_ENTRY *Link; 737 BROWSER_STORAGE *Storage; 738 FORMSET_STORAGE *FormsetStorage; 739 UINTN TotalSize; 740 BOOLEAN Found; 741 742 if (ResultsDataSize == NULL || ResultsData == NULL) { 743 return EFI_INVALID_PARAMETER; 744 } 745 746 TotalSize = *ResultsDataSize; 747 Storage = NULL; 748 Found = FALSE; 749 Status = EFI_SUCCESS; 750 751 if (VariableGuid != NULL) { 752 // 753 // Try to find target storage in the current formset. 754 // 755 Link = GetFirstNode (&gBrowserStorageList); 756 while (!IsNull (&gBrowserStorageList, Link)) { 757 Storage = BROWSER_STORAGE_FROM_LINK (Link); 758 Link = GetNextNode (&gBrowserStorageList, Link); 759 // 760 // Check the current storage. 761 // 762 if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { 763 continue; 764 } 765 766 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 767 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 768 // 769 // Buffer storage require both GUID and Name 770 // 771 if (VariableName == NULL) { 772 return EFI_NOT_FOUND; 773 } 774 775 if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { 776 continue; 777 } 778 } 779 780 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE || 781 Storage->Type == EFI_HII_VARSTORE_BUFFER) { 782 if (mSystemLevelFormSet == NULL || mSystemLevelFormSet->HiiHandle == NULL) { 783 return EFI_NOT_FOUND; 784 } 785 786 if (Storage->HiiHandle != mSystemLevelFormSet->HiiHandle) { 787 continue; 788 } 789 } 790 791 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage); 792 if (EFI_ERROR (Status)) { 793 return Status; 794 } 795 796 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 797 ConfigRequestAdjust (Storage, ResultsData, TRUE); 798 } 799 800 // 801 // Different formsets may have same varstore, so here just set the flag 802 // not exit the circle. 803 // 804 Found = TRUE; 805 break; 806 } 807 808 if (!Found) { 809 return EFI_NOT_FOUND; 810 } 811 } else { 812 // 813 // GUID/Name is not specified, take the first storage in FormSet 814 // 815 if (mSystemLevelFormSet == NULL) { 816 return EFI_NOT_READY; 817 } 818 819 // 820 // Generate <ConfigResp> 821 // 822 Link = GetFirstNode (&mSystemLevelFormSet->StorageListHead); 823 if (IsNull (&mSystemLevelFormSet->StorageListHead, Link)) { 824 return EFI_UNSUPPORTED; 825 } 826 827 FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link); 828 829 Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage); 830 if (EFI_ERROR (Status)) { 831 return Status; 832 } 833 } 834 835 if (RetrieveData) { 836 Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; 837 *ResultsDataSize = TotalSize; 838 } 839 840 return Status; 841 842 } 843 844 845 /** 846 Callback function for SimpleTextInEx protocol install events 847 848 @param Event the event that is signaled. 849 @param Context not used here. 850 851 **/ 852 VOID 853 EFIAPI 854 FormDisplayCallback ( 855 IN EFI_EVENT Event, 856 IN VOID *Context 857 ) 858 { 859 if (mFormDisplay != NULL) { 860 return; 861 } 862 863 gBS->LocateProtocol ( 864 &gEdkiiFormDisplayEngineProtocolGuid, 865 NULL, 866 (VOID **) &mFormDisplay 867 ); 868 } 869 870 /** 871 Initialize Setup Browser driver. 872 873 @param ImageHandle The image handle. 874 @param SystemTable The system table. 875 876 @retval EFI_SUCCESS The Setup Browser module is initialized correctly.. 877 @return Other value if failed to initialize the Setup Browser module. 878 879 **/ 880 EFI_STATUS 881 EFIAPI 882 InitializeSetup ( 883 IN EFI_HANDLE ImageHandle, 884 IN EFI_SYSTEM_TABLE *SystemTable 885 ) 886 { 887 EFI_STATUS Status; 888 VOID *Registration; 889 890 // 891 // Locate required Hii relative protocols 892 // 893 Status = gBS->LocateProtocol ( 894 &gEfiHiiDatabaseProtocolGuid, 895 NULL, 896 (VOID **) &mHiiDatabase 897 ); 898 ASSERT_EFI_ERROR (Status); 899 900 Status = gBS->LocateProtocol ( 901 &gEfiHiiConfigRoutingProtocolGuid, 902 NULL, 903 (VOID **) &mHiiConfigRouting 904 ); 905 ASSERT_EFI_ERROR (Status); 906 907 Status = gBS->LocateProtocol ( 908 &gEfiDevicePathFromTextProtocolGuid, 909 NULL, 910 (VOID **) &mPathFromText 911 ); 912 913 // 914 // Install FormBrowser2 protocol 915 // 916 mPrivateData.Handle = NULL; 917 Status = gBS->InstallProtocolInterface ( 918 &mPrivateData.Handle, 919 &gEfiFormBrowser2ProtocolGuid, 920 EFI_NATIVE_INTERFACE, 921 &mPrivateData.FormBrowser2 922 ); 923 ASSERT_EFI_ERROR (Status); 924 925 // 926 // Install FormBrowserEx2 protocol 927 // 928 InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead); 929 InitializeListHead (&mPrivateData.FormBrowserEx2.OverrideQestListHead); 930 mPrivateData.Handle = NULL; 931 Status = gBS->InstallProtocolInterface ( 932 &mPrivateData.Handle, 933 &gEdkiiFormBrowserEx2ProtocolGuid, 934 EFI_NATIVE_INTERFACE, 935 &mPrivateData.FormBrowserEx2 936 ); 937 ASSERT_EFI_ERROR (Status); 938 939 Status = gBS->InstallProtocolInterface ( 940 &mPrivateData.Handle, 941 &gEdkiiFormBrowserExProtocolGuid, 942 EFI_NATIVE_INTERFACE, 943 &mPrivateData.FormBrowserEx 944 ); 945 ASSERT_EFI_ERROR (Status); 946 947 InitializeDisplayFormData (); 948 949 Status = gBS->LocateProtocol ( 950 &gEdkiiFormDisplayEngineProtocolGuid, 951 NULL, 952 (VOID **) &mFormDisplay 953 ); 954 955 if (EFI_ERROR (Status)) { 956 EfiCreateProtocolNotifyEvent ( 957 &gEdkiiFormDisplayEngineProtocolGuid, 958 TPL_CALLBACK, 959 FormDisplayCallback, 960 NULL, 961 &Registration 962 ); 963 } 964 965 return EFI_SUCCESS; 966 } 967 968 969 /** 970 Create a new string in HII Package List. 971 972 @param String The String to be added 973 @param HiiHandle The package list in the HII database to insert the 974 specified string. 975 976 @return The output string. 977 978 **/ 979 EFI_STRING_ID 980 NewString ( 981 IN CHAR16 *String, 982 IN EFI_HII_HANDLE HiiHandle 983 ) 984 { 985 EFI_STRING_ID StringId; 986 987 StringId = HiiSetString (HiiHandle, 0, String, NULL); 988 ASSERT (StringId != 0); 989 990 return StringId; 991 } 992 993 994 /** 995 Delete a string from HII Package List. 996 997 @param StringId Id of the string in HII database. 998 @param HiiHandle The HII package list handle. 999 1000 @retval EFI_SUCCESS The string was deleted successfully. 1001 1002 **/ 1003 EFI_STATUS 1004 DeleteString ( 1005 IN EFI_STRING_ID StringId, 1006 IN EFI_HII_HANDLE HiiHandle 1007 ) 1008 { 1009 CHAR16 NullChar; 1010 1011 NullChar = CHAR_NULL; 1012 HiiSetString (HiiHandle, StringId, &NullChar, NULL); 1013 return EFI_SUCCESS; 1014 } 1015 1016 1017 /** 1018 Get the string based on the StringId and HII Package List Handle. 1019 1020 @param Token The String's ID. 1021 @param HiiHandle The package list in the HII database to search for 1022 the specified string. 1023 1024 @return The output string. 1025 1026 **/ 1027 CHAR16 * 1028 GetToken ( 1029 IN EFI_STRING_ID Token, 1030 IN EFI_HII_HANDLE HiiHandle 1031 ) 1032 { 1033 EFI_STRING String; 1034 1035 if (HiiHandle == NULL) { 1036 return NULL; 1037 } 1038 1039 String = HiiGetString (HiiHandle, Token, NULL); 1040 if (String == NULL) { 1041 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString); 1042 ASSERT (String != NULL); 1043 } 1044 return (CHAR16 *) String; 1045 } 1046 1047 1048 /** 1049 Allocate new memory and then copy the Unicode string Source to Destination. 1050 1051 @param Dest Location to copy string 1052 @param Src String to copy 1053 1054 **/ 1055 VOID 1056 NewStringCpy ( 1057 IN OUT CHAR16 **Dest, 1058 IN CHAR16 *Src 1059 ) 1060 { 1061 if (*Dest != NULL) { 1062 FreePool (*Dest); 1063 } 1064 *Dest = AllocateCopyPool (StrSize (Src), Src); 1065 ASSERT (*Dest != NULL); 1066 } 1067 1068 1069 /** 1070 Allocate new memory and concatinate Source on the end of Destination. 1071 1072 @param Dest String to added to the end of. 1073 @param Src String to concatinate. 1074 1075 **/ 1076 VOID 1077 NewStringCat ( 1078 IN OUT CHAR16 **Dest, 1079 IN CHAR16 *Src 1080 ) 1081 { 1082 CHAR16 *NewString; 1083 UINTN MaxLen; 1084 1085 if (*Dest == NULL) { 1086 NewStringCpy (Dest, Src); 1087 return; 1088 } 1089 1090 MaxLen = ( StrSize (*Dest) + StrSize (Src) - 1) / sizeof (CHAR16); 1091 NewString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 1092 ASSERT (NewString != NULL); 1093 1094 StrCpyS (NewString, MaxLen, *Dest); 1095 StrCatS (NewString, MaxLen, Src); 1096 1097 FreePool (*Dest); 1098 *Dest = NewString; 1099 } 1100 1101 /** 1102 Get Value for given Name from a NameValue Storage. 1103 1104 @param Storage The NameValue Storage. 1105 @param Name The Name. 1106 @param Value The retured Value. 1107 @param GetValueFrom Where to get source value, from EditValue or Value. 1108 1109 @retval EFI_SUCCESS Value found for given Name. 1110 @retval EFI_NOT_FOUND No such Name found in NameValue storage. 1111 1112 **/ 1113 EFI_STATUS 1114 GetValueByName ( 1115 IN BROWSER_STORAGE *Storage, 1116 IN CHAR16 *Name, 1117 IN OUT CHAR16 **Value, 1118 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom 1119 ) 1120 { 1121 LIST_ENTRY *Link; 1122 NAME_VALUE_NODE *Node; 1123 1124 if (GetValueFrom != GetSetValueWithEditBuffer && GetValueFrom != GetSetValueWithBuffer) { 1125 return EFI_INVALID_PARAMETER; 1126 } 1127 1128 *Value = NULL; 1129 1130 Link = GetFirstNode (&Storage->NameValueListHead); 1131 while (!IsNull (&Storage->NameValueListHead, Link)) { 1132 Node = NAME_VALUE_NODE_FROM_LINK (Link); 1133 1134 if (StrCmp (Name, Node->Name) == 0) { 1135 if (GetValueFrom == GetSetValueWithEditBuffer) { 1136 NewStringCpy (Value, Node->EditValue); 1137 } else { 1138 NewStringCpy (Value, Node->Value); 1139 } 1140 return EFI_SUCCESS; 1141 } 1142 1143 Link = GetNextNode (&Storage->NameValueListHead, Link); 1144 } 1145 1146 return EFI_NOT_FOUND; 1147 } 1148 1149 1150 /** 1151 Set Value of given Name in a NameValue Storage. 1152 1153 @param Storage The NameValue Storage. 1154 @param Name The Name. 1155 @param Value The Value to set. 1156 @param SetValueTo Whether update editValue or Value. 1157 @param ReturnNode The node use the input name. 1158 1159 @retval EFI_SUCCESS Value found for given Name. 1160 @retval EFI_NOT_FOUND No such Name found in NameValue storage. 1161 1162 **/ 1163 EFI_STATUS 1164 SetValueByName ( 1165 IN BROWSER_STORAGE *Storage, 1166 IN CHAR16 *Name, 1167 IN CHAR16 *Value, 1168 IN GET_SET_QUESTION_VALUE_WITH SetValueTo, 1169 OUT NAME_VALUE_NODE **ReturnNode 1170 ) 1171 { 1172 LIST_ENTRY *Link; 1173 NAME_VALUE_NODE *Node; 1174 CHAR16 *Buffer; 1175 1176 if (SetValueTo != GetSetValueWithEditBuffer && SetValueTo != GetSetValueWithBuffer) { 1177 return EFI_INVALID_PARAMETER; 1178 } 1179 1180 Link = GetFirstNode (&Storage->NameValueListHead); 1181 while (!IsNull (&Storage->NameValueListHead, Link)) { 1182 Node = NAME_VALUE_NODE_FROM_LINK (Link); 1183 1184 if (StrCmp (Name, Node->Name) == 0) { 1185 if (SetValueTo == GetSetValueWithEditBuffer) { 1186 Buffer = Node->EditValue; 1187 } else { 1188 Buffer = Node->Value; 1189 } 1190 if (Buffer != NULL) { 1191 FreePool (Buffer); 1192 } 1193 Buffer = AllocateCopyPool (StrSize (Value), Value); 1194 ASSERT (Buffer != NULL); 1195 if (SetValueTo == GetSetValueWithEditBuffer) { 1196 Node->EditValue = Buffer; 1197 } else { 1198 Node->Value = Buffer; 1199 } 1200 1201 if (ReturnNode != NULL) { 1202 *ReturnNode = Node; 1203 } 1204 1205 return EFI_SUCCESS; 1206 } 1207 1208 Link = GetNextNode (&Storage->NameValueListHead, Link); 1209 } 1210 1211 return EFI_NOT_FOUND; 1212 } 1213 1214 1215 /** 1216 Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>. 1217 1218 @param Storage The Storage to be conveted. 1219 @param ConfigResp The returned <ConfigResp>. 1220 @param ConfigRequest The ConfigRequest string. 1221 @param GetEditBuf Get the data from editbuffer or buffer. 1222 1223 @retval EFI_SUCCESS Convert success. 1224 @retval EFI_INVALID_PARAMETER Incorrect storage type. 1225 1226 **/ 1227 EFI_STATUS 1228 StorageToConfigResp ( 1229 IN BROWSER_STORAGE *Storage, 1230 IN CHAR16 **ConfigResp, 1231 IN CHAR16 *ConfigRequest, 1232 IN BOOLEAN GetEditBuf 1233 ) 1234 { 1235 EFI_STATUS Status; 1236 EFI_STRING Progress; 1237 LIST_ENTRY *Link; 1238 NAME_VALUE_NODE *Node; 1239 UINT8 *SourceBuf; 1240 FORMSET_STORAGE *FormsetStorage; 1241 1242 Status = EFI_SUCCESS; 1243 1244 switch (Storage->Type) { 1245 case EFI_HII_VARSTORE_BUFFER: 1246 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: 1247 SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer; 1248 Status = mHiiConfigRouting->BlockToConfig ( 1249 mHiiConfigRouting, 1250 ConfigRequest, 1251 SourceBuf, 1252 Storage->Size, 1253 ConfigResp, 1254 &Progress 1255 ); 1256 break; 1257 1258 case EFI_HII_VARSTORE_NAME_VALUE: 1259 *ConfigResp = NULL; 1260 FormsetStorage = GetFstStgFromBrsStg(Storage); 1261 ASSERT (FormsetStorage != NULL); 1262 NewStringCat (ConfigResp, FormsetStorage->ConfigHdr); 1263 1264 Link = GetFirstNode (&Storage->NameValueListHead); 1265 while (!IsNull (&Storage->NameValueListHead, Link)) { 1266 Node = NAME_VALUE_NODE_FROM_LINK (Link); 1267 1268 if (StrStr (ConfigRequest, Node->Name) != NULL) { 1269 NewStringCat (ConfigResp, L"&"); 1270 NewStringCat (ConfigResp, Node->Name); 1271 NewStringCat (ConfigResp, L"="); 1272 if (GetEditBuf) { 1273 NewStringCat (ConfigResp, Node->EditValue); 1274 } else { 1275 NewStringCat (ConfigResp, Node->Value); 1276 } 1277 } 1278 Link = GetNextNode (&Storage->NameValueListHead, Link); 1279 } 1280 break; 1281 1282 case EFI_HII_VARSTORE_EFI_VARIABLE: 1283 default: 1284 Status = EFI_INVALID_PARAMETER; 1285 break; 1286 } 1287 1288 return Status; 1289 } 1290 1291 1292 /** 1293 Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage. 1294 1295 @param Storage The Storage to receive the settings. 1296 @param ConfigResp The <ConfigResp> to be converted. 1297 1298 @retval EFI_SUCCESS Convert success. 1299 @retval EFI_INVALID_PARAMETER Incorrect storage type. 1300 1301 **/ 1302 EFI_STATUS 1303 ConfigRespToStorage ( 1304 IN BROWSER_STORAGE *Storage, 1305 IN CHAR16 *ConfigResp 1306 ) 1307 { 1308 EFI_STATUS Status; 1309 EFI_STRING Progress; 1310 UINTN BufferSize; 1311 CHAR16 *StrPtr; 1312 CHAR16 *Name; 1313 CHAR16 *Value; 1314 1315 Status = EFI_SUCCESS; 1316 1317 switch (Storage->Type) { 1318 case EFI_HII_VARSTORE_BUFFER: 1319 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: 1320 BufferSize = Storage->Size; 1321 Status = mHiiConfigRouting->ConfigToBlock ( 1322 mHiiConfigRouting, 1323 ConfigResp, 1324 Storage->EditBuffer, 1325 &BufferSize, 1326 &Progress 1327 ); 1328 break; 1329 1330 case EFI_HII_VARSTORE_NAME_VALUE: 1331 StrPtr = StrStr (ConfigResp, L"PATH"); 1332 if (StrPtr == NULL) { 1333 break; 1334 } 1335 StrPtr = StrStr (ConfigResp, L"&"); 1336 while (StrPtr != NULL) { 1337 // 1338 // Skip '&' 1339 // 1340 StrPtr = StrPtr + 1; 1341 Name = StrPtr; 1342 StrPtr = StrStr (StrPtr, L"="); 1343 if (StrPtr == NULL) { 1344 break; 1345 } 1346 *StrPtr = 0; 1347 1348 // 1349 // Skip '=' 1350 // 1351 StrPtr = StrPtr + 1; 1352 Value = StrPtr; 1353 StrPtr = StrStr (StrPtr, L"&"); 1354 if (StrPtr != NULL) { 1355 *StrPtr = 0; 1356 } 1357 SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL); 1358 } 1359 break; 1360 1361 case EFI_HII_VARSTORE_EFI_VARIABLE: 1362 default: 1363 Status = EFI_INVALID_PARAMETER; 1364 break; 1365 } 1366 1367 return Status; 1368 } 1369 1370 /** 1371 Convert the buffer value to HiiValue. 1372 1373 @param Question The question. 1374 @param Value Unicode buffer save the question value. 1375 1376 @retval Status whether convert the value success. 1377 1378 **/ 1379 EFI_STATUS 1380 BufferToValue ( 1381 IN OUT FORM_BROWSER_STATEMENT *Question, 1382 IN CHAR16 *Value 1383 ) 1384 { 1385 CHAR16 *StringPtr; 1386 BOOLEAN IsBufferStorage; 1387 CHAR16 *DstBuf; 1388 CHAR16 TempChar; 1389 UINTN LengthStr; 1390 UINT8 *Dst; 1391 CHAR16 TemStr[5]; 1392 UINTN Index; 1393 UINT8 DigitUint8; 1394 BOOLEAN IsString; 1395 UINTN Length; 1396 EFI_STATUS Status; 1397 1398 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); 1399 if (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER || 1400 Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 1401 IsBufferStorage = TRUE; 1402 } else { 1403 IsBufferStorage = FALSE; 1404 } 1405 1406 // 1407 // Question Value is provided by Buffer Storage or NameValue Storage 1408 // 1409 if (Question->BufferValue != NULL) { 1410 // 1411 // This Question is password or orderedlist 1412 // 1413 Dst = Question->BufferValue; 1414 } else { 1415 // 1416 // Other type of Questions 1417 // 1418 Dst = (UINT8 *) &Question->HiiValue.Value; 1419 } 1420 1421 // 1422 // Temp cut at the end of this section, end with '\0' or '&'. 1423 // 1424 StringPtr = Value; 1425 while (*StringPtr != L'\0' && *StringPtr != L'&') { 1426 StringPtr++; 1427 } 1428 TempChar = *StringPtr; 1429 *StringPtr = L'\0'; 1430 1431 LengthStr = StrLen (Value); 1432 1433 // 1434 // Value points to a Unicode hexadecimal string, we need to convert the string to the value with CHAR16/UINT8...type. 1435 // When generating the Value string, we follow this rule: 1 byte -> 2 Unicode characters (for string: 2 byte(CHAR16) ->4 Unicode characters). 1436 // So the maximum value string length of a question is : Question->StorageWidth * 2. 1437 // If the value string length > Question->StorageWidth * 2, only set the string length as Question->StorageWidth * 2, then convert. 1438 // 1439 if (LengthStr > (UINTN) Question->StorageWidth * 2) { 1440 Length = (UINTN) Question->StorageWidth * 2; 1441 } else { 1442 Length = LengthStr; 1443 } 1444 1445 Status = EFI_SUCCESS; 1446 if (!IsBufferStorage && IsString) { 1447 // 1448 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" 1449 // Add string tail char L'\0' into Length 1450 // 1451 DstBuf = (CHAR16 *) Dst; 1452 ZeroMem (TemStr, sizeof (TemStr)); 1453 for (Index = 0; Index < Length; Index += 4) { 1454 StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4); 1455 DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr); 1456 } 1457 // 1458 // Add tailing L'\0' character 1459 // 1460 DstBuf[Index/4] = L'\0'; 1461 } else { 1462 ZeroMem (TemStr, sizeof (TemStr)); 1463 for (Index = 0; Index < Length; Index ++) { 1464 TemStr[0] = Value[LengthStr - Index - 1]; 1465 DigitUint8 = (UINT8) StrHexToUint64 (TemStr); 1466 if ((Index & 1) == 0) { 1467 Dst [Index/2] = DigitUint8; 1468 } else { 1469 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]); 1470 } 1471 } 1472 } 1473 1474 *StringPtr = TempChar; 1475 1476 return Status; 1477 } 1478 1479 /** 1480 Get Question's current Value. 1481 1482 @param FormSet FormSet data structure. 1483 @param Form Form data structure. 1484 @param Question Question to be initialized. 1485 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. 1486 1487 @retval EFI_SUCCESS The function completed successfully. 1488 1489 **/ 1490 EFI_STATUS 1491 GetQuestionValue ( 1492 IN FORM_BROWSER_FORMSET *FormSet, 1493 IN FORM_BROWSER_FORM *Form, 1494 IN OUT FORM_BROWSER_STATEMENT *Question, 1495 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom 1496 ) 1497 { 1498 EFI_STATUS Status; 1499 BOOLEAN Enabled; 1500 BOOLEAN Pending; 1501 UINT8 *Dst; 1502 UINTN StorageWidth; 1503 EFI_TIME EfiTime; 1504 BROWSER_STORAGE *Storage; 1505 FORMSET_STORAGE *FormsetStorage; 1506 EFI_IFR_TYPE_VALUE *QuestionValue; 1507 CHAR16 *ConfigRequest; 1508 CHAR16 *Progress; 1509 CHAR16 *Result; 1510 CHAR16 *Value; 1511 UINTN Length; 1512 BOOLEAN IsBufferStorage; 1513 UINTN MaxLen; 1514 1515 Status = EFI_SUCCESS; 1516 Value = NULL; 1517 Result = NULL; 1518 1519 if (GetValueFrom >= GetSetValueWithMax) { 1520 return EFI_INVALID_PARAMETER; 1521 } 1522 1523 // 1524 // Question value is provided by an Expression, evaluate it 1525 // 1526 if (Question->ValueExpression != NULL) { 1527 Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); 1528 if (!EFI_ERROR (Status)) { 1529 if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { 1530 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL); 1531 if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) { 1532 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen); 1533 Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen; 1534 } else { 1535 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth); 1536 Question->HiiValue.BufferLen = Question->StorageWidth; 1537 } 1538 FreePool (Question->ValueExpression->Result.Buffer); 1539 } 1540 Question->HiiValue.Type = Question->ValueExpression->Result.Type; 1541 CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); 1542 } 1543 return Status; 1544 } 1545 1546 // 1547 // Get question value by read expression. 1548 // 1549 if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) { 1550 Status = EvaluateExpression (FormSet, Form, Question->ReadExpression); 1551 if (!EFI_ERROR (Status) && 1552 ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) { 1553 // 1554 // Only update question value to the valid result. 1555 // 1556 if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { 1557 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL); 1558 if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) { 1559 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen); 1560 Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen; 1561 } else { 1562 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth); 1563 Question->HiiValue.BufferLen = Question->StorageWidth; 1564 } 1565 FreePool (Question->ReadExpression->Result.Buffer); 1566 } 1567 Question->HiiValue.Type = Question->ReadExpression->Result.Type; 1568 CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); 1569 return EFI_SUCCESS; 1570 } 1571 } 1572 1573 // 1574 // Question value is provided by RTC 1575 // 1576 Storage = Question->Storage; 1577 QuestionValue = &Question->HiiValue.Value; 1578 if (Storage == NULL) { 1579 // 1580 // It's a Question without storage, or RTC date/time 1581 // 1582 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { 1583 // 1584 // Date and time define the same Flags bit 1585 // 1586 switch (Question->Flags & EFI_QF_DATE_STORAGE) { 1587 case QF_DATE_STORAGE_TIME: 1588 Status = gRT->GetTime (&EfiTime, NULL); 1589 break; 1590 1591 case QF_DATE_STORAGE_WAKEUP: 1592 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); 1593 break; 1594 1595 case QF_DATE_STORAGE_NORMAL: 1596 default: 1597 // 1598 // For date/time without storage 1599 // 1600 return EFI_SUCCESS; 1601 } 1602 1603 if (EFI_ERROR (Status)) { 1604 if (Question->Operand == EFI_IFR_DATE_OP){ 1605 QuestionValue->date.Year = 0xff; 1606 QuestionValue->date.Month = 0xff; 1607 QuestionValue->date.Day = 0xff; 1608 } else { 1609 QuestionValue->time.Hour = 0xff; 1610 QuestionValue->time.Minute = 0xff; 1611 QuestionValue->time.Second = 0xff; 1612 } 1613 return EFI_SUCCESS; 1614 } 1615 1616 if (Question->Operand == EFI_IFR_DATE_OP) { 1617 QuestionValue->date.Year = EfiTime.Year; 1618 QuestionValue->date.Month = EfiTime.Month; 1619 QuestionValue->date.Day = EfiTime.Day; 1620 } else { 1621 QuestionValue->time.Hour = EfiTime.Hour; 1622 QuestionValue->time.Minute = EfiTime.Minute; 1623 QuestionValue->time.Second = EfiTime.Second; 1624 } 1625 } 1626 1627 return EFI_SUCCESS; 1628 } 1629 1630 // 1631 // Question value is provided by EFI variable 1632 // 1633 StorageWidth = Question->StorageWidth; 1634 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 1635 if (Question->BufferValue != NULL) { 1636 Dst = Question->BufferValue; 1637 } else { 1638 Dst = (UINT8 *) QuestionValue; 1639 } 1640 1641 Status = gRT->GetVariable ( 1642 Question->VariableName, 1643 &Storage->Guid, 1644 NULL, 1645 &StorageWidth, 1646 Dst 1647 ); 1648 // 1649 // Always return success, even this EFI variable doesn't exist 1650 // 1651 return EFI_SUCCESS; 1652 } 1653 1654 // 1655 // Question Value is provided by Buffer Storage or NameValue Storage 1656 // 1657 if (Question->BufferValue != NULL) { 1658 // 1659 // This Question is password or orderedlist 1660 // 1661 Dst = Question->BufferValue; 1662 } else { 1663 // 1664 // Other type of Questions 1665 // 1666 Dst = (UINT8 *) &Question->HiiValue.Value; 1667 } 1668 1669 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 1670 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 1671 IsBufferStorage = TRUE; 1672 } else { 1673 IsBufferStorage = FALSE; 1674 } 1675 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) { 1676 if (IsBufferStorage) { 1677 if (GetValueFrom == GetSetValueWithEditBuffer) { 1678 // 1679 // Copy from storage Edit buffer 1680 // 1681 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); 1682 } else { 1683 // 1684 // Copy from storage Edit buffer 1685 // 1686 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth); 1687 } 1688 } else { 1689 Value = NULL; 1690 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom); 1691 if (EFI_ERROR (Status)) { 1692 return Status; 1693 } 1694 1695 ASSERT (Value != NULL); 1696 Status = BufferToValue (Question, Value); 1697 FreePool (Value); 1698 } 1699 } else { 1700 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId); 1701 ASSERT (FormsetStorage != NULL); 1702 // 1703 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || 1704 // <ConfigHdr> + "&" + <VariableName> 1705 // 1706 if (IsBufferStorage) { 1707 Length = StrLen (FormsetStorage->ConfigHdr); 1708 Length += StrLen (Question->BlockName); 1709 } else { 1710 Length = StrLen (FormsetStorage->ConfigHdr); 1711 Length += StrLen (Question->VariableName) + 1; 1712 } 1713 // Allocate buffer include '\0' 1714 MaxLen = Length + 1; 1715 ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 1716 ASSERT (ConfigRequest != NULL); 1717 1718 StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr); 1719 if (IsBufferStorage) { 1720 StrCatS (ConfigRequest, MaxLen, Question->BlockName); 1721 } else { 1722 StrCatS (ConfigRequest, MaxLen, L"&"); 1723 StrCatS (ConfigRequest, MaxLen, Question->VariableName); 1724 } 1725 1726 // 1727 // Request current settings from Configuration Driver 1728 // 1729 Status = mHiiConfigRouting->ExtractConfig ( 1730 mHiiConfigRouting, 1731 ConfigRequest, 1732 &Progress, 1733 &Result 1734 ); 1735 FreePool (ConfigRequest); 1736 if (EFI_ERROR (Status)) { 1737 return Status; 1738 } 1739 1740 // 1741 // Skip <ConfigRequest> 1742 // 1743 if (IsBufferStorage) { 1744 Value = StrStr (Result, L"&VALUE"); 1745 if (Value == NULL) { 1746 FreePool (Result); 1747 return EFI_NOT_FOUND; 1748 } 1749 // 1750 // Skip "&VALUE" 1751 // 1752 Value = Value + 6; 1753 } else { 1754 Value = Result + Length; 1755 } 1756 if (*Value != '=') { 1757 FreePool (Result); 1758 return EFI_NOT_FOUND; 1759 } 1760 // 1761 // Skip '=', point to value 1762 // 1763 Value = Value + 1; 1764 1765 Status = BufferToValue (Question, Value); 1766 if (EFI_ERROR (Status)) { 1767 FreePool (Result); 1768 return Status; 1769 } 1770 1771 // 1772 // Synchronize Edit Buffer 1773 // 1774 if (IsBufferStorage) { 1775 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); 1776 } else { 1777 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL); 1778 } 1779 1780 if (Result != NULL) { 1781 FreePool (Result); 1782 } 1783 } 1784 1785 return Status; 1786 } 1787 1788 1789 /** 1790 Save Question Value to edit copy(cached) or Storage(uncached). 1791 1792 @param FormSet FormSet data structure. 1793 @param Form Form data structure. 1794 @param Question Pointer to the Question. 1795 @param SetValueTo Update the question value to editbuffer , buffer or hii driver. 1796 1797 @retval EFI_SUCCESS The function completed successfully. 1798 1799 **/ 1800 EFI_STATUS 1801 SetQuestionValue ( 1802 IN FORM_BROWSER_FORMSET *FormSet, 1803 IN FORM_BROWSER_FORM *Form, 1804 IN OUT FORM_BROWSER_STATEMENT *Question, 1805 IN GET_SET_QUESTION_VALUE_WITH SetValueTo 1806 ) 1807 { 1808 EFI_STATUS Status; 1809 BOOLEAN Enabled; 1810 BOOLEAN Pending; 1811 UINT8 *Src; 1812 EFI_TIME EfiTime; 1813 UINTN BufferLen; 1814 UINTN StorageWidth; 1815 BROWSER_STORAGE *Storage; 1816 FORMSET_STORAGE *FormsetStorage; 1817 EFI_IFR_TYPE_VALUE *QuestionValue; 1818 CHAR16 *ConfigResp; 1819 CHAR16 *Progress; 1820 CHAR16 *Value; 1821 UINTN Length; 1822 BOOLEAN IsBufferStorage; 1823 BOOLEAN IsString; 1824 UINT8 *TemBuffer; 1825 CHAR16 *TemName; 1826 CHAR16 *TemString; 1827 UINTN Index; 1828 NAME_VALUE_NODE *Node; 1829 UINTN MaxLen; 1830 1831 Status = EFI_SUCCESS; 1832 Node = NULL; 1833 1834 if (SetValueTo >= GetSetValueWithMax) { 1835 return EFI_INVALID_PARAMETER; 1836 } 1837 1838 // 1839 // If Question value is provided by an Expression, then it is read only 1840 // 1841 if (Question->ValueExpression != NULL) { 1842 return Status; 1843 } 1844 1845 // 1846 // Before set question value, evaluate its write expression. 1847 // 1848 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) { 1849 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression); 1850 if (EFI_ERROR (Status)) { 1851 return Status; 1852 } 1853 } 1854 1855 // 1856 // Question value is provided by RTC 1857 // 1858 Storage = Question->Storage; 1859 QuestionValue = &Question->HiiValue.Value; 1860 if (Storage == NULL) { 1861 // 1862 // It's a Question without storage, or RTC date/time 1863 // 1864 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { 1865 // 1866 // Date and time define the same Flags bit 1867 // 1868 switch (Question->Flags & EFI_QF_DATE_STORAGE) { 1869 case QF_DATE_STORAGE_TIME: 1870 Status = gRT->GetTime (&EfiTime, NULL); 1871 break; 1872 1873 case QF_DATE_STORAGE_WAKEUP: 1874 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); 1875 break; 1876 1877 case QF_DATE_STORAGE_NORMAL: 1878 default: 1879 // 1880 // For date/time without storage 1881 // 1882 return EFI_SUCCESS; 1883 } 1884 1885 if (EFI_ERROR (Status)) { 1886 return Status; 1887 } 1888 1889 if (Question->Operand == EFI_IFR_DATE_OP) { 1890 EfiTime.Year = QuestionValue->date.Year; 1891 EfiTime.Month = QuestionValue->date.Month; 1892 EfiTime.Day = QuestionValue->date.Day; 1893 } else { 1894 EfiTime.Hour = QuestionValue->time.Hour; 1895 EfiTime.Minute = QuestionValue->time.Minute; 1896 EfiTime.Second = QuestionValue->time.Second; 1897 } 1898 1899 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { 1900 Status = gRT->SetTime (&EfiTime); 1901 } else { 1902 Status = gRT->SetWakeupTime (TRUE, &EfiTime); 1903 } 1904 } 1905 1906 return Status; 1907 } 1908 1909 // 1910 // Question value is provided by EFI variable 1911 // 1912 StorageWidth = Question->StorageWidth; 1913 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 1914 if (Question->BufferValue != NULL) { 1915 Src = Question->BufferValue; 1916 } else { 1917 Src = (UINT8 *) QuestionValue; 1918 } 1919 1920 Status = gRT->SetVariable ( 1921 Question->VariableName, 1922 &Storage->Guid, 1923 Storage->Attributes, 1924 StorageWidth, 1925 Src 1926 ); 1927 return Status; 1928 } 1929 1930 // 1931 // Question Value is provided by Buffer Storage or NameValue Storage 1932 // 1933 if (Question->BufferValue != NULL) { 1934 Src = Question->BufferValue; 1935 } else { 1936 Src = (UINT8 *) &Question->HiiValue.Value; 1937 } 1938 1939 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 1940 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 1941 IsBufferStorage = TRUE; 1942 } else { 1943 IsBufferStorage = FALSE; 1944 } 1945 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); 1946 1947 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) { 1948 if (IsBufferStorage) { 1949 if (SetValueTo == GetSetValueWithEditBuffer) { 1950 // 1951 // Copy to storage edit buffer 1952 // 1953 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); 1954 } else if (SetValueTo == GetSetValueWithBuffer) { 1955 // 1956 // Copy to storage edit buffer 1957 // 1958 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); 1959 } 1960 } else { 1961 if (IsString) { 1962 // 1963 // Allocate enough string buffer. 1964 // 1965 Value = NULL; 1966 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16); 1967 Value = AllocateZeroPool (BufferLen); 1968 ASSERT (Value != NULL); 1969 // 1970 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" 1971 // 1972 TemName = (CHAR16 *) Src; 1973 TemString = Value; 1974 for (; *TemName != L'\0'; TemName++) { 1975 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4); 1976 } 1977 } else { 1978 BufferLen = StorageWidth * 2 + 1; 1979 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16)); 1980 ASSERT (Value != NULL); 1981 // 1982 // Convert Buffer to Hex String 1983 // 1984 TemBuffer = Src + StorageWidth - 1; 1985 TemString = Value; 1986 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) { 1987 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); 1988 } 1989 } 1990 1991 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node); 1992 FreePool (Value); 1993 if (EFI_ERROR (Status)) { 1994 return Status; 1995 } 1996 } 1997 } else if (SetValueTo == GetSetValueWithHiiDriver) { 1998 // 1999 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" || 2000 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>" 2001 // 2002 if (IsBufferStorage) { 2003 Length = StrLen (Question->BlockName) + 7; 2004 } else { 2005 Length = StrLen (Question->VariableName) + 2; 2006 } 2007 if (!IsBufferStorage && IsString) { 2008 Length += (StrLen ((CHAR16 *) Src) * 4); 2009 } else { 2010 Length += (StorageWidth * 2); 2011 } 2012 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId); 2013 ASSERT (FormsetStorage != NULL); 2014 MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1; 2015 ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 2016 ASSERT (ConfigResp != NULL); 2017 2018 StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr); 2019 if (IsBufferStorage) { 2020 StrCatS (ConfigResp, MaxLen, Question->BlockName); 2021 StrCatS (ConfigResp, MaxLen, L"&VALUE="); 2022 } else { 2023 StrCatS (ConfigResp, MaxLen, L"&"); 2024 StrCatS (ConfigResp, MaxLen, Question->VariableName); 2025 StrCatS (ConfigResp, MaxLen, L"="); 2026 } 2027 2028 Value = ConfigResp + StrLen (ConfigResp); 2029 2030 if (!IsBufferStorage && IsString) { 2031 // 2032 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" 2033 // 2034 TemName = (CHAR16 *) Src; 2035 TemString = Value; 2036 for (; *TemName != L'\0'; TemName++) { 2037 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4); 2038 } 2039 } else { 2040 // 2041 // Convert Buffer to Hex String 2042 // 2043 TemBuffer = Src + StorageWidth - 1; 2044 TemString = Value; 2045 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) { 2046 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); 2047 } 2048 } 2049 2050 // 2051 // Convert to lower char. 2052 // 2053 for (TemString = Value; *Value != L'\0'; Value++) { 2054 if (*Value >= L'A' && *Value <= L'Z') { 2055 *Value = (CHAR16) (*Value - L'A' + L'a'); 2056 } 2057 } 2058 2059 // 2060 // Submit Question Value to Configuration Driver 2061 // 2062 Status = mHiiConfigRouting->RouteConfig ( 2063 mHiiConfigRouting, 2064 ConfigResp, 2065 &Progress 2066 ); 2067 if (EFI_ERROR (Status)) { 2068 FreePool (ConfigResp); 2069 return Status; 2070 } 2071 FreePool (ConfigResp); 2072 2073 // 2074 // Sync storage, from editbuffer to buffer. 2075 // 2076 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); 2077 } 2078 2079 return Status; 2080 } 2081 2082 2083 /** 2084 Perform nosubmitif check for a Form. 2085 2086 @param FormSet FormSet data structure. 2087 @param Form Form data structure. 2088 @param Question The Question to be validated. 2089 @param Type Validation type: NoSubmit 2090 2091 @retval EFI_SUCCESS Form validation pass. 2092 @retval other Form validation failed. 2093 2094 **/ 2095 EFI_STATUS 2096 ValidateQuestion ( 2097 IN FORM_BROWSER_FORMSET *FormSet, 2098 IN FORM_BROWSER_FORM *Form, 2099 IN FORM_BROWSER_STATEMENT *Question, 2100 IN UINTN Type 2101 ) 2102 { 2103 EFI_STATUS Status; 2104 LIST_ENTRY *Link; 2105 LIST_ENTRY *ListHead; 2106 FORM_EXPRESSION *Expression; 2107 UINT32 BrowserStatus; 2108 CHAR16 *ErrorStr; 2109 2110 BrowserStatus = BROWSER_SUCCESS; 2111 ErrorStr = NULL; 2112 2113 switch (Type) { 2114 case EFI_HII_EXPRESSION_INCONSISTENT_IF: 2115 ListHead = &Question->InconsistentListHead; 2116 break; 2117 2118 case EFI_HII_EXPRESSION_WARNING_IF: 2119 ListHead = &Question->WarningListHead; 2120 break; 2121 2122 case EFI_HII_EXPRESSION_NO_SUBMIT_IF: 2123 ListHead = &Question->NoSubmitListHead; 2124 break; 2125 2126 default: 2127 ASSERT (FALSE); 2128 return EFI_UNSUPPORTED; 2129 } 2130 2131 Link = GetFirstNode (ListHead); 2132 while (!IsNull (ListHead, Link)) { 2133 Expression = FORM_EXPRESSION_FROM_LINK (Link); 2134 2135 // 2136 // Evaluate the expression 2137 // 2138 Status = EvaluateExpression (FormSet, Form, Expression); 2139 if (EFI_ERROR (Status)) { 2140 return Status; 2141 } 2142 2143 if (IsTrue (&Expression->Result)) { 2144 switch (Type) { 2145 case EFI_HII_EXPRESSION_INCONSISTENT_IF: 2146 BrowserStatus = BROWSER_INCONSISTENT_IF; 2147 break; 2148 2149 case EFI_HII_EXPRESSION_WARNING_IF: 2150 BrowserStatus = BROWSER_WARNING_IF; 2151 break; 2152 2153 case EFI_HII_EXPRESSION_NO_SUBMIT_IF: 2154 BrowserStatus = BROWSER_NO_SUBMIT_IF; 2155 // 2156 // This code only used to compatible with old display engine, 2157 // New display engine will not use this field. 2158 // 2159 if (Expression->Error != 0) { 2160 ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle); 2161 } 2162 break; 2163 2164 default: 2165 ASSERT (FALSE); 2166 break; 2167 } 2168 2169 if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) { 2170 // 2171 // If in system submit process and for no_submit_if check, not popup this error message. 2172 // Will process this fail again later in not system submit process. 2173 // 2174 PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr); 2175 } 2176 2177 if (ErrorStr != NULL) { 2178 FreePool (ErrorStr); 2179 } 2180 2181 if (Type == EFI_HII_EXPRESSION_WARNING_IF) { 2182 return EFI_SUCCESS; 2183 } else { 2184 return EFI_NOT_READY; 2185 } 2186 } 2187 2188 Link = GetNextNode (ListHead, Link); 2189 } 2190 2191 return EFI_SUCCESS; 2192 } 2193 2194 /** 2195 Perform question check. 2196 2197 If one question has more than one check, process form high priority to low. 2198 Only one error info will be popup. 2199 2200 @param FormSet FormSet data structure. 2201 @param Form Form data structure. 2202 @param Question The Question to be validated. 2203 2204 @retval EFI_SUCCESS Form validation pass. 2205 @retval other Form validation failed. 2206 2207 **/ 2208 EFI_STATUS 2209 ValueChangedValidation ( 2210 IN FORM_BROWSER_FORMSET *FormSet, 2211 IN FORM_BROWSER_FORM *Form, 2212 IN FORM_BROWSER_STATEMENT *Question 2213 ) 2214 { 2215 EFI_STATUS Status; 2216 2217 Status = EFI_SUCCESS; 2218 2219 // 2220 // Do the inconsistentif check. 2221 // 2222 if (!IsListEmpty (&Question->InconsistentListHead)) { 2223 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); 2224 if (EFI_ERROR (Status)) { 2225 return Status; 2226 } 2227 } 2228 2229 // 2230 // Do the warningif check. 2231 // 2232 if (!IsListEmpty (&Question->WarningListHead)) { 2233 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF); 2234 } 2235 2236 return Status; 2237 } 2238 2239 /** 2240 Perform NoSubmit check for each Form in FormSet. 2241 2242 @param FormSet FormSet data structure. 2243 @param CurrentForm Current input form data structure. 2244 @param Statement The statement for this check. 2245 2246 @retval EFI_SUCCESS Form validation pass. 2247 @retval other Form validation failed. 2248 2249 **/ 2250 EFI_STATUS 2251 NoSubmitCheck ( 2252 IN FORM_BROWSER_FORMSET *FormSet, 2253 IN OUT FORM_BROWSER_FORM **CurrentForm, 2254 OUT FORM_BROWSER_STATEMENT **Statement 2255 ) 2256 { 2257 EFI_STATUS Status; 2258 LIST_ENTRY *Link; 2259 FORM_BROWSER_STATEMENT *Question; 2260 FORM_BROWSER_FORM *Form; 2261 LIST_ENTRY *LinkForm; 2262 2263 LinkForm = GetFirstNode (&FormSet->FormListHead); 2264 while (!IsNull (&FormSet->FormListHead, LinkForm)) { 2265 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm); 2266 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm); 2267 2268 if (*CurrentForm != NULL && *CurrentForm != Form) { 2269 continue; 2270 } 2271 2272 Link = GetFirstNode (&Form->StatementListHead); 2273 while (!IsNull (&Form->StatementListHead, Link)) { 2274 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2275 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); 2276 if (EFI_ERROR (Status)) { 2277 if (*CurrentForm == NULL) { 2278 *CurrentForm = Form; 2279 } 2280 if (Statement != NULL) { 2281 *Statement = Question; 2282 } 2283 return Status; 2284 } 2285 2286 Link = GetNextNode (&Form->StatementListHead, Link); 2287 } 2288 } 2289 2290 return EFI_SUCCESS; 2291 } 2292 2293 /** 2294 Fill storage's edit copy with settings requested from Configuration Driver. 2295 2296 @param Storage The storage which need to sync. 2297 @param ConfigRequest The config request string which used to sync storage. 2298 @param SyncOrRestore Sync the buffer to editbuffer or Restore the 2299 editbuffer to buffer 2300 if TRUE, copy the editbuffer to the buffer. 2301 if FALSE, copy the buffer to the editbuffer. 2302 2303 @retval EFI_SUCCESS The function completed successfully. 2304 2305 **/ 2306 EFI_STATUS 2307 SynchronizeStorage ( 2308 OUT BROWSER_STORAGE *Storage, 2309 IN CHAR16 *ConfigRequest, 2310 IN BOOLEAN SyncOrRestore 2311 ) 2312 { 2313 EFI_STATUS Status; 2314 EFI_STRING Progress; 2315 EFI_STRING Result; 2316 UINTN BufferSize; 2317 LIST_ENTRY *Link; 2318 NAME_VALUE_NODE *Node; 2319 UINT8 *Src; 2320 UINT8 *Dst; 2321 2322 Status = EFI_SUCCESS; 2323 Result = NULL; 2324 2325 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 2326 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 2327 BufferSize = Storage->Size; 2328 2329 if (SyncOrRestore) { 2330 Src = Storage->EditBuffer; 2331 Dst = Storage->Buffer; 2332 } else { 2333 Src = Storage->Buffer; 2334 Dst = Storage->EditBuffer; 2335 } 2336 2337 if (ConfigRequest != NULL) { 2338 Status = mHiiConfigRouting->BlockToConfig( 2339 mHiiConfigRouting, 2340 ConfigRequest, 2341 Src, 2342 BufferSize, 2343 &Result, 2344 &Progress 2345 ); 2346 if (EFI_ERROR (Status)) { 2347 return Status; 2348 } 2349 2350 Status = mHiiConfigRouting->ConfigToBlock ( 2351 mHiiConfigRouting, 2352 Result, 2353 Dst, 2354 &BufferSize, 2355 &Progress 2356 ); 2357 if (Result != NULL) { 2358 FreePool (Result); 2359 } 2360 } else { 2361 CopyMem (Dst, Src, BufferSize); 2362 } 2363 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2364 Link = GetFirstNode (&Storage->NameValueListHead); 2365 while (!IsNull (&Storage->NameValueListHead, Link)) { 2366 Node = NAME_VALUE_NODE_FROM_LINK (Link); 2367 2368 if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) || 2369 (ConfigRequest == NULL)) { 2370 if (SyncOrRestore) { 2371 NewStringCpy (&Node->Value, Node->EditValue); 2372 } else { 2373 NewStringCpy (&Node->EditValue, Node->Value); 2374 } 2375 } 2376 2377 Link = GetNextNode (&Storage->NameValueListHead, Link); 2378 } 2379 } 2380 2381 return Status; 2382 } 2383 2384 /** 2385 When discard the question value, call the callback function with Changed type 2386 to inform the hii driver. 2387 2388 @param FormSet FormSet data structure. 2389 @param Form Form data structure. 2390 2391 **/ 2392 VOID 2393 SendDiscardInfoToDriver ( 2394 IN FORM_BROWSER_FORMSET *FormSet, 2395 IN FORM_BROWSER_FORM *Form 2396 ) 2397 { 2398 LIST_ENTRY *Link; 2399 FORM_BROWSER_STATEMENT *Question; 2400 EFI_IFR_TYPE_VALUE *TypeValue; 2401 EFI_BROWSER_ACTION_REQUEST ActionRequest; 2402 2403 if (FormSet->ConfigAccess == NULL) { 2404 return; 2405 } 2406 2407 Link = GetFirstNode (&Form->StatementListHead); 2408 while (!IsNull (&Form->StatementListHead, Link)) { 2409 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2410 Link = GetNextNode (&Form->StatementListHead, Link); 2411 2412 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 2413 continue; 2414 } 2415 2416 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { 2417 continue; 2418 } 2419 2420 if (Question->Operand == EFI_IFR_PASSWORD_OP) { 2421 continue; 2422 } 2423 2424 if (!Question->ValueChanged) { 2425 continue; 2426 } 2427 2428 // 2429 // Restore the question value before call the CHANGED callback type. 2430 // 2431 GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 2432 2433 if (Question->Operand == EFI_IFR_STRING_OP){ 2434 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); 2435 } 2436 2437 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { 2438 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue; 2439 } else { 2440 TypeValue = &Question->HiiValue.Value; 2441 } 2442 2443 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 2444 FormSet->ConfigAccess->Callback ( 2445 FormSet->ConfigAccess, 2446 EFI_BROWSER_ACTION_CHANGED, 2447 Question->QuestionId, 2448 Question->HiiValue.Type, 2449 TypeValue, 2450 &ActionRequest 2451 ); 2452 } 2453 } 2454 2455 /** 2456 When submit the question value, call the callback function with Submitted type 2457 to inform the hii driver. 2458 2459 @param FormSet FormSet data structure. 2460 @param Form Form data structure. 2461 2462 **/ 2463 VOID 2464 SubmitCallbackForForm ( 2465 IN FORM_BROWSER_FORMSET *FormSet, 2466 IN FORM_BROWSER_FORM *Form 2467 ) 2468 { 2469 LIST_ENTRY *Link; 2470 FORM_BROWSER_STATEMENT *Question; 2471 EFI_IFR_TYPE_VALUE *TypeValue; 2472 EFI_BROWSER_ACTION_REQUEST ActionRequest; 2473 2474 if (FormSet->ConfigAccess == NULL) { 2475 return; 2476 } 2477 2478 Link = GetFirstNode (&Form->StatementListHead); 2479 while (!IsNull (&Form->StatementListHead, Link)) { 2480 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2481 Link = GetNextNode (&Form->StatementListHead, Link); 2482 2483 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 2484 continue; 2485 } 2486 2487 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { 2488 continue; 2489 } 2490 2491 if (Question->Operand == EFI_IFR_PASSWORD_OP) { 2492 continue; 2493 } 2494 2495 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { 2496 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue; 2497 } else { 2498 TypeValue = &Question->HiiValue.Value; 2499 } 2500 2501 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 2502 FormSet->ConfigAccess->Callback ( 2503 FormSet->ConfigAccess, 2504 EFI_BROWSER_ACTION_SUBMITTED, 2505 Question->QuestionId, 2506 Question->HiiValue.Type, 2507 TypeValue, 2508 &ActionRequest 2509 ); 2510 } 2511 } 2512 2513 /** 2514 When value set Success, call the submit callback function. 2515 2516 @param FormSet FormSet data structure. 2517 @param Form Form data structure. 2518 2519 **/ 2520 VOID 2521 SubmitCallback ( 2522 IN FORM_BROWSER_FORMSET *FormSet, 2523 IN FORM_BROWSER_FORM *Form 2524 ) 2525 { 2526 FORM_BROWSER_FORM *CurrentForm; 2527 LIST_ENTRY *Link; 2528 2529 if (Form != NULL) { 2530 SubmitCallbackForForm(FormSet, Form); 2531 return; 2532 } 2533 2534 Link = GetFirstNode (&FormSet->FormListHead); 2535 while (!IsNull (&FormSet->FormListHead, Link)) { 2536 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); 2537 Link = GetNextNode (&FormSet->FormListHead, Link); 2538 2539 SubmitCallbackForForm(FormSet, CurrentForm); 2540 } 2541 } 2542 2543 /** 2544 Validate the HiiHandle. 2545 2546 @param HiiHandle The input HiiHandle which need to validate. 2547 2548 @retval TRUE The handle is validate. 2549 @retval FALSE The handle is invalidate. 2550 2551 **/ 2552 BOOLEAN 2553 ValidateHiiHandle ( 2554 EFI_HII_HANDLE HiiHandle 2555 ) 2556 { 2557 EFI_HII_HANDLE *HiiHandles; 2558 UINTN Index; 2559 BOOLEAN Find; 2560 2561 if (HiiHandle == NULL) { 2562 return FALSE; 2563 } 2564 2565 Find = FALSE; 2566 2567 HiiHandles = HiiGetHiiHandles (NULL); 2568 ASSERT (HiiHandles != NULL); 2569 2570 for (Index = 0; HiiHandles[Index] != NULL; Index++) { 2571 if (HiiHandles[Index] == HiiHandle) { 2572 Find = TRUE; 2573 break; 2574 } 2575 } 2576 2577 FreePool (HiiHandles); 2578 2579 return Find; 2580 } 2581 2582 /** 2583 Validate the FormSet. If the formset is not validate, remove it from the list. 2584 2585 @param FormSet The input FormSet which need to validate. 2586 2587 @retval TRUE The handle is validate. 2588 @retval FALSE The handle is invalidate. 2589 2590 **/ 2591 BOOLEAN 2592 ValidateFormSet ( 2593 FORM_BROWSER_FORMSET *FormSet 2594 ) 2595 { 2596 BOOLEAN Find; 2597 2598 ASSERT (FormSet != NULL); 2599 2600 Find = ValidateHiiHandle(FormSet->HiiHandle); 2601 // 2602 // Should not remove the formset which is being used. 2603 // 2604 if (!Find && (FormSet != gCurrentSelection->FormSet)) { 2605 CleanBrowserStorage(FormSet); 2606 RemoveEntryList (&FormSet->Link); 2607 DestroyFormSet (FormSet); 2608 } 2609 2610 return Find; 2611 } 2612 /** 2613 Check whether need to enable the reset flag in form level. 2614 Also clean all ValueChanged flag in question. 2615 2616 @param SetFlag Whether need to set the Reset Flag. 2617 @param FormSet FormSet data structure. 2618 @param Form Form data structure. 2619 2620 **/ 2621 VOID 2622 UpdateFlagForForm ( 2623 IN BOOLEAN SetFlag, 2624 IN FORM_BROWSER_FORMSET *FormSet, 2625 IN FORM_BROWSER_FORM *Form 2626 ) 2627 { 2628 LIST_ENTRY *Link; 2629 FORM_BROWSER_STATEMENT *Question; 2630 BOOLEAN OldValue; 2631 2632 Link = GetFirstNode (&Form->StatementListHead); 2633 while (!IsNull (&Form->StatementListHead, Link)) { 2634 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2635 Link = GetNextNode (&Form->StatementListHead, Link); 2636 2637 if (!Question->ValueChanged) { 2638 continue; 2639 } 2640 2641 OldValue = Question->ValueChanged; 2642 2643 // 2644 // Compare the buffer and editbuffer data to see whether the data has been saved. 2645 // 2646 Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer); 2647 2648 // 2649 // Only the changed data has been saved, then need to set the reset flag. 2650 // 2651 if (SetFlag && OldValue && !Question->ValueChanged) { 2652 if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { 2653 gResetRequired = TRUE; 2654 } 2655 2656 if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { 2657 gFlagReconnect = TRUE; 2658 } 2659 } 2660 } 2661 } 2662 2663 /** 2664 Check whether need to enable the reset flag. 2665 Also clean ValueChanged flag for all statements. 2666 2667 Form level or formset level, only one. 2668 2669 @param SetFlag Whether need to set the Reset Flag. 2670 @param FormSet FormSet data structure. 2671 @param Form Form data structure. 2672 2673 **/ 2674 VOID 2675 ValueChangeResetFlagUpdate ( 2676 IN BOOLEAN SetFlag, 2677 IN FORM_BROWSER_FORMSET *FormSet, 2678 IN FORM_BROWSER_FORM *Form 2679 ) 2680 { 2681 FORM_BROWSER_FORM *CurrentForm; 2682 LIST_ENTRY *Link; 2683 2684 if (Form != NULL) { 2685 UpdateFlagForForm(SetFlag, FormSet, Form); 2686 return; 2687 } 2688 2689 Link = GetFirstNode (&FormSet->FormListHead); 2690 while (!IsNull (&FormSet->FormListHead, Link)) { 2691 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); 2692 Link = GetNextNode (&FormSet->FormListHead, Link); 2693 2694 UpdateFlagForForm(SetFlag, FormSet, CurrentForm); 2695 } 2696 } 2697 2698 /** 2699 Base on the return Progress string to find the form. 2700 2701 Base on the first return Offset/Width (Name) string to find the form 2702 which keep this string. 2703 2704 @param FormSet FormSet data structure. 2705 @param Storage Storage which has this Progress string. 2706 @param Progress The Progress string which has the first fail string. 2707 @param RetForm The return form for this progress string. 2708 @param RetQuestion The return question for the error progress string. 2709 2710 @retval TRUE Find the error form and statement for this error progress string. 2711 @retval FALSE Not find the error form. 2712 2713 **/ 2714 BOOLEAN 2715 FindQuestionFromProgress ( 2716 IN FORM_BROWSER_FORMSET *FormSet, 2717 IN BROWSER_STORAGE *Storage, 2718 IN EFI_STRING Progress, 2719 OUT FORM_BROWSER_FORM **RetForm, 2720 OUT FORM_BROWSER_STATEMENT **RetQuestion 2721 ) 2722 { 2723 LIST_ENTRY *Link; 2724 LIST_ENTRY *LinkStorage; 2725 LIST_ENTRY *LinkStatement; 2726 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 2727 FORM_BROWSER_FORM *Form; 2728 EFI_STRING EndStr; 2729 FORM_BROWSER_STATEMENT *Statement; 2730 2731 ASSERT ((*Progress == '&') || (*Progress == 'G')); 2732 2733 ConfigInfo = NULL; 2734 *RetForm = NULL; 2735 *RetQuestion = NULL; 2736 2737 // 2738 // Skip the first "&" or the ConfigHdr part. 2739 // 2740 if (*Progress == '&') { 2741 Progress++; 2742 } else { 2743 // 2744 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. 2745 // 2746 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2747 // 2748 // For Name/Value type, Skip the ConfigHdr part. 2749 // 2750 EndStr = StrStr (Progress, L"PATH="); 2751 ASSERT (EndStr != NULL); 2752 while (*EndStr != '&') { 2753 EndStr++; 2754 } 2755 2756 *EndStr = '\0'; 2757 } else { 2758 // 2759 // For Buffer type, Skip the ConfigHdr part. 2760 // 2761 EndStr = StrStr (Progress, L"&OFFSET="); 2762 ASSERT (EndStr != NULL); 2763 *EndStr = '\0'; 2764 } 2765 2766 Progress = EndStr + 1; 2767 } 2768 2769 // 2770 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. 2771 // 2772 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2773 // 2774 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset, 2775 // here, just keep the "Fred" string. 2776 // 2777 EndStr = StrStr (Progress, L"="); 2778 ASSERT (EndStr != NULL); 2779 *EndStr = '\0'; 2780 } else { 2781 // 2782 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####", 2783 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string. 2784 // 2785 EndStr = StrStr (Progress, L"&VALUE="); 2786 ASSERT (EndStr != NULL); 2787 *EndStr = '\0'; 2788 } 2789 2790 // 2791 // Search in the form list. 2792 // 2793 Link = GetFirstNode (&FormSet->FormListHead); 2794 while (!IsNull (&FormSet->FormListHead, Link)) { 2795 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 2796 Link = GetNextNode (&FormSet->FormListHead, Link); 2797 2798 // 2799 // Search in the ConfigReqeust list in this form. 2800 // 2801 LinkStorage = GetFirstNode (&Form->ConfigRequestHead); 2802 while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) { 2803 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage); 2804 LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage); 2805 2806 if (Storage != ConfigInfo->Storage) { 2807 continue; 2808 } 2809 2810 if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) { 2811 // 2812 // Find the OffsetWidth string in this form. 2813 // 2814 *RetForm = Form; 2815 break; 2816 } 2817 } 2818 2819 if (*RetForm != NULL) { 2820 LinkStatement = GetFirstNode (&Form->StatementListHead); 2821 while (!IsNull (&Form->StatementListHead, LinkStatement)) { 2822 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement); 2823 LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement); 2824 2825 if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) { 2826 *RetQuestion = Statement; 2827 break; 2828 } 2829 2830 if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) { 2831 *RetQuestion = Statement; 2832 break; 2833 } 2834 } 2835 } 2836 2837 if (*RetForm != NULL) { 2838 break; 2839 } 2840 } 2841 2842 // 2843 // restore the OffsetWidth string to the original format. 2844 // 2845 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2846 *EndStr = '='; 2847 } else { 2848 *EndStr = '&'; 2849 } 2850 2851 return (BOOLEAN) (*RetForm != NULL); 2852 } 2853 2854 /** 2855 Base on the return Progress string to get the SyncConfigRequest and RestoreConfigRequest 2856 for form and formset. 2857 2858 @param Storage Storage which has this Progress string. 2859 @param ConfigRequest The ConfigRequest string. 2860 @param Progress The Progress string which has the first fail string. 2861 @param RestoreConfigRequest Return the RestoreConfigRequest string. 2862 @param SyncConfigRequest Return the SyncConfigRequest string. 2863 2864 **/ 2865 VOID 2866 GetSyncRestoreConfigRequest( 2867 IN BROWSER_STORAGE *Storage, 2868 IN EFI_STRING ConfigRequest, 2869 IN EFI_STRING Progress, 2870 OUT EFI_STRING *RestoreConfigRequest, 2871 OUT EFI_STRING *SyncConfigRequest 2872 ) 2873 { 2874 EFI_STRING EndStr; 2875 EFI_STRING ConfigHdrEndStr; 2876 EFI_STRING ElementStr; 2877 UINTN TotalSize; 2878 UINTN RestoreEleSize; 2879 UINTN SyncSize; 2880 2881 ASSERT ((*Progress == L'&') || (*Progress == L'G')); 2882 // 2883 // If the Progress starts with ConfigHdr, means the failure is in the first name / value pair. 2884 // Need to restore all the fields in the ConfigRequest. 2885 // 2886 if (*Progress == L'G') { 2887 *RestoreConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); 2888 ASSERT (*RestoreConfigRequest != NULL); 2889 return; 2890 } 2891 2892 // 2893 // Find the first fail "NAME" or "OFFSET=0x####&WIDTH=0x####" string. 2894 // 2895 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2896 // 2897 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset, 2898 // here, just keep the "Fred" string. 2899 // 2900 EndStr = StrStr (Progress, L"="); 2901 ASSERT (EndStr != NULL); 2902 *EndStr = L'\0'; 2903 // 2904 // Find the ConfigHdr in ConfigRequest. 2905 // 2906 ConfigHdrEndStr = StrStr (ConfigRequest, L"PATH="); 2907 ASSERT (ConfigHdrEndStr != NULL); 2908 while (*ConfigHdrEndStr != L'&') { 2909 ConfigHdrEndStr++; 2910 } 2911 } else { 2912 // 2913 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####", 2914 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string. 2915 // 2916 EndStr = StrStr (Progress, L"&VALUE="); 2917 ASSERT (EndStr != NULL); 2918 *EndStr = L'\0'; 2919 // 2920 // Find the ConfigHdr in ConfigRequest. 2921 // 2922 ConfigHdrEndStr = StrStr (ConfigRequest, L"&OFFSET="); 2923 } 2924 // 2925 // Find the first fail pair in the ConfigRequest. 2926 // 2927 ElementStr = StrStr (ConfigRequest, Progress); 2928 ASSERT (ElementStr != NULL); 2929 // 2930 // To get the RestoreConfigRequest. 2931 // 2932 RestoreEleSize = StrSize (ElementStr); 2933 TotalSize = (ConfigHdrEndStr - ConfigRequest) * sizeof (CHAR16) + RestoreEleSize + sizeof (CHAR16); 2934 *RestoreConfigRequest = AllocateZeroPool (TotalSize); 2935 ASSERT (*RestoreConfigRequest != NULL); 2936 StrnCpyS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ConfigRequest, ConfigHdrEndStr - ConfigRequest); 2937 StrCatS (*RestoreConfigRequest, TotalSize / sizeof (CHAR16), ElementStr); 2938 // 2939 // To get the SyncConfigRequest. 2940 // 2941 SyncSize = StrSize (ConfigRequest) - RestoreEleSize + sizeof (CHAR16); 2942 *SyncConfigRequest = AllocateZeroPool (SyncSize); 2943 ASSERT (*SyncConfigRequest != NULL); 2944 StrnCpyS (*SyncConfigRequest, SyncSize / sizeof (CHAR16), ConfigRequest, SyncSize / sizeof (CHAR16) - 1); 2945 2946 // 2947 // restore the Progress string to the original format. 2948 // 2949 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2950 *EndStr = L'='; 2951 } else { 2952 *EndStr = L'&'; 2953 } 2954 } 2955 2956 /** 2957 Popup an save error info and get user input. 2958 2959 @param TitleId The form title id. 2960 @param HiiHandle The hii handle for this package. 2961 2962 @retval UINT32 The user select option for the save fail. 2963 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET 2964 **/ 2965 UINT32 2966 ConfirmSaveFail ( 2967 IN EFI_STRING_ID TitleId, 2968 IN EFI_HII_HANDLE HiiHandle 2969 ) 2970 { 2971 CHAR16 *FormTitle; 2972 CHAR16 *StringBuffer; 2973 UINT32 RetVal; 2974 2975 FormTitle = GetToken (TitleId, HiiHandle); 2976 2977 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); 2978 ASSERT (StringBuffer != NULL); 2979 2980 UnicodeSPrint ( 2981 StringBuffer, 2982 24 * sizeof (CHAR16) + StrSize (FormTitle), 2983 L"Submit Fail For Form: %s.", 2984 FormTitle 2985 ); 2986 2987 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer); 2988 2989 FreePool (StringBuffer); 2990 FreePool (FormTitle); 2991 2992 return RetVal; 2993 } 2994 2995 /** 2996 Popup an NO_SUBMIT_IF error info and get user input. 2997 2998 @param TitleId The form title id. 2999 @param HiiHandle The hii handle for this package. 3000 3001 @retval UINT32 The user select option for the save fail. 3002 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET 3003 **/ 3004 UINT32 3005 ConfirmNoSubmitFail ( 3006 IN EFI_STRING_ID TitleId, 3007 IN EFI_HII_HANDLE HiiHandle 3008 ) 3009 { 3010 CHAR16 *FormTitle; 3011 CHAR16 *StringBuffer; 3012 UINT32 RetVal; 3013 3014 FormTitle = GetToken (TitleId, HiiHandle); 3015 3016 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); 3017 ASSERT (StringBuffer != NULL); 3018 3019 UnicodeSPrint ( 3020 StringBuffer, 3021 24 * sizeof (CHAR16) + StrSize (FormTitle), 3022 L"NO_SUBMIT_IF error For Form: %s.", 3023 FormTitle 3024 ); 3025 3026 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer); 3027 3028 FreePool (StringBuffer); 3029 FreePool (FormTitle); 3030 3031 return RetVal; 3032 } 3033 3034 /** 3035 Discard data based on the input setting scope (Form, FormSet or System). 3036 3037 @param FormSet FormSet data structure. 3038 @param Form Form data structure. 3039 @param SettingScope Setting Scope for Discard action. 3040 3041 @retval EFI_SUCCESS The function completed successfully. 3042 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3043 3044 **/ 3045 EFI_STATUS 3046 DiscardForm ( 3047 IN FORM_BROWSER_FORMSET *FormSet, 3048 IN FORM_BROWSER_FORM *Form, 3049 IN BROWSER_SETTING_SCOPE SettingScope 3050 ) 3051 { 3052 LIST_ENTRY *Link; 3053 FORMSET_STORAGE *Storage; 3054 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 3055 FORM_BROWSER_FORMSET *LocalFormSet; 3056 FORM_BROWSER_FORMSET *OldFormSet; 3057 3058 // 3059 // Check the supported setting level. 3060 // 3061 if (SettingScope >= MaxLevel) { 3062 return EFI_UNSUPPORTED; 3063 } 3064 3065 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) { 3066 ConfigInfo = NULL; 3067 Link = GetFirstNode (&Form->ConfigRequestHead); 3068 while (!IsNull (&Form->ConfigRequestHead, Link)) { 3069 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 3070 Link = GetNextNode (&Form->ConfigRequestHead, Link); 3071 3072 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 3073 continue; 3074 } 3075 3076 // 3077 // Skip if there is no RequestElement 3078 // 3079 if (ConfigInfo->ElementCount == 0) { 3080 continue; 3081 } 3082 3083 // 3084 // Prepare <ConfigResp> 3085 // 3086 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); 3087 3088 // 3089 // Call callback with Changed type to inform the driver. 3090 // 3091 SendDiscardInfoToDriver (FormSet, Form); 3092 } 3093 3094 ValueChangeResetFlagUpdate (FALSE, FormSet, Form); 3095 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) { 3096 3097 // 3098 // Discard Buffer storage or Name/Value storage 3099 // 3100 Link = GetFirstNode (&FormSet->StorageListHead); 3101 while (!IsNull (&FormSet->StorageListHead, Link)) { 3102 Storage = FORMSET_STORAGE_FROM_LINK (Link); 3103 Link = GetNextNode (&FormSet->StorageListHead, Link); 3104 3105 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 3106 continue; 3107 } 3108 3109 // 3110 // Skip if there is no RequestElement 3111 // 3112 if (Storage->ElementCount == 0) { 3113 continue; 3114 } 3115 3116 SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); 3117 } 3118 3119 Link = GetFirstNode (&FormSet->FormListHead); 3120 while (!IsNull (&FormSet->FormListHead, Link)) { 3121 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 3122 Link = GetNextNode (&FormSet->FormListHead, Link); 3123 3124 // 3125 // Call callback with Changed type to inform the driver. 3126 // 3127 SendDiscardInfoToDriver (FormSet, Form); 3128 } 3129 3130 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL); 3131 } else if (SettingScope == SystemLevel) { 3132 // 3133 // System Level Discard. 3134 // 3135 OldFormSet = mSystemLevelFormSet; 3136 3137 // 3138 // Discard changed value for each FormSet in the maintain list. 3139 // 3140 Link = GetFirstNode (&gBrowserFormSetList); 3141 while (!IsNull (&gBrowserFormSetList, Link)) { 3142 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 3143 Link = GetNextNode (&gBrowserFormSetList, Link); 3144 if (!ValidateFormSet(LocalFormSet)) { 3145 continue; 3146 } 3147 3148 mSystemLevelFormSet = LocalFormSet; 3149 3150 DiscardForm (LocalFormSet, NULL, FormSetLevel); 3151 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { 3152 // 3153 // Remove maintain backup list after discard except for the current using FormSet. 3154 // 3155 CleanBrowserStorage(LocalFormSet); 3156 RemoveEntryList (&LocalFormSet->Link); 3157 DestroyFormSet (LocalFormSet); 3158 } 3159 } 3160 3161 mSystemLevelFormSet = OldFormSet; 3162 } 3163 3164 return EFI_SUCCESS; 3165 } 3166 3167 /** 3168 Submit data for a form. 3169 3170 @param FormSet FormSet data structure. 3171 @param Form Form data structure. 3172 3173 @retval EFI_SUCCESS The function completed successfully. 3174 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3175 3176 **/ 3177 EFI_STATUS 3178 SubmitForForm ( 3179 IN FORM_BROWSER_FORMSET *FormSet, 3180 IN FORM_BROWSER_FORM *Form 3181 ) 3182 { 3183 EFI_STATUS Status; 3184 LIST_ENTRY *Link; 3185 EFI_STRING ConfigResp; 3186 EFI_STRING Progress; 3187 BROWSER_STORAGE *Storage; 3188 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 3189 BOOLEAN SubmitFormFail; 3190 3191 SubmitFormFail = FALSE; 3192 3193 if (!IsNvUpdateRequiredForForm (Form)) { 3194 return EFI_SUCCESS; 3195 } 3196 3197 Status = NoSubmitCheck (FormSet, &Form, NULL); 3198 if (EFI_ERROR (Status)) { 3199 return Status; 3200 } 3201 3202 Link = GetFirstNode (&Form->ConfigRequestHead); 3203 while (!IsNull (&Form->ConfigRequestHead, Link)) { 3204 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 3205 Link = GetNextNode (&Form->ConfigRequestHead, Link); 3206 3207 Storage = ConfigInfo->Storage; 3208 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 3209 continue; 3210 } 3211 3212 // 3213 // Skip if there is no RequestElement 3214 // 3215 if (ConfigInfo->ElementCount == 0) { 3216 continue; 3217 } 3218 3219 // 3220 // 1. Prepare <ConfigResp> 3221 // 3222 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE); 3223 if (EFI_ERROR (Status)) { 3224 return Status; 3225 } 3226 3227 // 3228 // 2. Set value to hii config routine protocol. 3229 // 3230 Status = mHiiConfigRouting->RouteConfig ( 3231 mHiiConfigRouting, 3232 ConfigResp, 3233 &Progress 3234 ); 3235 3236 if (EFI_ERROR (Status)) { 3237 // 3238 // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest. 3239 // 3240 SubmitFormFail = TRUE; 3241 GetSyncRestoreConfigRequest (ConfigInfo->Storage, ConfigInfo->ConfigRequest, Progress, &ConfigInfo->RestoreConfigRequest, &ConfigInfo->SyncConfigRequest); 3242 InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink); 3243 FreePool (ConfigResp); 3244 continue; 3245 } 3246 3247 FreePool (ConfigResp); 3248 // 3249 // 3. Config success, update storage shadow Buffer, only update the data belong to this form. 3250 // 3251 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE); 3252 } 3253 3254 // 3255 // 4. Process the save failed storage. 3256 // 3257 if (!IsListEmpty (&gBrowserSaveFailFormSetList)) { 3258 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { 3259 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3260 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { 3261 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); 3262 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); 3263 // 3264 // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer 3265 // base on the SyncConfigRequest to Sync the buffer. 3266 // 3267 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->RestoreConfigRequest, FALSE); 3268 FreePool (ConfigInfo->RestoreConfigRequest); 3269 ConfigInfo->RestoreConfigRequest = NULL; 3270 if (ConfigInfo->SyncConfigRequest != NULL) { 3271 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->SyncConfigRequest, TRUE); 3272 FreePool (ConfigInfo->SyncConfigRequest); 3273 ConfigInfo->SyncConfigRequest = NULL; 3274 } 3275 3276 Status = EFI_SUCCESS; 3277 } 3278 SendDiscardInfoToDriver (FormSet,Form); 3279 } else { 3280 Status = EFI_UNSUPPORTED; 3281 } 3282 3283 // 3284 // Free Form save fail list. 3285 // 3286 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { 3287 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3288 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); 3289 RemoveEntryList (&ConfigInfo->SaveFailLink); 3290 } 3291 } 3292 3293 // 3294 // 5. Update the NV flag. 3295 // 3296 ValueChangeResetFlagUpdate(TRUE, FormSet, Form); 3297 3298 // 3299 // 6 Call callback with Submitted type to inform the driver. 3300 // 3301 if (!SubmitFormFail) { 3302 SubmitCallback (FormSet, Form); 3303 } 3304 3305 return Status; 3306 } 3307 3308 /** 3309 Submit data for a formset. 3310 3311 @param FormSet FormSet data structure. 3312 @param SkipProcessFail Whether skip to process the save failed storage. 3313 If submit formset is called when do system level save, 3314 set this value to true and process the failed formset 3315 together. 3316 if submit formset is called when do formset level save, 3317 set the value to false and process the failed storage 3318 right after process all storages for this formset. 3319 3320 @retval EFI_SUCCESS The function completed successfully. 3321 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3322 3323 **/ 3324 EFI_STATUS 3325 SubmitForFormSet ( 3326 IN FORM_BROWSER_FORMSET *FormSet, 3327 IN BOOLEAN SkipProcessFail 3328 ) 3329 { 3330 EFI_STATUS Status; 3331 LIST_ENTRY *Link; 3332 EFI_STRING ConfigResp; 3333 EFI_STRING Progress; 3334 BROWSER_STORAGE *Storage; 3335 FORMSET_STORAGE *FormSetStorage; 3336 FORM_BROWSER_FORM *Form; 3337 BOOLEAN HasInserted; 3338 FORM_BROWSER_STATEMENT *Question; 3339 BOOLEAN SubmitFormSetFail; 3340 BOOLEAN DiscardChange; 3341 3342 HasInserted = FALSE; 3343 SubmitFormSetFail = FALSE; 3344 DiscardChange = FALSE; 3345 3346 if (!IsNvUpdateRequiredForFormSet (FormSet)) { 3347 return EFI_SUCCESS; 3348 } 3349 3350 Form = NULL; 3351 Status = NoSubmitCheck (FormSet, &Form, &Question); 3352 if (EFI_ERROR (Status)) { 3353 if (SkipProcessFail) { 3354 // 3355 // Process NO_SUBMIT check first, so insert it at head. 3356 // 3357 FormSet->SaveFailForm = Form; 3358 FormSet->SaveFailStatement = Question; 3359 InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); 3360 } 3361 3362 return Status; 3363 } 3364 3365 Form = NULL; 3366 Question = NULL; 3367 // 3368 // Submit Buffer storage or Name/Value storage 3369 // 3370 Link = GetFirstNode (&FormSet->StorageListHead); 3371 while (!IsNull (&FormSet->StorageListHead, Link)) { 3372 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 3373 Storage = FormSetStorage->BrowserStorage; 3374 Link = GetNextNode (&FormSet->StorageListHead, Link); 3375 3376 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 3377 continue; 3378 } 3379 3380 // 3381 // Skip if there is no RequestElement 3382 // 3383 if (FormSetStorage->ElementCount == 0) { 3384 continue; 3385 } 3386 3387 // 3388 // 1. Prepare <ConfigResp> 3389 // 3390 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE); 3391 if (EFI_ERROR (Status)) { 3392 return Status; 3393 } 3394 3395 // 3396 // 2. Send <ConfigResp> to Routine config Protocol. 3397 // 3398 Status = mHiiConfigRouting->RouteConfig ( 3399 mHiiConfigRouting, 3400 ConfigResp, 3401 &Progress 3402 ); 3403 if (EFI_ERROR (Status)) { 3404 // 3405 // Submit fail, to get the RestoreConfigRequest and SyncConfigRequest. 3406 // 3407 SubmitFormSetFail = TRUE; 3408 GetSyncRestoreConfigRequest (FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, Progress, &FormSetStorage->RestoreConfigRequest, &FormSetStorage->SyncConfigRequest); 3409 InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink); 3410 if (!HasInserted) { 3411 // 3412 // Call submit formset for system level, save the formset info 3413 // and process later. 3414 // 3415 FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question); 3416 ASSERT (Form != NULL && Question != NULL); 3417 FormSet->SaveFailForm = Form; 3418 FormSet->SaveFailStatement = Question; 3419 if (SkipProcessFail) { 3420 InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); 3421 } 3422 HasInserted = TRUE; 3423 } 3424 3425 FreePool (ConfigResp); 3426 continue; 3427 } 3428 3429 FreePool (ConfigResp); 3430 // 3431 // 3. Config success, update storage shadow Buffer 3432 // 3433 SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE); 3434 } 3435 3436 // 3437 // 4. Has save fail storage need to handle. 3438 // 3439 if (Form != NULL) { 3440 if (!SkipProcessFail) { 3441 // 3442 // If not in system level, just handl the save failed storage here. 3443 // 3444 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { 3445 DiscardChange = TRUE; 3446 Link = GetFirstNode (&FormSet->SaveFailStorageListHead); 3447 while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) { 3448 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); 3449 Storage = FormSetStorage->BrowserStorage; 3450 Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link); 3451 // 3452 // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer 3453 // base on the SyncConfigRequest to Sync the buffer. 3454 // 3455 SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE); 3456 FreePool (FormSetStorage->RestoreConfigRequest); 3457 FormSetStorage->RestoreConfigRequest = NULL; 3458 if (FormSetStorage->SyncConfigRequest != NULL) { 3459 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE); 3460 FreePool (FormSetStorage->SyncConfigRequest); 3461 FormSetStorage->SyncConfigRequest = NULL; 3462 } 3463 3464 Status = EFI_SUCCESS; 3465 } 3466 } else { 3467 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); 3468 3469 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; 3470 gCurrentSelection->Handle = FormSet->HiiHandle; 3471 CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid); 3472 gCurrentSelection->FormId = Form->FormId; 3473 gCurrentSelection->QuestionId = Question->QuestionId; 3474 3475 Status = EFI_UNSUPPORTED; 3476 } 3477 3478 // 3479 // Free FormSet save fail list. 3480 // 3481 while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) { 3482 Link = GetFirstNode (&FormSet->SaveFailStorageListHead); 3483 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); 3484 RemoveEntryList (&FormSetStorage->SaveFailLink); 3485 } 3486 } else { 3487 // 3488 // If in system level, just return error and handle the failed formset later. 3489 // 3490 Status = EFI_UNSUPPORTED; 3491 } 3492 } 3493 3494 // 3495 // If user discard the change, send the discard info to driver. 3496 // 3497 if (DiscardChange) { 3498 Link = GetFirstNode (&FormSet->FormListHead); 3499 while (!IsNull (&FormSet->FormListHead, Link)) { 3500 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 3501 Link = GetNextNode (&FormSet->FormListHead, Link); 3502 // 3503 // Call callback with Changed type to inform the driver. 3504 // 3505 SendDiscardInfoToDriver (FormSet, Form); 3506 } 3507 } 3508 3509 // 3510 // 5. Update the NV flag. 3511 // 3512 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL); 3513 3514 // 3515 // 6. Call callback with Submitted type to inform the driver. 3516 // 3517 if (!SubmitFormSetFail) { 3518 SubmitCallback (FormSet, NULL); 3519 } 3520 3521 return Status; 3522 } 3523 3524 /** 3525 Submit data for all formsets. 3526 3527 @retval EFI_SUCCESS The function completed successfully. 3528 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3529 3530 **/ 3531 EFI_STATUS 3532 SubmitForSystem ( 3533 VOID 3534 ) 3535 { 3536 EFI_STATUS Status; 3537 LIST_ENTRY *Link; 3538 LIST_ENTRY *FormLink; 3539 LIST_ENTRY *StorageLink; 3540 FORMSET_STORAGE *FormSetStorage; 3541 FORM_BROWSER_FORM *Form; 3542 FORM_BROWSER_FORMSET *LocalFormSet; 3543 UINT32 UserSelection; 3544 FORM_BROWSER_STATEMENT *Question; 3545 3546 mSystemSubmit = TRUE; 3547 Link = GetFirstNode (&gBrowserFormSetList); 3548 while (!IsNull (&gBrowserFormSetList, Link)) { 3549 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 3550 Link = GetNextNode (&gBrowserFormSetList, Link); 3551 if (!ValidateFormSet(LocalFormSet)) { 3552 continue; 3553 } 3554 3555 Status = SubmitForFormSet (LocalFormSet, TRUE); 3556 if (EFI_ERROR (Status)) { 3557 continue; 3558 } 3559 3560 // 3561 // Remove maintain backup list after save except for the current using FormSet. 3562 // 3563 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { 3564 CleanBrowserStorage(LocalFormSet); 3565 RemoveEntryList (&LocalFormSet->Link); 3566 DestroyFormSet (LocalFormSet); 3567 } 3568 } 3569 mSystemSubmit = FALSE; 3570 3571 Status = EFI_SUCCESS; 3572 3573 // 3574 // Process the save failed formsets. 3575 // 3576 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3577 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { 3578 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); 3579 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); 3580 3581 if (!ValidateFormSet(LocalFormSet)) { 3582 continue; 3583 } 3584 3585 Form = LocalFormSet->SaveFailForm; 3586 Question= LocalFormSet->SaveFailStatement; 3587 3588 // 3589 // Confirm with user, get user input. 3590 // 3591 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3592 // 3593 // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check. 3594 // 3595 UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle); 3596 } else { 3597 UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle); 3598 } 3599 3600 if (UserSelection == BROWSER_ACTION_DISCARD) { 3601 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3602 StorageLink = GetFirstNode (&LocalFormSet->StorageListHead); 3603 while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) { 3604 FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink); 3605 StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink); 3606 3607 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); 3608 } 3609 } else { 3610 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); 3611 while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) { 3612 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); 3613 StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink); 3614 // 3615 // Process the submit fail question, base on the RestoreConfigRequest to restore the EditBuffer 3616 // base on the SyncConfigRequest to Sync the buffer. 3617 // 3618 SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->RestoreConfigRequest, FALSE); 3619 FreePool (FormSetStorage->RestoreConfigRequest); 3620 FormSetStorage->RestoreConfigRequest = NULL; 3621 if ( FormSetStorage->SyncConfigRequest != NULL) { 3622 SynchronizeStorage (FormSetStorage->BrowserStorage, FormSetStorage->SyncConfigRequest, TRUE); 3623 FreePool (FormSetStorage->SyncConfigRequest); 3624 FormSetStorage->SyncConfigRequest = NULL; 3625 } 3626 } 3627 } 3628 3629 FormLink = GetFirstNode (&LocalFormSet->FormListHead); 3630 while (!IsNull (&LocalFormSet->FormListHead, FormLink)) { 3631 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); 3632 FormLink = GetNextNode (&LocalFormSet->FormListHead, FormLink); 3633 // 3634 // Call callback with Changed type to inform the driver. 3635 // 3636 SendDiscardInfoToDriver (LocalFormSet, Form); 3637 } 3638 3639 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { 3640 CleanBrowserStorage(LocalFormSet); 3641 RemoveEntryList (&LocalFormSet->Link); 3642 RemoveEntryList (&LocalFormSet->SaveFailLink); 3643 DestroyFormSet (LocalFormSet); 3644 } else { 3645 ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL); 3646 } 3647 } else { 3648 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3649 NoSubmitCheck (LocalFormSet, &Form, &Question); 3650 } 3651 3652 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); 3653 3654 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; 3655 gCurrentSelection->Handle = LocalFormSet->HiiHandle; 3656 CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid); 3657 gCurrentSelection->FormId = Form->FormId; 3658 gCurrentSelection->QuestionId = Question->QuestionId; 3659 3660 Status = EFI_UNSUPPORTED; 3661 break; 3662 } 3663 } 3664 3665 // 3666 // Clean the list which will not process. 3667 // 3668 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { 3669 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3670 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); 3671 RemoveEntryList (&LocalFormSet->SaveFailLink); 3672 3673 while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3674 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); 3675 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); 3676 RemoveEntryList (&FormSetStorage->SaveFailLink); 3677 } 3678 } 3679 3680 return Status; 3681 } 3682 3683 /** 3684 Submit data based on the input Setting level (Form, FormSet or System). 3685 3686 @param FormSet FormSet data structure. 3687 @param Form Form data structure. 3688 @param SettingScope Setting Scope for Submit action. 3689 3690 @retval EFI_SUCCESS The function completed successfully. 3691 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3692 3693 **/ 3694 EFI_STATUS 3695 SubmitForm ( 3696 IN FORM_BROWSER_FORMSET *FormSet, 3697 IN FORM_BROWSER_FORM *Form, 3698 IN BROWSER_SETTING_SCOPE SettingScope 3699 ) 3700 { 3701 EFI_STATUS Status; 3702 3703 switch (SettingScope) { 3704 case FormLevel: 3705 Status = SubmitForForm(FormSet, Form); 3706 break; 3707 3708 case FormSetLevel: 3709 Status = SubmitForFormSet (FormSet, FALSE); 3710 break; 3711 3712 case SystemLevel: 3713 Status = SubmitForSystem (); 3714 break; 3715 3716 default: 3717 Status = EFI_UNSUPPORTED; 3718 break; 3719 } 3720 3721 return Status; 3722 } 3723 3724 /** 3725 Converts the unicode character of the string from uppercase to lowercase. 3726 This is a internal function. 3727 3728 @param ConfigString String to be converted 3729 3730 **/ 3731 VOID 3732 EFIAPI 3733 HiiToLower ( 3734 IN EFI_STRING ConfigString 3735 ) 3736 { 3737 EFI_STRING String; 3738 BOOLEAN Lower; 3739 3740 ASSERT (ConfigString != NULL); 3741 3742 // 3743 // Convert all hex digits in range [A-F] in the configuration header to [a-f] 3744 // 3745 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { 3746 if (*String == L'=') { 3747 Lower = TRUE; 3748 } else if (*String == L'&') { 3749 Lower = FALSE; 3750 } else if (Lower && *String >= L'A' && *String <= L'F') { 3751 *String = (CHAR16) (*String - L'A' + L'a'); 3752 } 3753 } 3754 } 3755 3756 /** 3757 Find the point in the ConfigResp string for this question. 3758 3759 @param Question The question. 3760 @param ConfigResp Get ConfigResp string. 3761 3762 @retval point to the offset where is for this question. 3763 3764 **/ 3765 CHAR16 * 3766 GetOffsetFromConfigResp ( 3767 IN FORM_BROWSER_STATEMENT *Question, 3768 IN CHAR16 *ConfigResp 3769 ) 3770 { 3771 CHAR16 *RequestElement; 3772 CHAR16 *BlockData; 3773 3774 // 3775 // Type is EFI_HII_VARSTORE_NAME_VALUE. 3776 // 3777 if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 3778 RequestElement = StrStr (ConfigResp, Question->VariableName); 3779 if (RequestElement != NULL) { 3780 // 3781 // Skip the "VariableName=" field. 3782 // 3783 RequestElement += StrLen (Question->VariableName) + 1; 3784 } 3785 3786 return RequestElement; 3787 } 3788 3789 // 3790 // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3791 // 3792 3793 // 3794 // Convert all hex digits in ConfigResp to lower case before searching. 3795 // 3796 HiiToLower (ConfigResp); 3797 3798 // 3799 // 1. Directly use Question->BlockName to find. 3800 // 3801 RequestElement = StrStr (ConfigResp, Question->BlockName); 3802 if (RequestElement != NULL) { 3803 // 3804 // Skip the "Question->BlockName&VALUE=" field. 3805 // 3806 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); 3807 return RequestElement; 3808 } 3809 3810 // 3811 // 2. Change all hex digits in Question->BlockName to lower and compare again. 3812 // 3813 BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName); 3814 ASSERT (BlockData != NULL); 3815 HiiToLower (BlockData); 3816 RequestElement = StrStr (ConfigResp, BlockData); 3817 FreePool (BlockData); 3818 3819 if (RequestElement != NULL) { 3820 // 3821 // Skip the "Question->BlockName&VALUE=" field. 3822 // 3823 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); 3824 } 3825 3826 return RequestElement; 3827 } 3828 3829 /** 3830 Get Question default value from AltCfg string. 3831 3832 @param FormSet The form set. 3833 @param Form The form 3834 @param Question The question. 3835 3836 @retval EFI_SUCCESS Question is reset to default value. 3837 3838 **/ 3839 EFI_STATUS 3840 GetDefaultValueFromAltCfg ( 3841 IN FORM_BROWSER_FORMSET *FormSet, 3842 IN FORM_BROWSER_FORM *Form, 3843 IN OUT FORM_BROWSER_STATEMENT *Question 3844 ) 3845 { 3846 BROWSER_STORAGE *Storage; 3847 FORMSET_STORAGE *FormSetStorage; 3848 CHAR16 *ConfigResp; 3849 CHAR16 *Value; 3850 LIST_ENTRY *Link; 3851 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 3852 3853 Storage = Question->Storage; 3854 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { 3855 return EFI_NOT_FOUND; 3856 } 3857 3858 // 3859 // Try to get AltCfg string from form. If not found it, then 3860 // try to get it from formset. 3861 // 3862 ConfigResp = NULL; 3863 Link = GetFirstNode (&Form->ConfigRequestHead); 3864 while (!IsNull (&Form->ConfigRequestHead, Link)) { 3865 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 3866 Link = GetNextNode (&Form->ConfigRequestHead, Link); 3867 3868 if (Storage == ConfigInfo->Storage) { 3869 ConfigResp = ConfigInfo->ConfigAltResp; 3870 break; 3871 } 3872 } 3873 3874 if (ConfigResp == NULL) { 3875 Link = GetFirstNode (&FormSet->StorageListHead); 3876 while (!IsNull (&FormSet->StorageListHead, Link)) { 3877 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 3878 Link = GetNextNode (&FormSet->StorageListHead, Link); 3879 3880 if (Storage == FormSetStorage->BrowserStorage) { 3881 ConfigResp = FormSetStorage->ConfigAltResp; 3882 break; 3883 } 3884 } 3885 } 3886 3887 if (ConfigResp == NULL) { 3888 return EFI_NOT_FOUND; 3889 } 3890 3891 Value = GetOffsetFromConfigResp (Question, ConfigResp); 3892 if (Value == NULL) { 3893 return EFI_NOT_FOUND; 3894 } 3895 3896 return BufferToValue (Question, Value); 3897 } 3898 3899 /** 3900 Get default Id value used for browser. 3901 3902 @param DefaultId The default id value used by hii. 3903 3904 @retval Browser used default value. 3905 3906 **/ 3907 INTN 3908 GetDefaultIdForCallBack ( 3909 UINTN DefaultId 3910 ) 3911 { 3912 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) { 3913 return EFI_BROWSER_ACTION_DEFAULT_STANDARD; 3914 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 3915 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING; 3916 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) { 3917 return EFI_BROWSER_ACTION_DEFAULT_SAFE; 3918 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) { 3919 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN; 3920 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) { 3921 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN; 3922 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) { 3923 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN; 3924 } else { 3925 return -1; 3926 } 3927 } 3928 3929 3930 3931 /** 3932 Return data element in an Array by its Index. 3933 3934 @param Array The data array. 3935 @param Type Type of the data in this array. 3936 @param Index Zero based index for data in this array. 3937 3938 @retval Value The data to be returned 3939 3940 **/ 3941 UINT64 3942 GetArrayData ( 3943 IN VOID *Array, 3944 IN UINT8 Type, 3945 IN UINTN Index 3946 ) 3947 { 3948 UINT64 Data; 3949 3950 ASSERT (Array != NULL); 3951 3952 Data = 0; 3953 switch (Type) { 3954 case EFI_IFR_TYPE_NUM_SIZE_8: 3955 Data = (UINT64) *(((UINT8 *) Array) + Index); 3956 break; 3957 3958 case EFI_IFR_TYPE_NUM_SIZE_16: 3959 Data = (UINT64) *(((UINT16 *) Array) + Index); 3960 break; 3961 3962 case EFI_IFR_TYPE_NUM_SIZE_32: 3963 Data = (UINT64) *(((UINT32 *) Array) + Index); 3964 break; 3965 3966 case EFI_IFR_TYPE_NUM_SIZE_64: 3967 Data = (UINT64) *(((UINT64 *) Array) + Index); 3968 break; 3969 3970 default: 3971 break; 3972 } 3973 3974 return Data; 3975 } 3976 3977 3978 /** 3979 Set value of a data element in an Array by its Index. 3980 3981 @param Array The data array. 3982 @param Type Type of the data in this array. 3983 @param Index Zero based index for data in this array. 3984 @param Value The value to be set. 3985 3986 **/ 3987 VOID 3988 SetArrayData ( 3989 IN VOID *Array, 3990 IN UINT8 Type, 3991 IN UINTN Index, 3992 IN UINT64 Value 3993 ) 3994 { 3995 3996 ASSERT (Array != NULL); 3997 3998 switch (Type) { 3999 case EFI_IFR_TYPE_NUM_SIZE_8: 4000 *(((UINT8 *) Array) + Index) = (UINT8) Value; 4001 break; 4002 4003 case EFI_IFR_TYPE_NUM_SIZE_16: 4004 *(((UINT16 *) Array) + Index) = (UINT16) Value; 4005 break; 4006 4007 case EFI_IFR_TYPE_NUM_SIZE_32: 4008 *(((UINT32 *) Array) + Index) = (UINT32) Value; 4009 break; 4010 4011 case EFI_IFR_TYPE_NUM_SIZE_64: 4012 *(((UINT64 *) Array) + Index) = (UINT64) Value; 4013 break; 4014 4015 default: 4016 break; 4017 } 4018 } 4019 4020 /** 4021 Search an Option of a Question by its value. 4022 4023 @param Question The Question 4024 @param OptionValue Value for Option to be searched. 4025 4026 @retval Pointer Pointer to the found Option. 4027 @retval NULL Option not found. 4028 4029 **/ 4030 QUESTION_OPTION * 4031 ValueToOption ( 4032 IN FORM_BROWSER_STATEMENT *Question, 4033 IN EFI_HII_VALUE *OptionValue 4034 ) 4035 { 4036 LIST_ENTRY *Link; 4037 QUESTION_OPTION *Option; 4038 INTN Result; 4039 4040 Link = GetFirstNode (&Question->OptionListHead); 4041 while (!IsNull (&Question->OptionListHead, Link)) { 4042 Option = QUESTION_OPTION_FROM_LINK (Link); 4043 4044 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { 4045 // 4046 // Check the suppressif condition, only a valid option can be return. 4047 // 4048 if ((Option->SuppressExpression == NULL) || 4049 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) { 4050 return Option; 4051 } 4052 } 4053 4054 Link = GetNextNode (&Question->OptionListHead, Link); 4055 } 4056 4057 return NULL; 4058 } 4059 4060 4061 /** 4062 Reset Question to its default value. 4063 4064 @param FormSet The form set. 4065 @param Form The form. 4066 @param Question The question. 4067 @param DefaultId The Class of the default. 4068 4069 @retval EFI_SUCCESS Question is reset to default value. 4070 4071 **/ 4072 EFI_STATUS 4073 GetQuestionDefault ( 4074 IN FORM_BROWSER_FORMSET *FormSet, 4075 IN FORM_BROWSER_FORM *Form, 4076 IN FORM_BROWSER_STATEMENT *Question, 4077 IN UINT16 DefaultId 4078 ) 4079 { 4080 EFI_STATUS Status; 4081 LIST_ENTRY *Link; 4082 QUESTION_DEFAULT *Default; 4083 QUESTION_OPTION *Option; 4084 EFI_HII_VALUE *HiiValue; 4085 UINT8 Index; 4086 EFI_STRING StrValue; 4087 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 4088 EFI_BROWSER_ACTION_REQUEST ActionRequest; 4089 INTN Action; 4090 CHAR16 *NewString; 4091 EFI_IFR_TYPE_VALUE *TypeValue; 4092 UINT16 OriginalDefaultId; 4093 FORMSET_DEFAULTSTORE *DefaultStore; 4094 LIST_ENTRY *DefaultLink; 4095 4096 Status = EFI_NOT_FOUND; 4097 StrValue = NULL; 4098 OriginalDefaultId = DefaultId; 4099 DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead); 4100 4101 // 4102 // Statement don't have storage, skip them 4103 // 4104 if (Question->QuestionId == 0) { 4105 return Status; 4106 } 4107 4108 // 4109 // There are Five ways to specify default value for a Question: 4110 // 1, use call back function (highest priority) 4111 // 2, use ExtractConfig function 4112 // 3, use nested EFI_IFR_DEFAULT 4113 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) 4114 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) 4115 // 4116 ReGetDefault: 4117 HiiValue = &Question->HiiValue; 4118 TypeValue = &HiiValue->Value; 4119 if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) { 4120 // 4121 // For orderedlist, need to pass the BufferValue to Callback function. 4122 // 4123 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue; 4124 } 4125 4126 // 4127 // Get Question defaut value from call back function. 4128 // 4129 ConfigAccess = FormSet->ConfigAccess; 4130 Action = GetDefaultIdForCallBack (DefaultId); 4131 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) { 4132 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 4133 Status = ConfigAccess->Callback ( 4134 ConfigAccess, 4135 Action, 4136 Question->QuestionId, 4137 HiiValue->Type, 4138 TypeValue, 4139 &ActionRequest 4140 ); 4141 if (!EFI_ERROR (Status)) { 4142 if (HiiValue->Type == EFI_IFR_TYPE_STRING) { 4143 NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle); 4144 ASSERT (NewString != NULL); 4145 4146 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth); 4147 if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) { 4148 ZeroMem (Question->BufferValue, Question->StorageWidth); 4149 CopyMem (Question->BufferValue, NewString, StrSize (NewString)); 4150 } else { 4151 CopyMem (Question->BufferValue, NewString, Question->StorageWidth); 4152 } 4153 4154 FreePool (NewString); 4155 } 4156 return Status; 4157 } 4158 } 4159 4160 // 4161 // Get default value from altcfg string. 4162 // 4163 if (ConfigAccess != NULL) { 4164 Status = GetDefaultValueFromAltCfg(FormSet, Form, Question); 4165 if (!EFI_ERROR (Status)) { 4166 return Status; 4167 } 4168 } 4169 4170 // 4171 // EFI_IFR_DEFAULT has highest priority 4172 // 4173 if (!IsListEmpty (&Question->DefaultListHead)) { 4174 Link = GetFirstNode (&Question->DefaultListHead); 4175 while (!IsNull (&Question->DefaultListHead, Link)) { 4176 Default = QUESTION_DEFAULT_FROM_LINK (Link); 4177 4178 if (Default->DefaultId == DefaultId) { 4179 if (Default->ValueExpression != NULL) { 4180 // 4181 // Default is provided by an Expression, evaluate it 4182 // 4183 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); 4184 if (EFI_ERROR (Status)) { 4185 return Status; 4186 } 4187 4188 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { 4189 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL); 4190 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) { 4191 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen); 4192 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen; 4193 } else { 4194 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth); 4195 Question->HiiValue.BufferLen = Question->StorageWidth; 4196 } 4197 FreePool (Default->ValueExpression->Result.Buffer); 4198 } 4199 HiiValue->Type = Default->ValueExpression->Result.Type; 4200 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); 4201 } else { 4202 // 4203 // Default value is embedded in EFI_IFR_DEFAULT 4204 // 4205 if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) { 4206 ASSERT (HiiValue->Buffer != NULL); 4207 CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen); 4208 } else { 4209 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); 4210 } 4211 } 4212 4213 if (HiiValue->Type == EFI_IFR_TYPE_STRING) { 4214 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL); 4215 if (StrValue == NULL) { 4216 return EFI_NOT_FOUND; 4217 } 4218 if (Question->StorageWidth > StrSize (StrValue)) { 4219 ZeroMem (Question->BufferValue, Question->StorageWidth); 4220 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue)); 4221 } else { 4222 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth); 4223 } 4224 } 4225 4226 return EFI_SUCCESS; 4227 } 4228 4229 Link = GetNextNode (&Question->DefaultListHead, Link); 4230 } 4231 } 4232 4233 // 4234 // EFI_ONE_OF_OPTION 4235 // 4236 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { 4237 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 4238 // 4239 // OneOfOption could only provide Standard and Manufacturing default 4240 // 4241 Link = GetFirstNode (&Question->OptionListHead); 4242 while (!IsNull (&Question->OptionListHead, Link)) { 4243 Option = QUESTION_OPTION_FROM_LINK (Link); 4244 Link = GetNextNode (&Question->OptionListHead, Link); 4245 4246 if ((Option->SuppressExpression != NULL) && 4247 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { 4248 continue; 4249 } 4250 4251 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) || 4252 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0)) 4253 ) { 4254 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); 4255 4256 return EFI_SUCCESS; 4257 } 4258 } 4259 } 4260 } 4261 4262 // 4263 // EFI_IFR_CHECKBOX - lowest priority 4264 // 4265 if (Question->Operand == EFI_IFR_CHECKBOX_OP) { 4266 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 4267 // 4268 // Checkbox could only provide Standard and Manufacturing default 4269 // 4270 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) || 4271 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0)) 4272 ) { 4273 HiiValue->Value.b = TRUE; 4274 } 4275 4276 return EFI_SUCCESS; 4277 } 4278 } 4279 4280 // 4281 // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList. 4282 // If get, will exit the function, if not, will choose next default id in the DefaultStoreList. 4283 // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time. 4284 // 4285 while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) { 4286 DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink); 4287 DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink); 4288 DefaultId = DefaultStore->DefaultId; 4289 if (DefaultId == OriginalDefaultId) { 4290 continue; 4291 } 4292 goto ReGetDefault; 4293 } 4294 4295 // 4296 // For Questions without default value for all the default id in the DefaultStoreList. 4297 // 4298 Status = EFI_NOT_FOUND; 4299 switch (Question->Operand) { 4300 case EFI_IFR_CHECKBOX_OP: 4301 HiiValue->Value.b = FALSE; 4302 Status = EFI_SUCCESS; 4303 break; 4304 4305 case EFI_IFR_NUMERIC_OP: 4306 // 4307 // Take minimum value as numeric default value 4308 // 4309 if ((Question->Flags & EFI_IFR_DISPLAY) == 0) { 4310 // 4311 // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type. 4312 // 4313 switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) { 4314 case EFI_IFR_NUMERIC_SIZE_1: 4315 if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) { 4316 HiiValue->Value.u8 = (UINT8) Question->Minimum; 4317 Status = EFI_SUCCESS; 4318 } 4319 break; 4320 case EFI_IFR_NUMERIC_SIZE_2: 4321 if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) { 4322 HiiValue->Value.u16 = (UINT16) Question->Minimum; 4323 Status = EFI_SUCCESS; 4324 } 4325 break; 4326 case EFI_IFR_NUMERIC_SIZE_4: 4327 if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) { 4328 HiiValue->Value.u32 = (UINT32) Question->Minimum; 4329 Status = EFI_SUCCESS; 4330 } 4331 break; 4332 case EFI_IFR_NUMERIC_SIZE_8: 4333 if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) { 4334 HiiValue->Value.u64 = Question->Minimum; 4335 Status = EFI_SUCCESS; 4336 } 4337 break; 4338 default: 4339 break; 4340 } 4341 } else { 4342 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) { 4343 HiiValue->Value.u64 = Question->Minimum; 4344 Status = EFI_SUCCESS; 4345 } 4346 } 4347 break; 4348 4349 case EFI_IFR_ONE_OF_OP: 4350 // 4351 // Take first oneof option as oneof's default value 4352 // 4353 if (ValueToOption (Question, HiiValue) == NULL) { 4354 Link = GetFirstNode (&Question->OptionListHead); 4355 while (!IsNull (&Question->OptionListHead, Link)) { 4356 Option = QUESTION_OPTION_FROM_LINK (Link); 4357 Link = GetNextNode (&Question->OptionListHead, Link); 4358 4359 if ((Option->SuppressExpression != NULL) && 4360 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { 4361 continue; 4362 } 4363 4364 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); 4365 Status = EFI_SUCCESS; 4366 break; 4367 } 4368 } 4369 break; 4370 4371 case EFI_IFR_ORDERED_LIST_OP: 4372 // 4373 // Take option sequence in IFR as ordered list's default value 4374 // 4375 Index = 0; 4376 Link = GetFirstNode (&Question->OptionListHead); 4377 while (!IsNull (&Question->OptionListHead, Link)) { 4378 Status = EFI_SUCCESS; 4379 Option = QUESTION_OPTION_FROM_LINK (Link); 4380 Link = GetNextNode (&Question->OptionListHead, Link); 4381 4382 if ((Option->SuppressExpression != NULL) && 4383 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { 4384 continue; 4385 } 4386 4387 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64); 4388 4389 Index++; 4390 if (Index >= Question->MaxContainers) { 4391 break; 4392 } 4393 } 4394 break; 4395 4396 default: 4397 break; 4398 } 4399 4400 return Status; 4401 } 4402 4403 /** 4404 Get AltCfg string for current form. 4405 4406 @param FormSet Form data structure. 4407 @param Form Form data structure. 4408 @param DefaultId The Class of the default. 4409 @param BrowserStorage The input request storage for the questions. 4410 4411 **/ 4412 VOID 4413 ExtractAltCfgForForm ( 4414 IN FORM_BROWSER_FORMSET *FormSet, 4415 IN FORM_BROWSER_FORM *Form, 4416 IN UINT16 DefaultId, 4417 IN BROWSER_STORAGE *BrowserStorage 4418 ) 4419 { 4420 EFI_STATUS Status; 4421 LIST_ENTRY *Link; 4422 CHAR16 *ConfigResp; 4423 CHAR16 *Progress; 4424 CHAR16 *Result; 4425 BROWSER_STORAGE *Storage; 4426 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 4427 FORMSET_STORAGE *FormSetStorage; 4428 4429 // 4430 // Check whether has get AltCfg string for this formset. 4431 // If yes, no need to get AltCfg for form. 4432 // 4433 Link = GetFirstNode (&FormSet->StorageListHead); 4434 while (!IsNull (&FormSet->StorageListHead, Link)) { 4435 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 4436 Storage = FormSetStorage->BrowserStorage; 4437 Link = GetNextNode (&FormSet->StorageListHead, Link); 4438 if (BrowserStorage != NULL && BrowserStorage != Storage) { 4439 continue; 4440 } 4441 4442 if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE && 4443 FormSetStorage->ElementCount != 0 && 4444 FormSetStorage->HasCallAltCfg) { 4445 return; 4446 } 4447 } 4448 4449 // 4450 // Get AltCfg string for each form. 4451 // 4452 Link = GetFirstNode (&Form->ConfigRequestHead); 4453 while (!IsNull (&Form->ConfigRequestHead, Link)) { 4454 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 4455 Link = GetNextNode (&Form->ConfigRequestHead, Link); 4456 4457 Storage = ConfigInfo->Storage; 4458 if (BrowserStorage != NULL && BrowserStorage != Storage) { 4459 continue; 4460 } 4461 4462 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 4463 continue; 4464 } 4465 4466 // 4467 // 1. Skip if there is no RequestElement 4468 // 4469 if (ConfigInfo->ElementCount == 0) { 4470 continue; 4471 } 4472 4473 // 4474 // 2. Get value through hii config routine protocol. 4475 // 4476 Status = mHiiConfigRouting->ExtractConfig ( 4477 mHiiConfigRouting, 4478 ConfigInfo->ConfigRequest, 4479 &Progress, 4480 &Result 4481 ); 4482 if (EFI_ERROR (Status)) { 4483 continue; 4484 } 4485 4486 // 4487 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp) 4488 // Get the default configuration string according to the default ID. 4489 // 4490 Status = mHiiConfigRouting->GetAltConfig ( 4491 mHiiConfigRouting, 4492 Result, 4493 &Storage->Guid, 4494 Storage->Name, 4495 NULL, 4496 &DefaultId, // it can be NULL to get the current setting. 4497 &ConfigResp 4498 ); 4499 FreePool (Result); 4500 if (EFI_ERROR (Status)) { 4501 continue; 4502 } 4503 4504 ConfigInfo->ConfigAltResp = ConfigResp; 4505 } 4506 } 4507 4508 /** 4509 Clean AltCfg string for current form. 4510 4511 @param Form Form data structure. 4512 4513 **/ 4514 VOID 4515 CleanAltCfgForForm ( 4516 IN FORM_BROWSER_FORM *Form 4517 ) 4518 { 4519 LIST_ENTRY *Link; 4520 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 4521 4522 Link = GetFirstNode (&Form->ConfigRequestHead); 4523 while (!IsNull (&Form->ConfigRequestHead, Link)) { 4524 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 4525 Link = GetNextNode (&Form->ConfigRequestHead, Link); 4526 4527 if (ConfigInfo->ConfigAltResp != NULL) { 4528 FreePool (ConfigInfo->ConfigAltResp); 4529 ConfigInfo->ConfigAltResp = NULL; 4530 } 4531 } 4532 } 4533 4534 /** 4535 Get AltCfg string for current formset. 4536 4537 @param FormSet Form data structure. 4538 @param DefaultId The Class of the default. 4539 @param BrowserStorage The input request storage for the questions. 4540 4541 **/ 4542 VOID 4543 ExtractAltCfgForFormSet ( 4544 IN FORM_BROWSER_FORMSET *FormSet, 4545 IN UINT16 DefaultId, 4546 IN BROWSER_STORAGE *BrowserStorage 4547 ) 4548 { 4549 EFI_STATUS Status; 4550 LIST_ENTRY *Link; 4551 CHAR16 *ConfigResp; 4552 CHAR16 *Progress; 4553 CHAR16 *Result; 4554 BROWSER_STORAGE *Storage; 4555 FORMSET_STORAGE *FormSetStorage; 4556 4557 Link = GetFirstNode (&FormSet->StorageListHead); 4558 while (!IsNull (&FormSet->StorageListHead, Link)) { 4559 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 4560 Storage = FormSetStorage->BrowserStorage; 4561 Link = GetNextNode (&FormSet->StorageListHead, Link); 4562 4563 if (BrowserStorage != NULL && BrowserStorage != Storage) { 4564 continue; 4565 } 4566 4567 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 4568 continue; 4569 } 4570 4571 // 4572 // 1. Skip if there is no RequestElement 4573 // 4574 if (FormSetStorage->ElementCount == 0) { 4575 continue; 4576 } 4577 4578 FormSetStorage->HasCallAltCfg = TRUE; 4579 4580 // 4581 // 2. Get value through hii config routine protocol. 4582 // 4583 Status = mHiiConfigRouting->ExtractConfig ( 4584 mHiiConfigRouting, 4585 FormSetStorage->ConfigRequest, 4586 &Progress, 4587 &Result 4588 ); 4589 if (EFI_ERROR (Status)) { 4590 continue; 4591 } 4592 4593 // 4594 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp) 4595 // Get the default configuration string according to the default ID. 4596 // 4597 Status = mHiiConfigRouting->GetAltConfig ( 4598 mHiiConfigRouting, 4599 Result, 4600 &Storage->Guid, 4601 Storage->Name, 4602 NULL, 4603 &DefaultId, // it can be NULL to get the current setting. 4604 &ConfigResp 4605 ); 4606 4607 FreePool (Result); 4608 if (EFI_ERROR (Status)) { 4609 continue; 4610 } 4611 4612 FormSetStorage->ConfigAltResp = ConfigResp; 4613 } 4614 4615 } 4616 4617 /** 4618 Clean AltCfg string for current formset. 4619 4620 @param FormSet Form data structure. 4621 4622 **/ 4623 VOID 4624 CleanAltCfgForFormSet ( 4625 IN FORM_BROWSER_FORMSET *FormSet 4626 ) 4627 { 4628 LIST_ENTRY *Link; 4629 FORMSET_STORAGE *FormSetStorage; 4630 4631 Link = GetFirstNode (&FormSet->StorageListHead); 4632 while (!IsNull (&FormSet->StorageListHead, Link)) { 4633 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 4634 Link = GetNextNode (&FormSet->StorageListHead, Link); 4635 4636 if (FormSetStorage->ConfigAltResp != NULL) { 4637 FreePool (FormSetStorage->ConfigAltResp); 4638 FormSetStorage->ConfigAltResp = NULL; 4639 } 4640 4641 FormSetStorage->HasCallAltCfg = FALSE; 4642 } 4643 } 4644 4645 /** 4646 Reset Questions to their initial value or default value in a Form, Formset or System. 4647 4648 GetDefaultValueScope parameter decides which questions will reset 4649 to its default value. 4650 4651 @param FormSet FormSet data structure. 4652 @param Form Form data structure. 4653 @param DefaultId The Class of the default. 4654 @param SettingScope Setting Scope for Default action. 4655 @param GetDefaultValueScope Get default value scope. 4656 @param Storage Get default value only for this storage. 4657 @param RetrieveValueFirst Whether call the retrieve call back to 4658 get the initial value before get default 4659 value. 4660 @param SkipGetAltCfg Whether skip the get altcfg string process. 4661 4662 @retval EFI_SUCCESS The function completed successfully. 4663 @retval EFI_UNSUPPORTED Unsupport SettingScope. 4664 4665 **/ 4666 EFI_STATUS 4667 ExtractDefault ( 4668 IN FORM_BROWSER_FORMSET *FormSet, 4669 IN FORM_BROWSER_FORM *Form, 4670 IN UINT16 DefaultId, 4671 IN BROWSER_SETTING_SCOPE SettingScope, 4672 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope, 4673 IN BROWSER_STORAGE *Storage OPTIONAL, 4674 IN BOOLEAN RetrieveValueFirst, 4675 IN BOOLEAN SkipGetAltCfg 4676 ) 4677 { 4678 EFI_STATUS Status; 4679 LIST_ENTRY *FormLink; 4680 LIST_ENTRY *Link; 4681 FORM_BROWSER_STATEMENT *Question; 4682 FORM_BROWSER_FORMSET *LocalFormSet; 4683 FORM_BROWSER_FORMSET *OldFormSet; 4684 4685 Status = EFI_SUCCESS; 4686 4687 // 4688 // Check the supported setting level. 4689 // 4690 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) { 4691 return EFI_UNSUPPORTED; 4692 } 4693 4694 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) { 4695 return EFI_UNSUPPORTED; 4696 } 4697 4698 if (SettingScope == FormLevel) { 4699 // 4700 // Prepare the AltCfg String for form. 4701 // 4702 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4703 ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage); 4704 } 4705 4706 // 4707 // Extract Form default 4708 // 4709 Link = GetFirstNode (&Form->StatementListHead); 4710 while (!IsNull (&Form->StatementListHead, Link)) { 4711 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 4712 Link = GetNextNode (&Form->StatementListHead, Link); 4713 4714 // 4715 // If get default value only for this storage, check the storage first. 4716 // 4717 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) { 4718 continue; 4719 } 4720 4721 // 4722 // If get default value only for no storage question, just skip the question which has storage. 4723 // 4724 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) { 4725 continue; 4726 } 4727 4728 // 4729 // If Question is disabled, don't reset it to default 4730 // 4731 if (Question->Expression != NULL) { 4732 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) { 4733 continue; 4734 } 4735 } 4736 4737 if (RetrieveValueFirst) { 4738 // 4739 // Call the Retrieve call back to get the initial question value. 4740 // 4741 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet); 4742 } 4743 4744 // 4745 // If not request to get the initial value or get initial value fail, then get default value. 4746 // 4747 if (!RetrieveValueFirst || EFI_ERROR (Status)) { 4748 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); 4749 if (EFI_ERROR (Status)) { 4750 continue; 4751 } 4752 } 4753 4754 // 4755 // Synchronize Buffer storage's Edit buffer 4756 // 4757 if ((Question->Storage != NULL) && 4758 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { 4759 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 4760 } 4761 } 4762 4763 // 4764 // Clean the AltCfg String. 4765 // 4766 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4767 CleanAltCfgForForm(Form); 4768 } 4769 } else if (SettingScope == FormSetLevel) { 4770 // 4771 // Prepare the AltCfg String for formset. 4772 // 4773 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4774 ExtractAltCfgForFormSet (FormSet, DefaultId, Storage); 4775 } 4776 4777 FormLink = GetFirstNode (&FormSet->FormListHead); 4778 while (!IsNull (&FormSet->FormListHead, FormLink)) { 4779 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); 4780 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); 4781 FormLink = GetNextNode (&FormSet->FormListHead, FormLink); 4782 } 4783 4784 // 4785 // Clean the AltCfg String. 4786 // 4787 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4788 CleanAltCfgForFormSet (FormSet); 4789 } 4790 } else if (SettingScope == SystemLevel) { 4791 // 4792 // Preload all Hii formset. 4793 // 4794 LoadAllHiiFormset(); 4795 4796 OldFormSet = mSystemLevelFormSet; 4797 4798 // 4799 // Set Default Value for each FormSet in the maintain list. 4800 // 4801 Link = GetFirstNode (&gBrowserFormSetList); 4802 while (!IsNull (&gBrowserFormSetList, Link)) { 4803 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 4804 Link = GetNextNode (&gBrowserFormSetList, Link); 4805 if (!ValidateFormSet(LocalFormSet)) { 4806 continue; 4807 } 4808 4809 mSystemLevelFormSet = LocalFormSet; 4810 4811 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); 4812 } 4813 4814 mSystemLevelFormSet = OldFormSet; 4815 } 4816 4817 return EFI_SUCCESS; 4818 } 4819 4820 4821 /** 4822 Validate whether this question's value has changed. 4823 4824 @param FormSet FormSet data structure. 4825 @param Form Form data structure. 4826 @param Question Question to be initialized. 4827 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. 4828 4829 @retval TRUE Question's value has changed. 4830 @retval FALSE Question's value has not changed 4831 4832 **/ 4833 BOOLEAN 4834 IsQuestionValueChanged ( 4835 IN FORM_BROWSER_FORMSET *FormSet, 4836 IN FORM_BROWSER_FORM *Form, 4837 IN OUT FORM_BROWSER_STATEMENT *Question, 4838 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom 4839 ) 4840 { 4841 EFI_HII_VALUE BackUpValue; 4842 CHAR8 *BackUpBuffer; 4843 EFI_HII_VALUE BackUpValue2; 4844 CHAR8 *BackUpBuffer2; 4845 EFI_STATUS Status; 4846 BOOLEAN ValueChanged; 4847 UINTN BufferWidth; 4848 4849 // 4850 // For quetion without storage, always mark it as data not changed. 4851 // 4852 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) { 4853 return FALSE; 4854 } 4855 4856 BackUpBuffer = NULL; 4857 BackUpBuffer2 = NULL; 4858 ValueChanged = FALSE; 4859 4860 switch (Question->Operand) { 4861 case EFI_IFR_ORDERED_LIST_OP: 4862 BufferWidth = Question->StorageWidth; 4863 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); 4864 ASSERT (BackUpBuffer != NULL); 4865 break; 4866 4867 case EFI_IFR_STRING_OP: 4868 case EFI_IFR_PASSWORD_OP: 4869 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); 4870 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); 4871 ASSERT (BackUpBuffer != NULL); 4872 break; 4873 4874 default: 4875 BufferWidth = 0; 4876 break; 4877 } 4878 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); 4879 4880 if (GetValueFrom == GetSetValueWithBothBuffer) { 4881 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 4882 ASSERT_EFI_ERROR(Status); 4883 4884 switch (Question->Operand) { 4885 case EFI_IFR_ORDERED_LIST_OP: 4886 BufferWidth = Question->StorageWidth; 4887 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); 4888 ASSERT (BackUpBuffer2 != NULL); 4889 break; 4890 4891 case EFI_IFR_STRING_OP: 4892 case EFI_IFR_PASSWORD_OP: 4893 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); 4894 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); 4895 ASSERT (BackUpBuffer2 != NULL); 4896 break; 4897 4898 default: 4899 BufferWidth = 0; 4900 break; 4901 } 4902 CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)); 4903 4904 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer); 4905 ASSERT_EFI_ERROR(Status); 4906 4907 if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || 4908 CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) { 4909 ValueChanged = TRUE; 4910 } 4911 } else { 4912 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom); 4913 ASSERT_EFI_ERROR(Status); 4914 4915 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || 4916 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) { 4917 ValueChanged = TRUE; 4918 } 4919 } 4920 4921 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE)); 4922 if (BackUpBuffer != NULL) { 4923 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth); 4924 FreePool (BackUpBuffer); 4925 } 4926 4927 if (BackUpBuffer2 != NULL) { 4928 FreePool (BackUpBuffer2); 4929 } 4930 4931 Question->ValueChanged = ValueChanged; 4932 4933 return ValueChanged; 4934 } 4935 4936 /** 4937 Initialize Question's Edit copy from Storage. 4938 4939 @param Selection Selection contains the information about 4940 the Selection, form and formset to be displayed. 4941 Selection action may be updated in retrieve callback. 4942 If Selection is NULL, only initialize Question value. 4943 @param FormSet FormSet data structure. 4944 @param Form Form data structure. 4945 4946 @retval EFI_SUCCESS The function completed successfully. 4947 4948 **/ 4949 EFI_STATUS 4950 LoadFormConfig ( 4951 IN OUT UI_MENU_SELECTION *Selection, 4952 IN FORM_BROWSER_FORMSET *FormSet, 4953 IN FORM_BROWSER_FORM *Form 4954 ) 4955 { 4956 EFI_STATUS Status; 4957 LIST_ENTRY *Link; 4958 FORM_BROWSER_STATEMENT *Question; 4959 4960 Link = GetFirstNode (&Form->StatementListHead); 4961 while (!IsNull (&Form->StatementListHead, Link)) { 4962 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 4963 4964 // 4965 // Initialize local copy of Value for each Question 4966 // 4967 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) { 4968 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); 4969 } else { 4970 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 4971 } 4972 if (EFI_ERROR (Status)) { 4973 return Status; 4974 } 4975 4976 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) { 4977 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); 4978 } 4979 4980 Link = GetNextNode (&Form->StatementListHead, Link); 4981 } 4982 4983 return EFI_SUCCESS; 4984 } 4985 4986 /** 4987 Initialize Question's Edit copy from Storage for the whole Formset. 4988 4989 @param Selection Selection contains the information about 4990 the Selection, form and formset to be displayed. 4991 Selection action may be updated in retrieve callback. 4992 If Selection is NULL, only initialize Question value. 4993 @param FormSet FormSet data structure. 4994 4995 @retval EFI_SUCCESS The function completed successfully. 4996 4997 **/ 4998 EFI_STATUS 4999 LoadFormSetConfig ( 5000 IN OUT UI_MENU_SELECTION *Selection, 5001 IN FORM_BROWSER_FORMSET *FormSet 5002 ) 5003 { 5004 EFI_STATUS Status; 5005 LIST_ENTRY *Link; 5006 FORM_BROWSER_FORM *Form; 5007 5008 Link = GetFirstNode (&FormSet->FormListHead); 5009 while (!IsNull (&FormSet->FormListHead, Link)) { 5010 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 5011 5012 // 5013 // Initialize local copy of Value for each Form 5014 // 5015 Status = LoadFormConfig (Selection, FormSet, Form); 5016 if (EFI_ERROR (Status)) { 5017 return Status; 5018 } 5019 5020 Link = GetNextNode (&FormSet->FormListHead, Link); 5021 } 5022 5023 // 5024 // Finished question initialization. 5025 // 5026 FormSet->QuestionInited = TRUE; 5027 5028 return EFI_SUCCESS; 5029 } 5030 5031 /** 5032 Remove the Request element from the Config Request. 5033 5034 @param Storage Pointer to the browser storage. 5035 @param RequestElement The pointer to the Request element. 5036 5037 **/ 5038 VOID 5039 RemoveElement ( 5040 IN OUT BROWSER_STORAGE *Storage, 5041 IN CHAR16 *RequestElement 5042 ) 5043 { 5044 CHAR16 *NewStr; 5045 CHAR16 *DestStr; 5046 5047 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL); 5048 5049 NewStr = StrStr (Storage->ConfigRequest, RequestElement); 5050 5051 if (NewStr == NULL) { 5052 return; 5053 } 5054 5055 // 5056 // Remove this element from this ConfigRequest. 5057 // 5058 DestStr = NewStr; 5059 NewStr += StrLen (RequestElement); 5060 CopyMem (DestStr, NewStr, StrSize (NewStr)); 5061 5062 Storage->SpareStrLen += StrLen (RequestElement); 5063 } 5064 5065 /** 5066 Adjust config request in storage, remove the request elements existed in the input ConfigRequest. 5067 5068 @param Storage Pointer to the formset storage. 5069 @param ConfigRequest The pointer to the Request element. 5070 5071 **/ 5072 VOID 5073 RemoveConfigRequest ( 5074 FORMSET_STORAGE *Storage, 5075 CHAR16 *ConfigRequest 5076 ) 5077 { 5078 CHAR16 *RequestElement; 5079 CHAR16 *NextRequestElement; 5080 CHAR16 *SearchKey; 5081 5082 // 5083 // No request element in it, just return. 5084 // 5085 if (ConfigRequest == NULL) { 5086 return; 5087 } 5088 5089 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 5090 // 5091 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage 5092 // 5093 SearchKey = L"&"; 5094 } else { 5095 // 5096 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage 5097 // 5098 SearchKey = L"&OFFSET"; 5099 } 5100 5101 // 5102 // Find SearchKey storage 5103 // 5104 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 5105 RequestElement = StrStr (ConfigRequest, L"PATH"); 5106 ASSERT (RequestElement != NULL); 5107 RequestElement = StrStr (RequestElement, SearchKey); 5108 } else { 5109 RequestElement = StrStr (ConfigRequest, SearchKey); 5110 } 5111 5112 while (RequestElement != NULL) { 5113 // 5114 // +1 to avoid find header itself. 5115 // 5116 NextRequestElement = StrStr (RequestElement + 1, SearchKey); 5117 5118 // 5119 // The last Request element in configRequest string. 5120 // 5121 if (NextRequestElement != NULL) { 5122 // 5123 // Replace "&" with '\0'. 5124 // 5125 *NextRequestElement = L'\0'; 5126 } 5127 5128 RemoveElement (Storage->BrowserStorage, RequestElement); 5129 5130 if (NextRequestElement != NULL) { 5131 // 5132 // Restore '&' with '\0' for later used. 5133 // 5134 *NextRequestElement = L'&'; 5135 } 5136 5137 RequestElement = NextRequestElement; 5138 } 5139 5140 // 5141 // If no request element remain, just remove the ConfigRequest string. 5142 // 5143 if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) { 5144 FreePool (Storage->BrowserStorage->ConfigRequest); 5145 Storage->BrowserStorage->ConfigRequest = NULL; 5146 Storage->BrowserStorage->SpareStrLen = 0; 5147 } 5148 } 5149 5150 /** 5151 Base on the current formset info, clean the ConfigRequest string in browser storage. 5152 5153 @param FormSet Pointer of the FormSet 5154 5155 **/ 5156 VOID 5157 CleanBrowserStorage ( 5158 IN OUT FORM_BROWSER_FORMSET *FormSet 5159 ) 5160 { 5161 LIST_ENTRY *Link; 5162 FORMSET_STORAGE *Storage; 5163 5164 Link = GetFirstNode (&FormSet->StorageListHead); 5165 while (!IsNull (&FormSet->StorageListHead, Link)) { 5166 Storage = FORMSET_STORAGE_FROM_LINK (Link); 5167 Link = GetNextNode (&FormSet->StorageListHead, Link); 5168 5169 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 5170 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) { 5171 continue; 5172 } 5173 5174 RemoveConfigRequest (Storage, Storage->ConfigRequest); 5175 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER || 5176 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 5177 if (Storage->BrowserStorage->ConfigRequest != NULL) { 5178 FreePool (Storage->BrowserStorage->ConfigRequest); 5179 Storage->BrowserStorage->ConfigRequest = NULL; 5180 } 5181 Storage->BrowserStorage->Initialized = FALSE; 5182 } 5183 } 5184 } 5185 5186 /** 5187 Check whether current element in the ConfigReqeust string. 5188 5189 @param BrowserStorage Storage which includes ConfigReqeust. 5190 @param RequestElement New element need to check. 5191 5192 @retval TRUE The Element is in the ConfigReqeust string. 5193 @retval FALSE The Element not in the configReqeust String. 5194 5195 **/ 5196 BOOLEAN 5197 ElementValidation ( 5198 BROWSER_STORAGE *BrowserStorage, 5199 CHAR16 *RequestElement 5200 ) 5201 { 5202 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE; 5203 } 5204 5205 /** 5206 Append the Request element to the Config Request. 5207 5208 @param ConfigRequest Current ConfigRequest info. 5209 @param SpareStrLen Current remain free buffer for config reqeust. 5210 @param RequestElement New Request element. 5211 5212 **/ 5213 VOID 5214 AppendConfigRequest ( 5215 IN OUT CHAR16 **ConfigRequest, 5216 IN OUT UINTN *SpareStrLen, 5217 IN CHAR16 *RequestElement 5218 ) 5219 { 5220 CHAR16 *NewStr; 5221 UINTN StringSize; 5222 UINTN StrLength; 5223 UINTN MaxLen; 5224 5225 StrLength = StrLen (RequestElement); 5226 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16); 5227 MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen; 5228 5229 // 5230 // Append <RequestElement> to <ConfigRequest> 5231 // 5232 if (StrLength > *SpareStrLen) { 5233 // 5234 // Old String buffer is not sufficient for RequestElement, allocate a new one 5235 // 5236 MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL; 5237 NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 5238 ASSERT (NewStr != NULL); 5239 5240 if (*ConfigRequest != NULL) { 5241 CopyMem (NewStr, *ConfigRequest, StringSize); 5242 FreePool (*ConfigRequest); 5243 } 5244 *ConfigRequest = NewStr; 5245 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; 5246 } 5247 5248 StrCatS (*ConfigRequest, MaxLen, RequestElement); 5249 *SpareStrLen -= StrLength; 5250 } 5251 5252 /** 5253 Adjust the config request info, remove the request elements which already in AllConfigRequest string. 5254 5255 @param Storage Form set Storage. 5256 @param Request The input request string. 5257 @param RespString Whether the input is ConfigRequest or ConfigResp format. 5258 5259 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig 5260 @retval FALSE All elements covered by current used elements. 5261 5262 **/ 5263 BOOLEAN 5264 ConfigRequestAdjust ( 5265 IN BROWSER_STORAGE *Storage, 5266 IN CHAR16 *Request, 5267 IN BOOLEAN RespString 5268 ) 5269 { 5270 CHAR16 *RequestElement; 5271 CHAR16 *NextRequestElement; 5272 CHAR16 *NextElementBakup; 5273 CHAR16 *SearchKey; 5274 CHAR16 *ValueKey; 5275 BOOLEAN RetVal; 5276 CHAR16 *ConfigRequest; 5277 5278 RetVal = FALSE; 5279 NextElementBakup = NULL; 5280 ValueKey = NULL; 5281 5282 if (Request != NULL) { 5283 ConfigRequest = Request; 5284 } else { 5285 ConfigRequest = Storage->ConfigRequest; 5286 } 5287 5288 if (Storage->ConfigRequest == NULL) { 5289 Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); 5290 return TRUE; 5291 } 5292 5293 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 5294 // 5295 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage 5296 // 5297 SearchKey = L"&"; 5298 } else { 5299 // 5300 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage 5301 // 5302 SearchKey = L"&OFFSET"; 5303 ValueKey = L"&VALUE"; 5304 } 5305 5306 // 5307 // Find SearchKey storage 5308 // 5309 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 5310 RequestElement = StrStr (ConfigRequest, L"PATH"); 5311 ASSERT (RequestElement != NULL); 5312 RequestElement = StrStr (RequestElement, SearchKey); 5313 } else { 5314 RequestElement = StrStr (ConfigRequest, SearchKey); 5315 } 5316 5317 while (RequestElement != NULL) { 5318 5319 // 5320 // +1 to avoid find header itself. 5321 // 5322 NextRequestElement = StrStr (RequestElement + 1, SearchKey); 5323 5324 // 5325 // The last Request element in configRequest string. 5326 // 5327 if (NextRequestElement != NULL) { 5328 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 5329 NextElementBakup = NextRequestElement; 5330 NextRequestElement = StrStr (RequestElement, ValueKey); 5331 ASSERT (NextRequestElement != NULL); 5332 } 5333 // 5334 // Replace "&" with '\0'. 5335 // 5336 *NextRequestElement = L'\0'; 5337 } else { 5338 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 5339 NextElementBakup = NextRequestElement; 5340 NextRequestElement = StrStr (RequestElement, ValueKey); 5341 ASSERT (NextRequestElement != NULL); 5342 // 5343 // Replace "&" with '\0'. 5344 // 5345 *NextRequestElement = L'\0'; 5346 } 5347 } 5348 5349 if (!ElementValidation (Storage, RequestElement)) { 5350 // 5351 // Add this element to the Storage->BrowserStorage->AllRequestElement. 5352 // 5353 AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement); 5354 RetVal = TRUE; 5355 } 5356 5357 if (NextRequestElement != NULL) { 5358 // 5359 // Restore '&' with '\0' for later used. 5360 // 5361 *NextRequestElement = L'&'; 5362 } 5363 5364 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 5365 RequestElement = NextElementBakup; 5366 } else { 5367 RequestElement = NextRequestElement; 5368 } 5369 } 5370 5371 return RetVal; 5372 } 5373 5374 /** 5375 Fill storage's edit copy with settings requested from Configuration Driver. 5376 5377 @param FormSet FormSet data structure. 5378 @param Storage Buffer Storage. 5379 5380 **/ 5381 VOID 5382 LoadStorage ( 5383 IN FORM_BROWSER_FORMSET *FormSet, 5384 IN FORMSET_STORAGE *Storage 5385 ) 5386 { 5387 EFI_STATUS Status; 5388 EFI_STRING Progress; 5389 EFI_STRING Result; 5390 CHAR16 *StrPtr; 5391 EFI_STRING ConfigRequest; 5392 UINTN StrLen; 5393 5394 ConfigRequest = NULL; 5395 5396 switch (Storage->BrowserStorage->Type) { 5397 case EFI_HII_VARSTORE_EFI_VARIABLE: 5398 return; 5399 5400 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: 5401 if (Storage->BrowserStorage->ConfigRequest != NULL) { 5402 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); 5403 return; 5404 } 5405 break; 5406 5407 case EFI_HII_VARSTORE_BUFFER: 5408 case EFI_HII_VARSTORE_NAME_VALUE: 5409 // 5410 // Skip if there is no RequestElement. 5411 // 5412 if (Storage->ElementCount == 0) { 5413 return; 5414 } 5415 5416 // 5417 // Just update the ConfigRequest, if storage already initialized. 5418 // 5419 if (Storage->BrowserStorage->Initialized) { 5420 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); 5421 return; 5422 } 5423 5424 Storage->BrowserStorage->Initialized = TRUE; 5425 break; 5426 5427 default: 5428 return; 5429 } 5430 5431 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { 5432 // 5433 // Create the config request string to get all fields for this storage. 5434 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template 5435 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator 5436 // 5437 StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16); 5438 ConfigRequest = AllocateZeroPool (StrLen); 5439 ASSERT (ConfigRequest != NULL); 5440 UnicodeSPrint ( 5441 ConfigRequest, 5442 StrLen, 5443 L"%s&OFFSET=0&WIDTH=%04x", 5444 Storage->ConfigHdr, 5445 Storage->BrowserStorage->Size); 5446 } else { 5447 ConfigRequest = Storage->ConfigRequest; 5448 } 5449 5450 // 5451 // Request current settings from Configuration Driver 5452 // 5453 Status = mHiiConfigRouting->ExtractConfig ( 5454 mHiiConfigRouting, 5455 ConfigRequest, 5456 &Progress, 5457 &Result 5458 ); 5459 5460 // 5461 // If get value fail, extract default from IFR binary 5462 // 5463 if (EFI_ERROR (Status)) { 5464 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE); 5465 } else { 5466 // 5467 // Convert Result from <ConfigAltResp> to <ConfigResp> 5468 // 5469 StrPtr = StrStr (Result, L"&GUID="); 5470 if (StrPtr != NULL) { 5471 *StrPtr = L'\0'; 5472 } 5473 5474 Status = ConfigRespToStorage (Storage->BrowserStorage, Result); 5475 FreePool (Result); 5476 } 5477 5478 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); 5479 5480 // 5481 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. 5482 // 5483 SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE); 5484 5485 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { 5486 if (ConfigRequest != NULL) { 5487 FreePool (ConfigRequest); 5488 } 5489 } 5490 } 5491 5492 /** 5493 Get Value changed status from old question. 5494 5495 @param NewFormSet FormSet data structure. 5496 @param OldQuestion Old question which has value changed. 5497 5498 **/ 5499 VOID 5500 SyncStatusForQuestion ( 5501 IN OUT FORM_BROWSER_FORMSET *NewFormSet, 5502 IN FORM_BROWSER_STATEMENT *OldQuestion 5503 ) 5504 { 5505 LIST_ENTRY *Link; 5506 LIST_ENTRY *QuestionLink; 5507 FORM_BROWSER_FORM *Form; 5508 FORM_BROWSER_STATEMENT *Question; 5509 5510 // 5511 // For each form in one formset. 5512 // 5513 Link = GetFirstNode (&NewFormSet->FormListHead); 5514 while (!IsNull (&NewFormSet->FormListHead, Link)) { 5515 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 5516 Link = GetNextNode (&NewFormSet->FormListHead, Link); 5517 5518 // 5519 // for each question in one form. 5520 // 5521 QuestionLink = GetFirstNode (&Form->StatementListHead); 5522 while (!IsNull (&Form->StatementListHead, QuestionLink)) { 5523 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); 5524 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); 5525 5526 if (Question->QuestionId == OldQuestion->QuestionId) { 5527 Question->ValueChanged = TRUE; 5528 return; 5529 } 5530 } 5531 } 5532 } 5533 5534 /** 5535 Get Value changed status from old formset. 5536 5537 @param NewFormSet FormSet data structure. 5538 @param OldFormSet FormSet data structure. 5539 5540 **/ 5541 VOID 5542 SyncStatusForFormSet ( 5543 IN OUT FORM_BROWSER_FORMSET *NewFormSet, 5544 IN FORM_BROWSER_FORMSET *OldFormSet 5545 ) 5546 { 5547 LIST_ENTRY *Link; 5548 LIST_ENTRY *QuestionLink; 5549 FORM_BROWSER_FORM *Form; 5550 FORM_BROWSER_STATEMENT *Question; 5551 5552 // 5553 // For each form in one formset. 5554 // 5555 Link = GetFirstNode (&OldFormSet->FormListHead); 5556 while (!IsNull (&OldFormSet->FormListHead, Link)) { 5557 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 5558 Link = GetNextNode (&OldFormSet->FormListHead, Link); 5559 5560 // 5561 // for each question in one form. 5562 // 5563 QuestionLink = GetFirstNode (&Form->StatementListHead); 5564 while (!IsNull (&Form->StatementListHead, QuestionLink)) { 5565 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); 5566 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); 5567 5568 if (!Question->ValueChanged) { 5569 continue; 5570 } 5571 5572 // 5573 // Find the same question in new formset and update the value changed flag. 5574 // 5575 SyncStatusForQuestion (NewFormSet, Question); 5576 } 5577 } 5578 } 5579 5580 /** 5581 Get current setting of Questions. 5582 5583 @param FormSet FormSet data structure. 5584 5585 **/ 5586 VOID 5587 InitializeCurrentSetting ( 5588 IN OUT FORM_BROWSER_FORMSET *FormSet 5589 ) 5590 { 5591 LIST_ENTRY *Link; 5592 FORMSET_STORAGE *Storage; 5593 FORM_BROWSER_FORMSET *OldFormSet; 5594 5595 // 5596 // Try to find pre FormSet in the maintain backup list. 5597 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList. 5598 // 5599 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle); 5600 if (OldFormSet != NULL) { 5601 SyncStatusForFormSet (FormSet, OldFormSet); 5602 RemoveEntryList (&OldFormSet->Link); 5603 DestroyFormSet (OldFormSet); 5604 } 5605 InsertTailList (&gBrowserFormSetList, &FormSet->Link); 5606 5607 // 5608 // Extract default from IFR binary for no storage questions. 5609 // 5610 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE); 5611 5612 // 5613 // Request current settings from Configuration Driver 5614 // 5615 Link = GetFirstNode (&FormSet->StorageListHead); 5616 while (!IsNull (&FormSet->StorageListHead, Link)) { 5617 Storage = FORMSET_STORAGE_FROM_LINK (Link); 5618 5619 LoadStorage (FormSet, Storage); 5620 5621 Link = GetNextNode (&FormSet->StorageListHead, Link); 5622 } 5623 } 5624 5625 5626 /** 5627 Fetch the Ifr binary data of a FormSet. 5628 5629 @param Handle PackageList Handle 5630 @param FormSetGuid On input, GUID or class GUID of a formset. If not 5631 specified (NULL or zero GUID), take the first 5632 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID 5633 found in package list. 5634 On output, GUID of the formset found(if not NULL). 5635 @param BinaryLength The length of the FormSet IFR binary. 5636 @param BinaryData The buffer designed to receive the FormSet. 5637 5638 @retval EFI_SUCCESS Buffer filled with the requested FormSet. 5639 BufferLength was updated. 5640 @retval EFI_INVALID_PARAMETER The handle is unknown. 5641 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot 5642 be found with the requested FormId. 5643 5644 **/ 5645 EFI_STATUS 5646 GetIfrBinaryData ( 5647 IN EFI_HII_HANDLE Handle, 5648 IN OUT EFI_GUID *FormSetGuid, 5649 OUT UINTN *BinaryLength, 5650 OUT UINT8 **BinaryData 5651 ) 5652 { 5653 EFI_STATUS Status; 5654 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; 5655 UINTN BufferSize; 5656 UINT8 *Package; 5657 UINT8 *OpCodeData; 5658 UINT32 Offset; 5659 UINT32 Offset2; 5660 UINT32 PackageListLength; 5661 EFI_HII_PACKAGE_HEADER PackageHeader; 5662 UINT8 Index; 5663 UINT8 NumberOfClassGuid; 5664 BOOLEAN ClassGuidMatch; 5665 EFI_GUID *ClassGuid; 5666 EFI_GUID *ComparingGuid; 5667 5668 OpCodeData = NULL; 5669 Package = NULL; 5670 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER)); 5671 5672 // 5673 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list 5674 // 5675 if (FormSetGuid == NULL) { 5676 ComparingGuid = &gZeroGuid; 5677 } else { 5678 ComparingGuid = FormSetGuid; 5679 } 5680 5681 // 5682 // Get HII PackageList 5683 // 5684 BufferSize = 0; 5685 HiiPackageList = NULL; 5686 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); 5687 if (Status == EFI_BUFFER_TOO_SMALL) { 5688 HiiPackageList = AllocatePool (BufferSize); 5689 ASSERT (HiiPackageList != NULL); 5690 5691 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); 5692 } 5693 if (EFI_ERROR (Status)) { 5694 return Status; 5695 } 5696 ASSERT (HiiPackageList != NULL); 5697 5698 // 5699 // Get Form package from this HII package List 5700 // 5701 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); 5702 Offset2 = 0; 5703 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); 5704 5705 ClassGuidMatch = FALSE; 5706 while (Offset < PackageListLength) { 5707 Package = ((UINT8 *) HiiPackageList) + Offset; 5708 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); 5709 5710 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { 5711 // 5712 // Search FormSet in this Form Package 5713 // 5714 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); 5715 while (Offset2 < PackageHeader.Length) { 5716 OpCodeData = Package + Offset2; 5717 5718 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { 5719 // 5720 // Try to compare against formset GUID 5721 // 5722 if (IsZeroGuid (FormSetGuid) || 5723 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { 5724 break; 5725 } 5726 5727 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) { 5728 // 5729 // Try to compare against formset class GUID 5730 // 5731 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3); 5732 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET)); 5733 for (Index = 0; Index < NumberOfClassGuid; Index++) { 5734 if (CompareGuid (ComparingGuid, ClassGuid + Index)) { 5735 ClassGuidMatch = TRUE; 5736 break; 5737 } 5738 } 5739 if (ClassGuidMatch) { 5740 break; 5741 } 5742 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) { 5743 ClassGuidMatch = TRUE; 5744 break; 5745 } 5746 } 5747 5748 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; 5749 } 5750 5751 if (Offset2 < PackageHeader.Length) { 5752 // 5753 // Target formset found 5754 // 5755 break; 5756 } 5757 } 5758 5759 Offset += PackageHeader.Length; 5760 } 5761 5762 if (Offset >= PackageListLength) { 5763 // 5764 // Form package not found in this Package List 5765 // 5766 FreePool (HiiPackageList); 5767 return EFI_NOT_FOUND; 5768 } 5769 5770 if (FormSetGuid != NULL) { 5771 // 5772 // Return the FormSet GUID 5773 // 5774 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); 5775 } 5776 5777 // 5778 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes 5779 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end 5780 // of the Form Package. 5781 // 5782 *BinaryLength = PackageHeader.Length - Offset2; 5783 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); 5784 5785 FreePool (HiiPackageList); 5786 5787 if (*BinaryData == NULL) { 5788 return EFI_OUT_OF_RESOURCES; 5789 } 5790 5791 return EFI_SUCCESS; 5792 } 5793 5794 5795 /** 5796 Initialize the internal data structure of a FormSet. 5797 5798 @param Handle PackageList Handle 5799 @param FormSetGuid On input, GUID or class GUID of a formset. If not 5800 specified (NULL or zero GUID), take the first 5801 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID 5802 found in package list. 5803 On output, GUID of the formset found(if not NULL). 5804 @param FormSet FormSet data structure. 5805 5806 @retval EFI_SUCCESS The function completed successfully. 5807 @retval EFI_NOT_FOUND The specified FormSet could not be found. 5808 5809 **/ 5810 EFI_STATUS 5811 InitializeFormSet ( 5812 IN EFI_HII_HANDLE Handle, 5813 IN OUT EFI_GUID *FormSetGuid, 5814 OUT FORM_BROWSER_FORMSET *FormSet 5815 ) 5816 { 5817 EFI_STATUS Status; 5818 EFI_HANDLE DriverHandle; 5819 5820 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); 5821 if (EFI_ERROR (Status)) { 5822 return Status; 5823 } 5824 5825 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE; 5826 FormSet->HiiHandle = Handle; 5827 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); 5828 FormSet->QuestionInited = FALSE; 5829 5830 // 5831 // Retrieve ConfigAccess Protocol associated with this HiiPackageList 5832 // 5833 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); 5834 if (EFI_ERROR (Status)) { 5835 return Status; 5836 } 5837 FormSet->DriverHandle = DriverHandle; 5838 Status = gBS->HandleProtocol ( 5839 DriverHandle, 5840 &gEfiHiiConfigAccessProtocolGuid, 5841 (VOID **) &FormSet->ConfigAccess 5842 ); 5843 if (EFI_ERROR (Status)) { 5844 // 5845 // Configuration Driver don't attach ConfigAccess protocol to its HII package 5846 // list, then there will be no configuration action required 5847 // 5848 FormSet->ConfigAccess = NULL; 5849 } 5850 5851 // 5852 // Parse the IFR binary OpCodes 5853 // 5854 Status = ParseOpCodes (FormSet); 5855 5856 return Status; 5857 } 5858 5859 5860 /** 5861 Save globals used by previous call to SendForm(). SendForm() may be called from 5862 HiiConfigAccess.Callback(), this will cause SendForm() be reentried. 5863 So, save globals of previous call to SendForm() and restore them upon exit. 5864 5865 **/ 5866 VOID 5867 SaveBrowserContext ( 5868 VOID 5869 ) 5870 { 5871 BROWSER_CONTEXT *Context; 5872 FORM_ENTRY_INFO *MenuList; 5873 FORM_BROWSER_FORMSET *FormSet; 5874 5875 gBrowserContextCount++; 5876 if (gBrowserContextCount == 1) { 5877 // 5878 // This is not reentry of SendForm(), no context to save 5879 // 5880 return; 5881 } 5882 5883 Context = AllocatePool (sizeof (BROWSER_CONTEXT)); 5884 ASSERT (Context != NULL); 5885 5886 Context->Signature = BROWSER_CONTEXT_SIGNATURE; 5887 5888 // 5889 // Save FormBrowser context 5890 // 5891 Context->Selection = gCurrentSelection; 5892 Context->ResetRequired = gResetRequired; 5893 Context->FlagReconnect = gFlagReconnect; 5894 Context->CallbackReconnect = gCallbackReconnect; 5895 Context->ExitRequired = gExitRequired; 5896 Context->HiiHandle = mCurrentHiiHandle; 5897 Context->FormId = mCurrentFormId; 5898 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid); 5899 Context->SystemLevelFormSet = mSystemLevelFormSet; 5900 Context->CurFakeQestId = mCurFakeQestId; 5901 Context->HiiPackageListUpdated = mHiiPackageListUpdated; 5902 Context->FinishRetrieveCall = mFinishRetrieveCall; 5903 5904 // 5905 // Save the menu history data. 5906 // 5907 InitializeListHead(&Context->FormHistoryList); 5908 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { 5909 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); 5910 RemoveEntryList (&MenuList->Link); 5911 5912 InsertTailList(&Context->FormHistoryList, &MenuList->Link); 5913 } 5914 5915 // 5916 // Save formset list. 5917 // 5918 InitializeListHead(&Context->FormSetList); 5919 while (!IsListEmpty (&gBrowserFormSetList)) { 5920 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink); 5921 RemoveEntryList (&FormSet->Link); 5922 5923 InsertTailList(&Context->FormSetList, &FormSet->Link); 5924 } 5925 5926 // 5927 // Insert to FormBrowser context list 5928 // 5929 InsertHeadList (&gBrowserContextList, &Context->Link); 5930 } 5931 5932 5933 /** 5934 Restore globals used by previous call to SendForm(). 5935 5936 **/ 5937 VOID 5938 RestoreBrowserContext ( 5939 VOID 5940 ) 5941 { 5942 LIST_ENTRY *Link; 5943 BROWSER_CONTEXT *Context; 5944 FORM_ENTRY_INFO *MenuList; 5945 FORM_BROWSER_FORMSET *FormSet; 5946 5947 ASSERT (gBrowserContextCount != 0); 5948 gBrowserContextCount--; 5949 if (gBrowserContextCount == 0) { 5950 // 5951 // This is not reentry of SendForm(), no context to restore 5952 // 5953 return; 5954 } 5955 5956 ASSERT (!IsListEmpty (&gBrowserContextList)); 5957 5958 Link = GetFirstNode (&gBrowserContextList); 5959 Context = BROWSER_CONTEXT_FROM_LINK (Link); 5960 5961 // 5962 // Restore FormBrowser context 5963 // 5964 gCurrentSelection = Context->Selection; 5965 gResetRequired = Context->ResetRequired; 5966 gFlagReconnect = Context->FlagReconnect; 5967 gCallbackReconnect = Context->CallbackReconnect; 5968 gExitRequired = Context->ExitRequired; 5969 mCurrentHiiHandle = Context->HiiHandle; 5970 mCurrentFormId = Context->FormId; 5971 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid); 5972 mSystemLevelFormSet = Context->SystemLevelFormSet; 5973 mCurFakeQestId = Context->CurFakeQestId; 5974 mHiiPackageListUpdated = Context->HiiPackageListUpdated; 5975 mFinishRetrieveCall = Context->FinishRetrieveCall; 5976 5977 // 5978 // Restore the menu history data. 5979 // 5980 while (!IsListEmpty (&Context->FormHistoryList)) { 5981 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink); 5982 RemoveEntryList (&MenuList->Link); 5983 5984 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); 5985 } 5986 5987 // 5988 // Restore the Formset data. 5989 // 5990 while (!IsListEmpty (&Context->FormSetList)) { 5991 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink); 5992 RemoveEntryList (&FormSet->Link); 5993 5994 InsertTailList(&gBrowserFormSetList, &FormSet->Link); 5995 } 5996 5997 // 5998 // Remove from FormBrowser context list 5999 // 6000 RemoveEntryList (&Context->Link); 6001 gBS->FreePool (Context); 6002 } 6003 6004 /** 6005 Find the matched FormSet context in the backup maintain list based on HiiHandle. 6006 6007 @param Handle The Hii Handle. 6008 6009 @return the found FormSet context. If no found, NULL will return. 6010 6011 **/ 6012 FORM_BROWSER_FORMSET * 6013 GetFormSetFromHiiHandle ( 6014 EFI_HII_HANDLE Handle 6015 ) 6016 { 6017 LIST_ENTRY *Link; 6018 FORM_BROWSER_FORMSET *FormSet; 6019 6020 Link = GetFirstNode (&gBrowserFormSetList); 6021 while (!IsNull (&gBrowserFormSetList, Link)) { 6022 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 6023 Link = GetNextNode (&gBrowserFormSetList, Link); 6024 if (!ValidateFormSet(FormSet)) { 6025 continue; 6026 } 6027 if (FormSet->HiiHandle == Handle) { 6028 return FormSet; 6029 } 6030 } 6031 6032 return NULL; 6033 } 6034 6035 /** 6036 Check whether the input HII handle is the FormSet that is being used. 6037 6038 @param Handle The Hii Handle. 6039 6040 @retval TRUE HII handle is being used. 6041 @retval FALSE HII handle is not being used. 6042 6043 **/ 6044 BOOLEAN 6045 IsHiiHandleInBrowserContext ( 6046 EFI_HII_HANDLE Handle 6047 ) 6048 { 6049 LIST_ENTRY *Link; 6050 BROWSER_CONTEXT *Context; 6051 6052 // 6053 // HiiHandle is Current FormSet. 6054 // 6055 if (mCurrentHiiHandle == Handle) { 6056 return TRUE; 6057 } 6058 6059 // 6060 // Check whether HiiHandle is in BrowserContext. 6061 // 6062 Link = GetFirstNode (&gBrowserContextList); 6063 while (!IsNull (&gBrowserContextList, Link)) { 6064 Context = BROWSER_CONTEXT_FROM_LINK (Link); 6065 if (Context->HiiHandle == Handle) { 6066 // 6067 // HiiHandle is in BrowserContext 6068 // 6069 return TRUE; 6070 } 6071 Link = GetNextNode (&gBrowserContextList, Link); 6072 } 6073 6074 return FALSE; 6075 } 6076 6077 /** 6078 Perform Password check. 6079 Passwork may be encrypted by driver that requires the specific check. 6080 6081 @param Form Form where Password Statement is in. 6082 @param Statement Password statement 6083 @param PasswordString Password string to be checked. It may be NULL. 6084 NULL means to restore password. 6085 "" string can be used to checked whether old password does exist. 6086 6087 @return Status Status of Password check. 6088 **/ 6089 EFI_STATUS 6090 EFIAPI 6091 PasswordCheck ( 6092 IN FORM_DISPLAY_ENGINE_FORM *Form, 6093 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, 6094 IN EFI_STRING PasswordString OPTIONAL 6095 ) 6096 { 6097 EFI_STATUS Status; 6098 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 6099 EFI_BROWSER_ACTION_REQUEST ActionRequest; 6100 EFI_IFR_TYPE_VALUE IfrTypeValue; 6101 FORM_BROWSER_STATEMENT *Question; 6102 6103 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess; 6104 Question = GetBrowserStatement(Statement); 6105 ASSERT (Question != NULL); 6106 6107 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) { 6108 if (ConfigAccess == NULL) { 6109 return EFI_UNSUPPORTED; 6110 } 6111 } else { 6112 // 6113 // If a password doesn't have the CALLBACK flag, browser will not handle it. 6114 // 6115 return EFI_UNSUPPORTED; 6116 } 6117 6118 // 6119 // Prepare password string in HII database 6120 // 6121 if (PasswordString != NULL) { 6122 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle); 6123 } else { 6124 IfrTypeValue.string = 0; 6125 } 6126 6127 // 6128 // Send password to Configuration Driver for validation 6129 // 6130 Status = ConfigAccess->Callback ( 6131 ConfigAccess, 6132 EFI_BROWSER_ACTION_CHANGING, 6133 Question->QuestionId, 6134 Question->HiiValue.Type, 6135 &IfrTypeValue, 6136 &ActionRequest 6137 ); 6138 6139 // 6140 // Remove password string from HII database 6141 // 6142 if (PasswordString != NULL) { 6143 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle); 6144 } 6145 6146 return Status; 6147 } 6148 6149 /** 6150 Find the registered HotKey based on KeyData. 6151 6152 @param[in] KeyData A pointer to a buffer that describes the keystroke 6153 information for the hot key. 6154 6155 @return The registered HotKey context. If no found, NULL will return. 6156 **/ 6157 BROWSER_HOT_KEY * 6158 GetHotKeyFromRegisterList ( 6159 IN EFI_INPUT_KEY *KeyData 6160 ) 6161 { 6162 LIST_ENTRY *Link; 6163 BROWSER_HOT_KEY *HotKey; 6164 6165 Link = GetFirstNode (&gBrowserHotKeyList); 6166 while (!IsNull (&gBrowserHotKeyList, Link)) { 6167 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); 6168 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) { 6169 return HotKey; 6170 } 6171 Link = GetNextNode (&gBrowserHotKeyList, Link); 6172 } 6173 6174 return NULL; 6175 } 6176 6177 /** 6178 Configure what scope the hot key will impact. 6179 All hot keys have the same scope. The mixed hot keys with the different level are not supported. 6180 If no scope is set, the default scope will be FormSet level. 6181 After all registered hot keys are removed, previous Scope can reset to another level. 6182 6183 @param[in] Scope Scope level to be set. 6184 6185 @retval EFI_SUCCESS Scope is set correctly. 6186 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. 6187 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. 6188 6189 **/ 6190 EFI_STATUS 6191 EFIAPI 6192 SetScope ( 6193 IN BROWSER_SETTING_SCOPE Scope 6194 ) 6195 { 6196 if (Scope >= MaxLevel) { 6197 return EFI_INVALID_PARAMETER; 6198 } 6199 6200 // 6201 // When no hot key registered in system or on the first setting, 6202 // Scope can be set. 6203 // 6204 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) { 6205 gBrowserSettingScope = Scope; 6206 mBrowserScopeFirstSet = FALSE; 6207 } else if (Scope != gBrowserSettingScope) { 6208 return EFI_UNSUPPORTED; 6209 } 6210 6211 return EFI_SUCCESS; 6212 } 6213 6214 /** 6215 Register the hot key with its browser action, or unregistered the hot key. 6216 Only support hot key that is not printable character (control key, function key, etc.). 6217 If the action value is zero, the hot key will be unregistered if it has been registered. 6218 If the same hot key has been registered, the new action and help string will override the previous ones. 6219 6220 @param[in] KeyData A pointer to a buffer that describes the keystroke 6221 information for the hot key. Its type is EFI_INPUT_KEY to 6222 be supported by all ConsoleIn devices. 6223 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. 6224 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. 6225 @param[in] HelpString Help string that describes the hot key information. 6226 Its value may be NULL for the unregistered hot key. 6227 6228 @retval EFI_SUCCESS Hot key is registered or unregistered. 6229 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register. 6230 @retval EFI_NOT_FOUND KeyData is not found to be unregistered. 6231 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. 6232 @retval EFI_ALREADY_STARTED Key already been registered for one hot key. 6233 **/ 6234 EFI_STATUS 6235 EFIAPI 6236 RegisterHotKey ( 6237 IN EFI_INPUT_KEY *KeyData, 6238 IN UINT32 Action, 6239 IN UINT16 DefaultId, 6240 IN EFI_STRING HelpString OPTIONAL 6241 ) 6242 { 6243 BROWSER_HOT_KEY *HotKey; 6244 6245 // 6246 // Check input parameters. 6247 // 6248 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || 6249 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) { 6250 return EFI_INVALID_PARAMETER; 6251 } 6252 6253 // 6254 // Check whether the input KeyData is in BrowserHotKeyList. 6255 // 6256 HotKey = GetHotKeyFromRegisterList (KeyData); 6257 6258 // 6259 // Unregister HotKey 6260 // 6261 if (Action == BROWSER_ACTION_UNREGISTER) { 6262 if (HotKey != NULL) { 6263 // 6264 // The registered HotKey is found. 6265 // Remove it from List, and free its resource. 6266 // 6267 RemoveEntryList (&HotKey->Link); 6268 FreePool (HotKey->KeyData); 6269 FreePool (HotKey->HelpString); 6270 return EFI_SUCCESS; 6271 } else { 6272 // 6273 // The registered HotKey is not found. 6274 // 6275 return EFI_NOT_FOUND; 6276 } 6277 } 6278 6279 if (HotKey != NULL) { 6280 return EFI_ALREADY_STARTED; 6281 } 6282 6283 // 6284 // Create new Key, and add it into List. 6285 // 6286 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY)); 6287 ASSERT (HotKey != NULL); 6288 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE; 6289 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData); 6290 InsertTailList (&gBrowserHotKeyList, &HotKey->Link); 6291 6292 // 6293 // Fill HotKey information. 6294 // 6295 HotKey->Action = Action; 6296 HotKey->DefaultId = DefaultId; 6297 if (HotKey->HelpString != NULL) { 6298 FreePool (HotKey->HelpString); 6299 } 6300 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString); 6301 6302 return EFI_SUCCESS; 6303 } 6304 6305 /** 6306 Register Exit handler function. 6307 When more than one handler function is registered, the latter one will override the previous one. 6308 When NULL handler is specified, the previous Exit handler will be unregistered. 6309 6310 @param[in] Handler Pointer to handler function. 6311 6312 **/ 6313 VOID 6314 EFIAPI 6315 RegiserExitHandler ( 6316 IN EXIT_HANDLER Handler 6317 ) 6318 { 6319 ExitHandlerFunction = Handler; 6320 return; 6321 } 6322 6323 /** 6324 Check whether the browser data has been modified. 6325 6326 @retval TRUE Browser data is modified. 6327 @retval FALSE No browser data is modified. 6328 6329 **/ 6330 BOOLEAN 6331 EFIAPI 6332 IsBrowserDataModified ( 6333 VOID 6334 ) 6335 { 6336 LIST_ENTRY *Link; 6337 FORM_BROWSER_FORMSET *FormSet; 6338 6339 switch (gBrowserSettingScope) { 6340 case FormLevel: 6341 if (gCurrentSelection == NULL) { 6342 return FALSE; 6343 } 6344 return IsNvUpdateRequiredForForm (gCurrentSelection->Form); 6345 6346 case FormSetLevel: 6347 if (gCurrentSelection == NULL) { 6348 return FALSE; 6349 } 6350 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet); 6351 6352 case SystemLevel: 6353 Link = GetFirstNode (&gBrowserFormSetList); 6354 while (!IsNull (&gBrowserFormSetList, Link)) { 6355 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 6356 if (!ValidateFormSet(FormSet)) { 6357 continue; 6358 } 6359 6360 if (IsNvUpdateRequiredForFormSet (FormSet)) { 6361 return TRUE; 6362 } 6363 Link = GetNextNode (&gBrowserFormSetList, Link); 6364 } 6365 return FALSE; 6366 6367 default: 6368 return FALSE; 6369 } 6370 } 6371 6372 /** 6373 Execute the action requested by the Action parameter. 6374 6375 @param[in] Action Execute the request action. 6376 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT. 6377 6378 @retval EFI_SUCCESS Execute the request action succss. 6379 @retval EFI_INVALID_PARAMETER The input action value is invalid. 6380 6381 **/ 6382 EFI_STATUS 6383 EFIAPI 6384 ExecuteAction ( 6385 IN UINT32 Action, 6386 IN UINT16 DefaultId 6387 ) 6388 { 6389 EFI_STATUS Status; 6390 FORM_BROWSER_FORMSET *FormSet; 6391 FORM_BROWSER_FORM *Form; 6392 6393 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) { 6394 return EFI_NOT_READY; 6395 } 6396 6397 Status = EFI_SUCCESS; 6398 FormSet = NULL; 6399 Form = NULL; 6400 if (gBrowserSettingScope < SystemLevel) { 6401 FormSet = gCurrentSelection->FormSet; 6402 Form = gCurrentSelection->Form; 6403 } 6404 6405 // 6406 // Executet the discard action. 6407 // 6408 if ((Action & BROWSER_ACTION_DISCARD) != 0) { 6409 Status = DiscardForm (FormSet, Form, gBrowserSettingScope); 6410 if (EFI_ERROR (Status)) { 6411 return Status; 6412 } 6413 } 6414 6415 // 6416 // Executet the difault action. 6417 // 6418 if ((Action & BROWSER_ACTION_DEFAULT) != 0) { 6419 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE); 6420 if (EFI_ERROR (Status)) { 6421 return Status; 6422 } 6423 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope); 6424 } 6425 6426 // 6427 // Executet the submit action. 6428 // 6429 if ((Action & BROWSER_ACTION_SUBMIT) != 0) { 6430 Status = SubmitForm (FormSet, Form, gBrowserSettingScope); 6431 if (EFI_ERROR (Status)) { 6432 return Status; 6433 } 6434 } 6435 6436 // 6437 // Executet the reset action. 6438 // 6439 if ((Action & BROWSER_ACTION_RESET) != 0) { 6440 gResetRequired = TRUE; 6441 } 6442 6443 // 6444 // Executet the exit action. 6445 // 6446 if ((Action & BROWSER_ACTION_EXIT) != 0) { 6447 DiscardForm (FormSet, Form, gBrowserSettingScope); 6448 if (gBrowserSettingScope == SystemLevel) { 6449 if (ExitHandlerFunction != NULL) { 6450 ExitHandlerFunction (); 6451 } 6452 } 6453 6454 gExitRequired = TRUE; 6455 } 6456 6457 return Status; 6458 } 6459 6460 /** 6461 Create reminder to let user to choose save or discard the changed browser data. 6462 Caller can use it to actively check the changed browser data. 6463 6464 @retval BROWSER_NO_CHANGES No browser data is changed. 6465 @retval BROWSER_SAVE_CHANGES The changed browser data is saved. 6466 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. 6467 @retval BROWSER_KEEP_CURRENT Browser keep current changes. 6468 6469 **/ 6470 UINT32 6471 EFIAPI 6472 SaveReminder ( 6473 VOID 6474 ) 6475 { 6476 LIST_ENTRY *Link; 6477 FORM_BROWSER_FORMSET *FormSet; 6478 BOOLEAN IsDataChanged; 6479 UINT32 DataSavedAction; 6480 UINT32 ConfirmRet; 6481 6482 DataSavedAction = BROWSER_NO_CHANGES; 6483 IsDataChanged = FALSE; 6484 Link = GetFirstNode (&gBrowserFormSetList); 6485 while (!IsNull (&gBrowserFormSetList, Link)) { 6486 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 6487 Link = GetNextNode (&gBrowserFormSetList, Link); 6488 if (!ValidateFormSet(FormSet)) { 6489 continue; 6490 } 6491 if (IsNvUpdateRequiredForFormSet (FormSet)) { 6492 IsDataChanged = TRUE; 6493 break; 6494 } 6495 } 6496 6497 // 6498 // No data is changed. No save is required. 6499 // 6500 if (!IsDataChanged) { 6501 return DataSavedAction; 6502 } 6503 6504 // 6505 // If data is changed, prompt user to save or discard it. 6506 // 6507 do { 6508 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange(); 6509 6510 if (ConfirmRet == BROWSER_ACTION_SUBMIT) { 6511 SubmitForm (NULL, NULL, SystemLevel); 6512 DataSavedAction = BROWSER_SAVE_CHANGES; 6513 break; 6514 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) { 6515 DiscardForm (NULL, NULL, SystemLevel); 6516 DataSavedAction = BROWSER_DISCARD_CHANGES; 6517 break; 6518 } else if (ConfirmRet == BROWSER_ACTION_NONE) { 6519 DataSavedAction = BROWSER_KEEP_CURRENT; 6520 break; 6521 } 6522 } while (1); 6523 6524 return DataSavedAction; 6525 } 6526 6527 /** 6528 Check whether the Reset Required for the browser 6529 6530 @retval TRUE Browser required to reset after exit. 6531 @retval FALSE Browser not need to reset after exit. 6532 6533 **/ 6534 BOOLEAN 6535 EFIAPI 6536 IsResetRequired ( 6537 VOID 6538 ) 6539 { 6540 return gResetRequired; 6541 } 6542 6543