1 /** @file 2 Entry and initialization module for the browser. 3 4 Copyright (c) 2007 - 2015, 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 (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) { 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 &gEfiFormBrowserExProtocolGuid, 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 Status = EFI_SUCCESS; 1433 if (!IsBufferStorage && IsString) { 1434 // 1435 // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" 1436 // Add string tail char L'\0' into Length 1437 // 1438 Length = Question->StorageWidth + sizeof (CHAR16); 1439 if (Length < ((LengthStr / 4 + 1) * 2)) { 1440 Status = EFI_BUFFER_TOO_SMALL; 1441 } else { 1442 DstBuf = (CHAR16 *) Dst; 1443 ZeroMem (TemStr, sizeof (TemStr)); 1444 for (Index = 0; Index < LengthStr; Index += 4) { 1445 StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), Value + Index, 4); 1446 DstBuf[Index/4] = (CHAR16) StrHexToUint64 (TemStr); 1447 } 1448 // 1449 // Add tailing L'\0' character 1450 // 1451 DstBuf[Index/4] = L'\0'; 1452 } 1453 } else { 1454 if (Question->StorageWidth < ((LengthStr + 1) / 2)) { 1455 Status = EFI_BUFFER_TOO_SMALL; 1456 } else { 1457 ZeroMem (TemStr, sizeof (TemStr)); 1458 for (Index = 0; Index < LengthStr; Index ++) { 1459 TemStr[0] = Value[LengthStr - Index - 1]; 1460 DigitUint8 = (UINT8) StrHexToUint64 (TemStr); 1461 if ((Index & 1) == 0) { 1462 Dst [Index/2] = DigitUint8; 1463 } else { 1464 Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]); 1465 } 1466 } 1467 } 1468 } 1469 1470 *StringPtr = TempChar; 1471 1472 return Status; 1473 } 1474 1475 /** 1476 Get Question's current Value. 1477 1478 @param FormSet FormSet data structure. 1479 @param Form Form data structure. 1480 @param Question Question to be initialized. 1481 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. 1482 1483 @retval EFI_SUCCESS The function completed successfully. 1484 1485 **/ 1486 EFI_STATUS 1487 GetQuestionValue ( 1488 IN FORM_BROWSER_FORMSET *FormSet, 1489 IN FORM_BROWSER_FORM *Form, 1490 IN OUT FORM_BROWSER_STATEMENT *Question, 1491 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom 1492 ) 1493 { 1494 EFI_STATUS Status; 1495 BOOLEAN Enabled; 1496 BOOLEAN Pending; 1497 UINT8 *Dst; 1498 UINTN StorageWidth; 1499 EFI_TIME EfiTime; 1500 BROWSER_STORAGE *Storage; 1501 FORMSET_STORAGE *FormsetStorage; 1502 EFI_IFR_TYPE_VALUE *QuestionValue; 1503 CHAR16 *ConfigRequest; 1504 CHAR16 *Progress; 1505 CHAR16 *Result; 1506 CHAR16 *Value; 1507 UINTN Length; 1508 BOOLEAN IsBufferStorage; 1509 UINTN MaxLen; 1510 1511 Status = EFI_SUCCESS; 1512 Value = NULL; 1513 Result = NULL; 1514 1515 if (GetValueFrom >= GetSetValueWithMax) { 1516 return EFI_INVALID_PARAMETER; 1517 } 1518 1519 // 1520 // Question value is provided by an Expression, evaluate it 1521 // 1522 if (Question->ValueExpression != NULL) { 1523 Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); 1524 if (!EFI_ERROR (Status)) { 1525 if (Question->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { 1526 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL); 1527 if (Question->StorageWidth > Question->ValueExpression->Result.BufferLen) { 1528 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->ValueExpression->Result.BufferLen); 1529 Question->HiiValue.BufferLen = Question->ValueExpression->Result.BufferLen; 1530 } else { 1531 CopyMem (Question->HiiValue.Buffer, Question->ValueExpression->Result.Buffer, Question->StorageWidth); 1532 Question->HiiValue.BufferLen = Question->StorageWidth; 1533 } 1534 FreePool (Question->ValueExpression->Result.Buffer); 1535 } 1536 Question->HiiValue.Type = Question->ValueExpression->Result.Type; 1537 CopyMem (&Question->HiiValue.Value, &Question->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); 1538 } 1539 return Status; 1540 } 1541 1542 // 1543 // Get question value by read expression. 1544 // 1545 if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) { 1546 Status = EvaluateExpression (FormSet, Form, Question->ReadExpression); 1547 if (!EFI_ERROR (Status) && 1548 ((Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER) || (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER))) { 1549 // 1550 // Only update question value to the valid result. 1551 // 1552 if (Question->ReadExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { 1553 ASSERT (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER && Question->HiiValue.Buffer != NULL); 1554 if (Question->StorageWidth > Question->ReadExpression->Result.BufferLen) { 1555 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->ReadExpression->Result.BufferLen); 1556 Question->HiiValue.BufferLen = Question->ReadExpression->Result.BufferLen; 1557 } else { 1558 CopyMem (Question->HiiValue.Buffer, Question->ReadExpression->Result.Buffer, Question->StorageWidth); 1559 Question->HiiValue.BufferLen = Question->StorageWidth; 1560 } 1561 FreePool (Question->ReadExpression->Result.Buffer); 1562 } 1563 Question->HiiValue.Type = Question->ReadExpression->Result.Type; 1564 CopyMem (&Question->HiiValue.Value, &Question->ReadExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); 1565 return EFI_SUCCESS; 1566 } 1567 } 1568 1569 // 1570 // Question value is provided by RTC 1571 // 1572 Storage = Question->Storage; 1573 QuestionValue = &Question->HiiValue.Value; 1574 if (Storage == NULL) { 1575 // 1576 // It's a Question without storage, or RTC date/time 1577 // 1578 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { 1579 // 1580 // Date and time define the same Flags bit 1581 // 1582 switch (Question->Flags & EFI_QF_DATE_STORAGE) { 1583 case QF_DATE_STORAGE_TIME: 1584 Status = gRT->GetTime (&EfiTime, NULL); 1585 break; 1586 1587 case QF_DATE_STORAGE_WAKEUP: 1588 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); 1589 break; 1590 1591 case QF_DATE_STORAGE_NORMAL: 1592 default: 1593 // 1594 // For date/time without storage 1595 // 1596 return EFI_SUCCESS; 1597 } 1598 1599 if (EFI_ERROR (Status)) { 1600 if (Question->Operand == EFI_IFR_DATE_OP){ 1601 QuestionValue->date.Year = 0xff; 1602 QuestionValue->date.Month = 0xff; 1603 QuestionValue->date.Day = 0xff; 1604 } else { 1605 QuestionValue->time.Hour = 0xff; 1606 QuestionValue->time.Minute = 0xff; 1607 QuestionValue->time.Second = 0xff; 1608 } 1609 return EFI_SUCCESS; 1610 } 1611 1612 if (Question->Operand == EFI_IFR_DATE_OP) { 1613 QuestionValue->date.Year = EfiTime.Year; 1614 QuestionValue->date.Month = EfiTime.Month; 1615 QuestionValue->date.Day = EfiTime.Day; 1616 } else { 1617 QuestionValue->time.Hour = EfiTime.Hour; 1618 QuestionValue->time.Minute = EfiTime.Minute; 1619 QuestionValue->time.Second = EfiTime.Second; 1620 } 1621 } 1622 1623 return EFI_SUCCESS; 1624 } 1625 1626 // 1627 // Question value is provided by EFI variable 1628 // 1629 StorageWidth = Question->StorageWidth; 1630 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 1631 if (Question->BufferValue != NULL) { 1632 Dst = Question->BufferValue; 1633 } else { 1634 Dst = (UINT8 *) QuestionValue; 1635 } 1636 1637 Status = gRT->GetVariable ( 1638 Question->VariableName, 1639 &Storage->Guid, 1640 NULL, 1641 &StorageWidth, 1642 Dst 1643 ); 1644 // 1645 // Always return success, even this EFI variable doesn't exist 1646 // 1647 return EFI_SUCCESS; 1648 } 1649 1650 // 1651 // Question Value is provided by Buffer Storage or NameValue Storage 1652 // 1653 if (Question->BufferValue != NULL) { 1654 // 1655 // This Question is password or orderedlist 1656 // 1657 Dst = Question->BufferValue; 1658 } else { 1659 // 1660 // Other type of Questions 1661 // 1662 Dst = (UINT8 *) &Question->HiiValue.Value; 1663 } 1664 1665 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 1666 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 1667 IsBufferStorage = TRUE; 1668 } else { 1669 IsBufferStorage = FALSE; 1670 } 1671 if (GetValueFrom == GetSetValueWithEditBuffer || GetValueFrom == GetSetValueWithBuffer ) { 1672 if (IsBufferStorage) { 1673 if (GetValueFrom == GetSetValueWithEditBuffer) { 1674 // 1675 // Copy from storage Edit buffer 1676 // 1677 CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); 1678 } else { 1679 // 1680 // Copy from storage Edit buffer 1681 // 1682 CopyMem (Dst, Storage->Buffer + Question->VarStoreInfo.VarOffset, StorageWidth); 1683 } 1684 } else { 1685 Value = NULL; 1686 Status = GetValueByName (Storage, Question->VariableName, &Value, GetValueFrom); 1687 if (EFI_ERROR (Status)) { 1688 return Status; 1689 } 1690 1691 ASSERT (Value != NULL); 1692 Status = BufferToValue (Question, Value); 1693 FreePool (Value); 1694 } 1695 } else { 1696 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId); 1697 ASSERT (FormsetStorage != NULL); 1698 // 1699 // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || 1700 // <ConfigHdr> + "&" + <VariableName> 1701 // 1702 if (IsBufferStorage) { 1703 Length = StrLen (FormsetStorage->ConfigHdr); 1704 Length += StrLen (Question->BlockName); 1705 } else { 1706 Length = StrLen (FormsetStorage->ConfigHdr); 1707 Length += StrLen (Question->VariableName) + 1; 1708 } 1709 // Allocate buffer include '\0' 1710 MaxLen = Length + 1; 1711 ConfigRequest = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 1712 ASSERT (ConfigRequest != NULL); 1713 1714 StrCpyS (ConfigRequest, MaxLen, FormsetStorage->ConfigHdr); 1715 if (IsBufferStorage) { 1716 StrCatS (ConfigRequest, MaxLen, Question->BlockName); 1717 } else { 1718 StrCatS (ConfigRequest, MaxLen, L"&"); 1719 StrCatS (ConfigRequest, MaxLen, Question->VariableName); 1720 } 1721 1722 // 1723 // Request current settings from Configuration Driver 1724 // 1725 Status = mHiiConfigRouting->ExtractConfig ( 1726 mHiiConfigRouting, 1727 ConfigRequest, 1728 &Progress, 1729 &Result 1730 ); 1731 FreePool (ConfigRequest); 1732 if (EFI_ERROR (Status)) { 1733 return Status; 1734 } 1735 1736 // 1737 // Skip <ConfigRequest> 1738 // 1739 if (IsBufferStorage) { 1740 Value = StrStr (Result, L"&VALUE"); 1741 if (Value == NULL) { 1742 FreePool (Result); 1743 return EFI_NOT_FOUND; 1744 } 1745 // 1746 // Skip "&VALUE" 1747 // 1748 Value = Value + 6; 1749 } else { 1750 Value = Result + Length; 1751 } 1752 if (*Value != '=') { 1753 FreePool (Result); 1754 return EFI_NOT_FOUND; 1755 } 1756 // 1757 // Skip '=', point to value 1758 // 1759 Value = Value + 1; 1760 1761 Status = BufferToValue (Question, Value); 1762 if (EFI_ERROR (Status)) { 1763 FreePool (Result); 1764 return Status; 1765 } 1766 1767 // 1768 // Synchronize Edit Buffer 1769 // 1770 if (IsBufferStorage) { 1771 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); 1772 } else { 1773 SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL); 1774 } 1775 1776 if (Result != NULL) { 1777 FreePool (Result); 1778 } 1779 } 1780 1781 return Status; 1782 } 1783 1784 1785 /** 1786 Save Question Value to edit copy(cached) or Storage(uncached). 1787 1788 @param FormSet FormSet data structure. 1789 @param Form Form data structure. 1790 @param Question Pointer to the Question. 1791 @param SetValueTo Update the question value to editbuffer , buffer or hii driver. 1792 1793 @retval EFI_SUCCESS The function completed successfully. 1794 1795 **/ 1796 EFI_STATUS 1797 SetQuestionValue ( 1798 IN FORM_BROWSER_FORMSET *FormSet, 1799 IN FORM_BROWSER_FORM *Form, 1800 IN OUT FORM_BROWSER_STATEMENT *Question, 1801 IN GET_SET_QUESTION_VALUE_WITH SetValueTo 1802 ) 1803 { 1804 EFI_STATUS Status; 1805 BOOLEAN Enabled; 1806 BOOLEAN Pending; 1807 UINT8 *Src; 1808 EFI_TIME EfiTime; 1809 UINTN BufferLen; 1810 UINTN StorageWidth; 1811 BROWSER_STORAGE *Storage; 1812 FORMSET_STORAGE *FormsetStorage; 1813 EFI_IFR_TYPE_VALUE *QuestionValue; 1814 CHAR16 *ConfigResp; 1815 CHAR16 *Progress; 1816 CHAR16 *Value; 1817 UINTN Length; 1818 BOOLEAN IsBufferStorage; 1819 BOOLEAN IsString; 1820 UINT8 *TemBuffer; 1821 CHAR16 *TemName; 1822 CHAR16 *TemString; 1823 UINTN Index; 1824 NAME_VALUE_NODE *Node; 1825 UINTN MaxLen; 1826 1827 Status = EFI_SUCCESS; 1828 Node = NULL; 1829 1830 if (SetValueTo >= GetSetValueWithMax) { 1831 return EFI_INVALID_PARAMETER; 1832 } 1833 1834 // 1835 // If Question value is provided by an Expression, then it is read only 1836 // 1837 if (Question->ValueExpression != NULL) { 1838 return Status; 1839 } 1840 1841 // 1842 // Before set question value, evaluate its write expression. 1843 // 1844 if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) { 1845 Status = EvaluateExpression (FormSet, Form, Question->WriteExpression); 1846 if (EFI_ERROR (Status)) { 1847 return Status; 1848 } 1849 } 1850 1851 // 1852 // Question value is provided by RTC 1853 // 1854 Storage = Question->Storage; 1855 QuestionValue = &Question->HiiValue.Value; 1856 if (Storage == NULL) { 1857 // 1858 // It's a Question without storage, or RTC date/time 1859 // 1860 if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { 1861 // 1862 // Date and time define the same Flags bit 1863 // 1864 switch (Question->Flags & EFI_QF_DATE_STORAGE) { 1865 case QF_DATE_STORAGE_TIME: 1866 Status = gRT->GetTime (&EfiTime, NULL); 1867 break; 1868 1869 case QF_DATE_STORAGE_WAKEUP: 1870 Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); 1871 break; 1872 1873 case QF_DATE_STORAGE_NORMAL: 1874 default: 1875 // 1876 // For date/time without storage 1877 // 1878 return EFI_SUCCESS; 1879 } 1880 1881 if (EFI_ERROR (Status)) { 1882 return Status; 1883 } 1884 1885 if (Question->Operand == EFI_IFR_DATE_OP) { 1886 EfiTime.Year = QuestionValue->date.Year; 1887 EfiTime.Month = QuestionValue->date.Month; 1888 EfiTime.Day = QuestionValue->date.Day; 1889 } else { 1890 EfiTime.Hour = QuestionValue->time.Hour; 1891 EfiTime.Minute = QuestionValue->time.Minute; 1892 EfiTime.Second = QuestionValue->time.Second; 1893 } 1894 1895 if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { 1896 Status = gRT->SetTime (&EfiTime); 1897 } else { 1898 Status = gRT->SetWakeupTime (TRUE, &EfiTime); 1899 } 1900 } 1901 1902 return Status; 1903 } 1904 1905 // 1906 // Question value is provided by EFI variable 1907 // 1908 StorageWidth = Question->StorageWidth; 1909 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 1910 if (Question->BufferValue != NULL) { 1911 Src = Question->BufferValue; 1912 } else { 1913 Src = (UINT8 *) QuestionValue; 1914 } 1915 1916 Status = gRT->SetVariable ( 1917 Question->VariableName, 1918 &Storage->Guid, 1919 Storage->Attributes, 1920 StorageWidth, 1921 Src 1922 ); 1923 return Status; 1924 } 1925 1926 // 1927 // Question Value is provided by Buffer Storage or NameValue Storage 1928 // 1929 if (Question->BufferValue != NULL) { 1930 Src = Question->BufferValue; 1931 } else { 1932 Src = (UINT8 *) &Question->HiiValue.Value; 1933 } 1934 1935 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 1936 Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 1937 IsBufferStorage = TRUE; 1938 } else { 1939 IsBufferStorage = FALSE; 1940 } 1941 IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); 1942 1943 if (SetValueTo == GetSetValueWithEditBuffer || SetValueTo == GetSetValueWithBuffer) { 1944 if (IsBufferStorage) { 1945 if (SetValueTo == GetSetValueWithEditBuffer) { 1946 // 1947 // Copy to storage edit buffer 1948 // 1949 CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); 1950 } else if (SetValueTo == GetSetValueWithBuffer) { 1951 // 1952 // Copy to storage edit buffer 1953 // 1954 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); 1955 } 1956 } else { 1957 if (IsString) { 1958 // 1959 // Allocate enough string buffer. 1960 // 1961 Value = NULL; 1962 BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16); 1963 Value = AllocateZeroPool (BufferLen); 1964 ASSERT (Value != NULL); 1965 // 1966 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" 1967 // 1968 TemName = (CHAR16 *) Src; 1969 TemString = Value; 1970 for (; *TemName != L'\0'; TemName++) { 1971 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4); 1972 } 1973 } else { 1974 BufferLen = StorageWidth * 2 + 1; 1975 Value = AllocateZeroPool (BufferLen * sizeof (CHAR16)); 1976 ASSERT (Value != NULL); 1977 // 1978 // Convert Buffer to Hex String 1979 // 1980 TemBuffer = Src + StorageWidth - 1; 1981 TemString = Value; 1982 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) { 1983 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); 1984 } 1985 } 1986 1987 Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node); 1988 FreePool (Value); 1989 if (EFI_ERROR (Status)) { 1990 return Status; 1991 } 1992 } 1993 } else if (SetValueTo == GetSetValueWithHiiDriver) { 1994 // 1995 // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" || 1996 // <ConfigHdr> + "&" + <VariableName> + "=" + "<string>" 1997 // 1998 if (IsBufferStorage) { 1999 Length = StrLen (Question->BlockName) + 7; 2000 } else { 2001 Length = StrLen (Question->VariableName) + 2; 2002 } 2003 if (!IsBufferStorage && IsString) { 2004 Length += (StrLen ((CHAR16 *) Src) * 4); 2005 } else { 2006 Length += (StorageWidth * 2); 2007 } 2008 FormsetStorage = GetFstStgFromVarId(FormSet, Question->VarStoreId); 2009 ASSERT (FormsetStorage != NULL); 2010 MaxLen = StrLen (FormsetStorage->ConfigHdr) + Length + 1; 2011 ConfigResp = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 2012 ASSERT (ConfigResp != NULL); 2013 2014 StrCpyS (ConfigResp, MaxLen, FormsetStorage->ConfigHdr); 2015 if (IsBufferStorage) { 2016 StrCatS (ConfigResp, MaxLen, Question->BlockName); 2017 StrCatS (ConfigResp, MaxLen, L"&VALUE="); 2018 } else { 2019 StrCatS (ConfigResp, MaxLen, L"&"); 2020 StrCatS (ConfigResp, MaxLen, Question->VariableName); 2021 StrCatS (ConfigResp, MaxLen, L"="); 2022 } 2023 2024 Value = ConfigResp + StrLen (ConfigResp); 2025 2026 if (!IsBufferStorage && IsString) { 2027 // 2028 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" 2029 // 2030 TemName = (CHAR16 *) Src; 2031 TemString = Value; 2032 for (; *TemName != L'\0'; TemName++) { 2033 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4); 2034 } 2035 } else { 2036 // 2037 // Convert Buffer to Hex String 2038 // 2039 TemBuffer = Src + StorageWidth - 1; 2040 TemString = Value; 2041 for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) { 2042 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); 2043 } 2044 } 2045 2046 // 2047 // Convert to lower char. 2048 // 2049 for (TemString = Value; *Value != L'\0'; Value++) { 2050 if (*Value >= L'A' && *Value <= L'Z') { 2051 *Value = (CHAR16) (*Value - L'A' + L'a'); 2052 } 2053 } 2054 2055 // 2056 // Submit Question Value to Configuration Driver 2057 // 2058 Status = mHiiConfigRouting->RouteConfig ( 2059 mHiiConfigRouting, 2060 ConfigResp, 2061 &Progress 2062 ); 2063 if (EFI_ERROR (Status)) { 2064 FreePool (ConfigResp); 2065 return Status; 2066 } 2067 FreePool (ConfigResp); 2068 2069 // 2070 // Sync storage, from editbuffer to buffer. 2071 // 2072 CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); 2073 } 2074 2075 return Status; 2076 } 2077 2078 2079 /** 2080 Perform nosubmitif check for a Form. 2081 2082 @param FormSet FormSet data structure. 2083 @param Form Form data structure. 2084 @param Question The Question to be validated. 2085 @param Type Validation type: NoSubmit 2086 2087 @retval EFI_SUCCESS Form validation pass. 2088 @retval other Form validation failed. 2089 2090 **/ 2091 EFI_STATUS 2092 ValidateQuestion ( 2093 IN FORM_BROWSER_FORMSET *FormSet, 2094 IN FORM_BROWSER_FORM *Form, 2095 IN FORM_BROWSER_STATEMENT *Question, 2096 IN UINTN Type 2097 ) 2098 { 2099 EFI_STATUS Status; 2100 LIST_ENTRY *Link; 2101 LIST_ENTRY *ListHead; 2102 FORM_EXPRESSION *Expression; 2103 UINT32 BrowserStatus; 2104 CHAR16 *ErrorStr; 2105 2106 BrowserStatus = BROWSER_SUCCESS; 2107 ErrorStr = NULL; 2108 2109 switch (Type) { 2110 case EFI_HII_EXPRESSION_INCONSISTENT_IF: 2111 ListHead = &Question->InconsistentListHead; 2112 break; 2113 2114 case EFI_HII_EXPRESSION_WARNING_IF: 2115 ListHead = &Question->WarningListHead; 2116 break; 2117 2118 case EFI_HII_EXPRESSION_NO_SUBMIT_IF: 2119 ListHead = &Question->NoSubmitListHead; 2120 break; 2121 2122 default: 2123 ASSERT (FALSE); 2124 return EFI_UNSUPPORTED; 2125 } 2126 2127 Link = GetFirstNode (ListHead); 2128 while (!IsNull (ListHead, Link)) { 2129 Expression = FORM_EXPRESSION_FROM_LINK (Link); 2130 2131 // 2132 // Evaluate the expression 2133 // 2134 Status = EvaluateExpression (FormSet, Form, Expression); 2135 if (EFI_ERROR (Status)) { 2136 return Status; 2137 } 2138 2139 if (IsTrue (&Expression->Result)) { 2140 switch (Type) { 2141 case EFI_HII_EXPRESSION_INCONSISTENT_IF: 2142 BrowserStatus = BROWSER_INCONSISTENT_IF; 2143 break; 2144 2145 case EFI_HII_EXPRESSION_WARNING_IF: 2146 BrowserStatus = BROWSER_WARNING_IF; 2147 break; 2148 2149 case EFI_HII_EXPRESSION_NO_SUBMIT_IF: 2150 BrowserStatus = BROWSER_NO_SUBMIT_IF; 2151 // 2152 // This code only used to compatible with old display engine, 2153 // New display engine will not use this field. 2154 // 2155 if (Expression->Error != 0) { 2156 ErrorStr = GetToken (Expression->Error, FormSet->HiiHandle); 2157 } 2158 break; 2159 2160 default: 2161 ASSERT (FALSE); 2162 break; 2163 } 2164 2165 if (!((Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) && mSystemSubmit)) { 2166 // 2167 // If in system submit process and for no_submit_if check, not popup this error message. 2168 // Will process this fail again later in not system submit process. 2169 // 2170 PopupErrorMessage(BrowserStatus, FormSet->HiiHandle, Expression->OpCode, ErrorStr); 2171 } 2172 2173 if (ErrorStr != NULL) { 2174 FreePool (ErrorStr); 2175 } 2176 2177 if (Type == EFI_HII_EXPRESSION_WARNING_IF) { 2178 return EFI_SUCCESS; 2179 } else { 2180 return EFI_NOT_READY; 2181 } 2182 } 2183 2184 Link = GetNextNode (ListHead, Link); 2185 } 2186 2187 return EFI_SUCCESS; 2188 } 2189 2190 /** 2191 Perform question check. 2192 2193 If one question has more than one check, process form high priority to low. 2194 Only one error info will be popup. 2195 2196 @param FormSet FormSet data structure. 2197 @param Form Form data structure. 2198 @param Question The Question to be validated. 2199 2200 @retval EFI_SUCCESS Form validation pass. 2201 @retval other Form validation failed. 2202 2203 **/ 2204 EFI_STATUS 2205 ValueChangedValidation ( 2206 IN FORM_BROWSER_FORMSET *FormSet, 2207 IN FORM_BROWSER_FORM *Form, 2208 IN FORM_BROWSER_STATEMENT *Question 2209 ) 2210 { 2211 EFI_STATUS Status; 2212 2213 Status = EFI_SUCCESS; 2214 2215 // 2216 // Do the inconsistentif check. 2217 // 2218 if (!IsListEmpty (&Question->InconsistentListHead)) { 2219 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); 2220 if (EFI_ERROR (Status)) { 2221 return Status; 2222 } 2223 } 2224 2225 // 2226 // Do the warningif check. 2227 // 2228 if (!IsListEmpty (&Question->WarningListHead)) { 2229 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_WARNING_IF); 2230 } 2231 2232 return Status; 2233 } 2234 2235 /** 2236 Perform NoSubmit check for each Form in FormSet. 2237 2238 @param FormSet FormSet data structure. 2239 @param CurrentForm Current input form data structure. 2240 @param Statement The statement for this check. 2241 2242 @retval EFI_SUCCESS Form validation pass. 2243 @retval other Form validation failed. 2244 2245 **/ 2246 EFI_STATUS 2247 NoSubmitCheck ( 2248 IN FORM_BROWSER_FORMSET *FormSet, 2249 IN OUT FORM_BROWSER_FORM **CurrentForm, 2250 OUT FORM_BROWSER_STATEMENT **Statement 2251 ) 2252 { 2253 EFI_STATUS Status; 2254 LIST_ENTRY *Link; 2255 FORM_BROWSER_STATEMENT *Question; 2256 FORM_BROWSER_FORM *Form; 2257 LIST_ENTRY *LinkForm; 2258 2259 LinkForm = GetFirstNode (&FormSet->FormListHead); 2260 while (!IsNull (&FormSet->FormListHead, LinkForm)) { 2261 Form = FORM_BROWSER_FORM_FROM_LINK (LinkForm); 2262 LinkForm = GetNextNode (&FormSet->FormListHead, LinkForm); 2263 2264 if (*CurrentForm != NULL && *CurrentForm != Form) { 2265 continue; 2266 } 2267 2268 Link = GetFirstNode (&Form->StatementListHead); 2269 while (!IsNull (&Form->StatementListHead, Link)) { 2270 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2271 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); 2272 if (EFI_ERROR (Status)) { 2273 if (*CurrentForm == NULL) { 2274 *CurrentForm = Form; 2275 } 2276 if (Statement != NULL) { 2277 *Statement = Question; 2278 } 2279 return Status; 2280 } 2281 2282 Link = GetNextNode (&Form->StatementListHead, Link); 2283 } 2284 } 2285 2286 return EFI_SUCCESS; 2287 } 2288 2289 /** 2290 Fill storage's edit copy with settings requested from Configuration Driver. 2291 2292 @param Storage The storage which need to sync. 2293 @param ConfigRequest The config request string which used to sync storage. 2294 @param SyncOrRestore Sync the buffer to editbuffer or Restore the 2295 editbuffer to buffer 2296 if TRUE, copy the editbuffer to the buffer. 2297 if FALSE, copy the buffer to the editbuffer. 2298 2299 @retval EFI_SUCCESS The function completed successfully. 2300 2301 **/ 2302 EFI_STATUS 2303 SynchronizeStorage ( 2304 OUT BROWSER_STORAGE *Storage, 2305 IN CHAR16 *ConfigRequest, 2306 IN BOOLEAN SyncOrRestore 2307 ) 2308 { 2309 EFI_STATUS Status; 2310 EFI_STRING Progress; 2311 EFI_STRING Result; 2312 UINTN BufferSize; 2313 LIST_ENTRY *Link; 2314 NAME_VALUE_NODE *Node; 2315 UINT8 *Src; 2316 UINT8 *Dst; 2317 2318 Status = EFI_SUCCESS; 2319 Result = NULL; 2320 2321 if (Storage->Type == EFI_HII_VARSTORE_BUFFER || 2322 (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 2323 BufferSize = Storage->Size; 2324 2325 if (SyncOrRestore) { 2326 Src = Storage->EditBuffer; 2327 Dst = Storage->Buffer; 2328 } else { 2329 Src = Storage->Buffer; 2330 Dst = Storage->EditBuffer; 2331 } 2332 2333 if (ConfigRequest != NULL) { 2334 Status = mHiiConfigRouting->BlockToConfig( 2335 mHiiConfigRouting, 2336 ConfigRequest, 2337 Src, 2338 BufferSize, 2339 &Result, 2340 &Progress 2341 ); 2342 if (EFI_ERROR (Status)) { 2343 return Status; 2344 } 2345 2346 Status = mHiiConfigRouting->ConfigToBlock ( 2347 mHiiConfigRouting, 2348 Result, 2349 Dst, 2350 &BufferSize, 2351 &Progress 2352 ); 2353 if (Result != NULL) { 2354 FreePool (Result); 2355 } 2356 } else { 2357 CopyMem (Dst, Src, BufferSize); 2358 } 2359 } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2360 Link = GetFirstNode (&Storage->NameValueListHead); 2361 while (!IsNull (&Storage->NameValueListHead, Link)) { 2362 Node = NAME_VALUE_NODE_FROM_LINK (Link); 2363 2364 if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) || 2365 (ConfigRequest == NULL)) { 2366 if (SyncOrRestore) { 2367 NewStringCpy (&Node->Value, Node->EditValue); 2368 } else { 2369 NewStringCpy (&Node->EditValue, Node->Value); 2370 } 2371 } 2372 2373 Link = GetNextNode (&Storage->NameValueListHead, Link); 2374 } 2375 } 2376 2377 return Status; 2378 } 2379 2380 /** 2381 When discard the question value, call the callback function with Changed type 2382 to inform the hii driver. 2383 2384 @param FormSet FormSet data structure. 2385 @param Form Form data structure. 2386 2387 **/ 2388 VOID 2389 SendDiscardInfoToDriver ( 2390 IN FORM_BROWSER_FORMSET *FormSet, 2391 IN FORM_BROWSER_FORM *Form 2392 ) 2393 { 2394 LIST_ENTRY *Link; 2395 FORM_BROWSER_STATEMENT *Question; 2396 EFI_IFR_TYPE_VALUE *TypeValue; 2397 EFI_BROWSER_ACTION_REQUEST ActionRequest; 2398 2399 if (FormSet->ConfigAccess == NULL) { 2400 return; 2401 } 2402 2403 Link = GetFirstNode (&Form->StatementListHead); 2404 while (!IsNull (&Form->StatementListHead, Link)) { 2405 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2406 Link = GetNextNode (&Form->StatementListHead, Link); 2407 2408 if (Question->Storage == NULL || Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 2409 continue; 2410 } 2411 2412 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) { 2413 continue; 2414 } 2415 2416 if (Question->Operand == EFI_IFR_PASSWORD_OP) { 2417 continue; 2418 } 2419 2420 if (!Question->ValueChanged) { 2421 continue; 2422 } 2423 2424 // 2425 // Restore the question value before call the CHANGED callback type. 2426 // 2427 GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 2428 2429 if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) { 2430 TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue; 2431 } else { 2432 TypeValue = &Question->HiiValue.Value; 2433 } 2434 2435 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 2436 FormSet->ConfigAccess->Callback ( 2437 FormSet->ConfigAccess, 2438 EFI_BROWSER_ACTION_CHANGED, 2439 Question->QuestionId, 2440 Question->HiiValue.Type, 2441 TypeValue, 2442 &ActionRequest 2443 ); 2444 } 2445 } 2446 2447 /** 2448 Validate the HiiHandle. 2449 2450 @param HiiHandle The input HiiHandle which need to validate. 2451 2452 @retval TRUE The handle is validate. 2453 @retval FALSE The handle is invalidate. 2454 2455 **/ 2456 BOOLEAN 2457 ValidateHiiHandle ( 2458 EFI_HII_HANDLE HiiHandle 2459 ) 2460 { 2461 EFI_HII_HANDLE *HiiHandles; 2462 UINTN Index; 2463 BOOLEAN Find; 2464 2465 if (HiiHandle == NULL) { 2466 return FALSE; 2467 } 2468 2469 Find = FALSE; 2470 2471 HiiHandles = HiiGetHiiHandles (NULL); 2472 ASSERT (HiiHandles != NULL); 2473 2474 for (Index = 0; HiiHandles[Index] != NULL; Index++) { 2475 if (HiiHandles[Index] == HiiHandle) { 2476 Find = TRUE; 2477 break; 2478 } 2479 } 2480 2481 FreePool (HiiHandles); 2482 2483 return Find; 2484 } 2485 2486 /** 2487 Validate the FormSet. If the formset is not validate, remove it from the list. 2488 2489 @param FormSet The input FormSet which need to validate. 2490 2491 @retval TRUE The handle is validate. 2492 @retval FALSE The handle is invalidate. 2493 2494 **/ 2495 BOOLEAN 2496 ValidateFormSet ( 2497 FORM_BROWSER_FORMSET *FormSet 2498 ) 2499 { 2500 BOOLEAN Find; 2501 2502 ASSERT (FormSet != NULL); 2503 2504 Find = ValidateHiiHandle(FormSet->HiiHandle); 2505 // 2506 // Should not remove the formset which is being used. 2507 // 2508 if (!Find && (FormSet != gCurrentSelection->FormSet)) { 2509 CleanBrowserStorage(FormSet); 2510 RemoveEntryList (&FormSet->Link); 2511 DestroyFormSet (FormSet); 2512 } 2513 2514 return Find; 2515 } 2516 /** 2517 Check whether need to enable the reset flag in form level. 2518 Also clean all ValueChanged flag in question. 2519 2520 @param SetFlag Whether need to set the Reset Flag. 2521 @param FormSet FormSet data structure. 2522 @param Form Form data structure. 2523 2524 **/ 2525 VOID 2526 UpdateFlagForForm ( 2527 IN BOOLEAN SetFlag, 2528 IN FORM_BROWSER_FORMSET *FormSet, 2529 IN FORM_BROWSER_FORM *Form 2530 ) 2531 { 2532 LIST_ENTRY *Link; 2533 FORM_BROWSER_STATEMENT *Question; 2534 BOOLEAN OldValue; 2535 2536 Link = GetFirstNode (&Form->StatementListHead); 2537 while (!IsNull (&Form->StatementListHead, Link)) { 2538 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 2539 Link = GetNextNode (&Form->StatementListHead, Link); 2540 2541 if (!Question->ValueChanged) { 2542 continue; 2543 } 2544 2545 OldValue = Question->ValueChanged; 2546 2547 // 2548 // Compare the buffer and editbuffer data to see whether the data has been saved. 2549 // 2550 Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBothBuffer); 2551 2552 // 2553 // Only the changed data has been saved, then need to set the reset flag. 2554 // 2555 if (SetFlag && OldValue && !Question->ValueChanged) { 2556 if ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) { 2557 gResetRequired = TRUE; 2558 } 2559 2560 if ((Question->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) { 2561 gFlagReconnect = TRUE; 2562 } 2563 } 2564 } 2565 } 2566 2567 /** 2568 Check whether need to enable the reset flag. 2569 Also clean ValueChanged flag for all statements. 2570 2571 Form level or formset level, only one. 2572 2573 @param SetFlag Whether need to set the Reset Flag. 2574 @param FormSet FormSet data structure. 2575 @param Form Form data structure. 2576 2577 **/ 2578 VOID 2579 ValueChangeResetFlagUpdate ( 2580 IN BOOLEAN SetFlag, 2581 IN FORM_BROWSER_FORMSET *FormSet, 2582 IN FORM_BROWSER_FORM *Form 2583 ) 2584 { 2585 FORM_BROWSER_FORM *CurrentForm; 2586 LIST_ENTRY *Link; 2587 2588 if (Form != NULL) { 2589 UpdateFlagForForm(SetFlag, FormSet, Form); 2590 return; 2591 } 2592 2593 Link = GetFirstNode (&FormSet->FormListHead); 2594 while (!IsNull (&FormSet->FormListHead, Link)) { 2595 CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link); 2596 Link = GetNextNode (&FormSet->FormListHead, Link); 2597 2598 UpdateFlagForForm(SetFlag, FormSet, CurrentForm); 2599 } 2600 } 2601 2602 /** 2603 Base on the return Progress string to find the form. 2604 2605 Base on the first return Offset/Width (Name) string to find the form 2606 which keep this string. 2607 2608 @param FormSet FormSet data structure. 2609 @param Storage Storage which has this Progress string. 2610 @param Progress The Progress string which has the first fail string. 2611 @param RetForm The return form for this progress string. 2612 @param RetQuestion The return question for the error progress string. 2613 2614 @retval TRUE Find the error form and statement for this error progress string. 2615 @retval FALSE Not find the error form. 2616 2617 **/ 2618 BOOLEAN 2619 FindQuestionFromProgress ( 2620 IN FORM_BROWSER_FORMSET *FormSet, 2621 IN BROWSER_STORAGE *Storage, 2622 IN EFI_STRING Progress, 2623 OUT FORM_BROWSER_FORM **RetForm, 2624 OUT FORM_BROWSER_STATEMENT **RetQuestion 2625 ) 2626 { 2627 LIST_ENTRY *Link; 2628 LIST_ENTRY *LinkStorage; 2629 LIST_ENTRY *LinkStatement; 2630 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 2631 FORM_BROWSER_FORM *Form; 2632 EFI_STRING EndStr; 2633 FORM_BROWSER_STATEMENT *Statement; 2634 2635 ASSERT ((*Progress == '&') || (*Progress == 'G')); 2636 2637 ConfigInfo = NULL; 2638 *RetForm = NULL; 2639 *RetQuestion = NULL; 2640 2641 // 2642 // Skip the first "&" or the ConfigHdr part. 2643 // 2644 if (*Progress == '&') { 2645 Progress++; 2646 } else { 2647 // 2648 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. 2649 // 2650 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2651 // 2652 // For Name/Value type, Skip the ConfigHdr part. 2653 // 2654 EndStr = StrStr (Progress, L"PATH="); 2655 ASSERT (EndStr != NULL); 2656 while (*EndStr != '&') { 2657 EndStr++; 2658 } 2659 2660 *EndStr = '\0'; 2661 } else { 2662 // 2663 // For Buffer type, Skip the ConfigHdr part. 2664 // 2665 EndStr = StrStr (Progress, L"&OFFSET="); 2666 ASSERT (EndStr != NULL); 2667 *EndStr = '\0'; 2668 } 2669 2670 Progress = EndStr + 1; 2671 } 2672 2673 // 2674 // Prepare the "NAME" or "OFFSET=0x####&WIDTH=0x####" string. 2675 // 2676 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2677 // 2678 // For Name/Value type, the data is "&Fred=16&George=16&Ron=12" formset, 2679 // here, just keep the "Fred" string. 2680 // 2681 EndStr = StrStr (Progress, L"="); 2682 ASSERT (EndStr != NULL); 2683 *EndStr = '\0'; 2684 } else { 2685 // 2686 // For Buffer type, the data is "OFFSET=0x####&WIDTH=0x####&VALUE=0x####", 2687 // here, just keep the "OFFSET=0x####&WIDTH=0x####" string. 2688 // 2689 EndStr = StrStr (Progress, L"&VALUE="); 2690 ASSERT (EndStr != NULL); 2691 *EndStr = '\0'; 2692 } 2693 2694 // 2695 // Search in the form list. 2696 // 2697 Link = GetFirstNode (&FormSet->FormListHead); 2698 while (!IsNull (&FormSet->FormListHead, Link)) { 2699 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 2700 Link = GetNextNode (&FormSet->FormListHead, Link); 2701 2702 // 2703 // Search in the ConfigReqeust list in this form. 2704 // 2705 LinkStorage = GetFirstNode (&Form->ConfigRequestHead); 2706 while (!IsNull (&Form->ConfigRequestHead, LinkStorage)) { 2707 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (LinkStorage); 2708 LinkStorage = GetNextNode (&Form->ConfigRequestHead, LinkStorage); 2709 2710 if (Storage != ConfigInfo->Storage) { 2711 continue; 2712 } 2713 2714 if (StrStr (ConfigInfo->ConfigRequest, Progress) != NULL) { 2715 // 2716 // Find the OffsetWidth string in this form. 2717 // 2718 *RetForm = Form; 2719 break; 2720 } 2721 } 2722 2723 if (*RetForm != NULL) { 2724 LinkStatement = GetFirstNode (&Form->StatementListHead); 2725 while (!IsNull (&Form->StatementListHead, LinkStatement)) { 2726 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (LinkStatement); 2727 LinkStatement = GetNextNode (&Form->StatementListHead, LinkStatement); 2728 2729 if (Statement->BlockName != NULL && StrStr (Statement->BlockName, Progress) != NULL) { 2730 *RetQuestion = Statement; 2731 break; 2732 } 2733 2734 if (Statement->VariableName != NULL && StrStr (Statement->VariableName, Progress) != NULL) { 2735 *RetQuestion = Statement; 2736 break; 2737 } 2738 } 2739 } 2740 2741 if (*RetForm != NULL) { 2742 break; 2743 } 2744 } 2745 2746 // 2747 // restore the OffsetWidth string to the original format. 2748 // 2749 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 2750 *EndStr = '='; 2751 } else { 2752 *EndStr = '&'; 2753 } 2754 2755 return (BOOLEAN) (*RetForm != NULL); 2756 } 2757 2758 /** 2759 Popup an save error info and get user input. 2760 2761 @param TitleId The form title id. 2762 @param HiiHandle The hii handle for this package. 2763 2764 @retval UINT32 The user select option for the save fail. 2765 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET 2766 **/ 2767 UINT32 2768 ConfirmSaveFail ( 2769 IN EFI_STRING_ID TitleId, 2770 IN EFI_HII_HANDLE HiiHandle 2771 ) 2772 { 2773 CHAR16 *FormTitle; 2774 CHAR16 *StringBuffer; 2775 UINT32 RetVal; 2776 2777 FormTitle = GetToken (TitleId, HiiHandle); 2778 2779 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); 2780 ASSERT (StringBuffer != NULL); 2781 2782 UnicodeSPrint ( 2783 StringBuffer, 2784 24 * sizeof (CHAR16) + StrSize (FormTitle), 2785 L"Submit Fail For Form: %s.", 2786 FormTitle 2787 ); 2788 2789 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL, NULL, NULL, StringBuffer); 2790 2791 FreePool (StringBuffer); 2792 FreePool (FormTitle); 2793 2794 return RetVal; 2795 } 2796 2797 /** 2798 Popup an NO_SUBMIT_IF error info and get user input. 2799 2800 @param TitleId The form title id. 2801 @param HiiHandle The hii handle for this package. 2802 2803 @retval UINT32 The user select option for the save fail. 2804 BROWSER_ACTION_DISCARD or BROWSER_ACTION_JUMP_TO_FORMSET 2805 **/ 2806 UINT32 2807 ConfirmNoSubmitFail ( 2808 IN EFI_STRING_ID TitleId, 2809 IN EFI_HII_HANDLE HiiHandle 2810 ) 2811 { 2812 CHAR16 *FormTitle; 2813 CHAR16 *StringBuffer; 2814 UINT32 RetVal; 2815 2816 FormTitle = GetToken (TitleId, HiiHandle); 2817 2818 StringBuffer = AllocateZeroPool (256 * sizeof (CHAR16)); 2819 ASSERT (StringBuffer != NULL); 2820 2821 UnicodeSPrint ( 2822 StringBuffer, 2823 24 * sizeof (CHAR16) + StrSize (FormTitle), 2824 L"NO_SUBMIT_IF error For Form: %s.", 2825 FormTitle 2826 ); 2827 2828 RetVal = PopupErrorMessage(BROWSER_SUBMIT_FAIL_NO_SUBMIT_IF, NULL, NULL, StringBuffer); 2829 2830 FreePool (StringBuffer); 2831 FreePool (FormTitle); 2832 2833 return RetVal; 2834 } 2835 2836 /** 2837 Discard data based on the input setting scope (Form, FormSet or System). 2838 2839 @param FormSet FormSet data structure. 2840 @param Form Form data structure. 2841 @param SettingScope Setting Scope for Discard action. 2842 2843 @retval EFI_SUCCESS The function completed successfully. 2844 @retval EFI_UNSUPPORTED Unsupport SettingScope. 2845 2846 **/ 2847 EFI_STATUS 2848 DiscardForm ( 2849 IN FORM_BROWSER_FORMSET *FormSet, 2850 IN FORM_BROWSER_FORM *Form, 2851 IN BROWSER_SETTING_SCOPE SettingScope 2852 ) 2853 { 2854 LIST_ENTRY *Link; 2855 FORMSET_STORAGE *Storage; 2856 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 2857 FORM_BROWSER_FORMSET *LocalFormSet; 2858 FORM_BROWSER_FORMSET *OldFormSet; 2859 2860 // 2861 // Check the supported setting level. 2862 // 2863 if (SettingScope >= MaxLevel) { 2864 return EFI_UNSUPPORTED; 2865 } 2866 2867 if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) { 2868 ConfigInfo = NULL; 2869 Link = GetFirstNode (&Form->ConfigRequestHead); 2870 while (!IsNull (&Form->ConfigRequestHead, Link)) { 2871 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 2872 Link = GetNextNode (&Form->ConfigRequestHead, Link); 2873 2874 if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 2875 continue; 2876 } 2877 2878 // 2879 // Skip if there is no RequestElement 2880 // 2881 if (ConfigInfo->ElementCount == 0) { 2882 continue; 2883 } 2884 2885 // 2886 // Prepare <ConfigResp> 2887 // 2888 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); 2889 2890 // 2891 // Call callback with Changed type to inform the driver. 2892 // 2893 SendDiscardInfoToDriver (FormSet, Form); 2894 } 2895 2896 ValueChangeResetFlagUpdate (FALSE, FormSet, Form); 2897 } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) { 2898 2899 // 2900 // Discard Buffer storage or Name/Value storage 2901 // 2902 Link = GetFirstNode (&FormSet->StorageListHead); 2903 while (!IsNull (&FormSet->StorageListHead, Link)) { 2904 Storage = FORMSET_STORAGE_FROM_LINK (Link); 2905 Link = GetNextNode (&FormSet->StorageListHead, Link); 2906 2907 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 2908 continue; 2909 } 2910 2911 // 2912 // Skip if there is no RequestElement 2913 // 2914 if (Storage->ElementCount == 0) { 2915 continue; 2916 } 2917 2918 SynchronizeStorage(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); 2919 } 2920 2921 Link = GetFirstNode (&FormSet->FormListHead); 2922 while (!IsNull (&FormSet->FormListHead, Link)) { 2923 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 2924 Link = GetNextNode (&FormSet->FormListHead, Link); 2925 2926 // 2927 // Call callback with Changed type to inform the driver. 2928 // 2929 SendDiscardInfoToDriver (FormSet, Form); 2930 } 2931 2932 ValueChangeResetFlagUpdate(FALSE, FormSet, NULL); 2933 } else if (SettingScope == SystemLevel) { 2934 // 2935 // System Level Discard. 2936 // 2937 OldFormSet = mSystemLevelFormSet; 2938 2939 // 2940 // Discard changed value for each FormSet in the maintain list. 2941 // 2942 Link = GetFirstNode (&gBrowserFormSetList); 2943 while (!IsNull (&gBrowserFormSetList, Link)) { 2944 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 2945 Link = GetNextNode (&gBrowserFormSetList, Link); 2946 if (!ValidateFormSet(LocalFormSet)) { 2947 continue; 2948 } 2949 2950 mSystemLevelFormSet = LocalFormSet; 2951 2952 DiscardForm (LocalFormSet, NULL, FormSetLevel); 2953 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { 2954 // 2955 // Remove maintain backup list after discard except for the current using FormSet. 2956 // 2957 CleanBrowserStorage(LocalFormSet); 2958 RemoveEntryList (&LocalFormSet->Link); 2959 DestroyFormSet (LocalFormSet); 2960 } 2961 } 2962 2963 mSystemLevelFormSet = OldFormSet; 2964 } 2965 2966 return EFI_SUCCESS; 2967 } 2968 2969 /** 2970 Submit data for a form. 2971 2972 @param FormSet FormSet data structure. 2973 @param Form Form data structure. 2974 2975 @retval EFI_SUCCESS The function completed successfully. 2976 @retval EFI_UNSUPPORTED Unsupport SettingScope. 2977 2978 **/ 2979 EFI_STATUS 2980 SubmitForForm ( 2981 IN FORM_BROWSER_FORMSET *FormSet, 2982 IN FORM_BROWSER_FORM *Form 2983 ) 2984 { 2985 EFI_STATUS Status; 2986 LIST_ENTRY *Link; 2987 EFI_STRING ConfigResp; 2988 EFI_STRING Progress; 2989 BROWSER_STORAGE *Storage; 2990 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 2991 2992 if (!IsNvUpdateRequiredForForm (Form)) { 2993 return EFI_SUCCESS; 2994 } 2995 2996 Status = NoSubmitCheck (FormSet, &Form, NULL); 2997 if (EFI_ERROR (Status)) { 2998 return Status; 2999 } 3000 3001 Link = GetFirstNode (&Form->ConfigRequestHead); 3002 while (!IsNull (&Form->ConfigRequestHead, Link)) { 3003 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 3004 Link = GetNextNode (&Form->ConfigRequestHead, Link); 3005 3006 Storage = ConfigInfo->Storage; 3007 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 3008 continue; 3009 } 3010 3011 // 3012 // Skip if there is no RequestElement 3013 // 3014 if (ConfigInfo->ElementCount == 0) { 3015 continue; 3016 } 3017 3018 // 3019 // 1. Prepare <ConfigResp> 3020 // 3021 Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE); 3022 if (EFI_ERROR (Status)) { 3023 return Status; 3024 } 3025 3026 // 3027 // 2. Set value to hii config routine protocol. 3028 // 3029 Status = mHiiConfigRouting->RouteConfig ( 3030 mHiiConfigRouting, 3031 ConfigResp, 3032 &Progress 3033 ); 3034 FreePool (ConfigResp); 3035 3036 if (EFI_ERROR (Status)) { 3037 InsertTailList (&gBrowserSaveFailFormSetList, &ConfigInfo->SaveFailLink); 3038 continue; 3039 } 3040 3041 // 3042 // 3. Config success, update storage shadow Buffer, only update the data belong to this form. 3043 // 3044 SynchronizeStorage (ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE); 3045 } 3046 3047 // 3048 // 4. Process the save failed storage. 3049 // 3050 if (!IsListEmpty (&gBrowserSaveFailFormSetList)) { 3051 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { 3052 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3053 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { 3054 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); 3055 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); 3056 3057 SynchronizeStorage(ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE); 3058 3059 Status = EFI_SUCCESS; 3060 } 3061 } else { 3062 Status = EFI_UNSUPPORTED; 3063 } 3064 3065 // 3066 // Free Form save fail list. 3067 // 3068 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { 3069 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3070 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_SAVE_FAIL_LINK (Link); 3071 RemoveEntryList (&ConfigInfo->SaveFailLink); 3072 } 3073 } 3074 3075 // 3076 // 5. Update the NV flag. 3077 // 3078 ValueChangeResetFlagUpdate(TRUE, FormSet, Form); 3079 3080 return Status; 3081 } 3082 3083 /** 3084 Submit data for a formset. 3085 3086 @param FormSet FormSet data structure. 3087 @param SkipProcessFail Whether skip to process the save failed storage. 3088 If submit formset is called when do system level save, 3089 set this value to true and process the failed formset 3090 together. 3091 if submit formset is called when do formset level save, 3092 set the value to false and process the failed storage 3093 right after process all storages for this formset. 3094 3095 @retval EFI_SUCCESS The function completed successfully. 3096 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3097 3098 **/ 3099 EFI_STATUS 3100 SubmitForFormSet ( 3101 IN FORM_BROWSER_FORMSET *FormSet, 3102 IN BOOLEAN SkipProcessFail 3103 ) 3104 { 3105 EFI_STATUS Status; 3106 LIST_ENTRY *Link; 3107 EFI_STRING ConfigResp; 3108 EFI_STRING Progress; 3109 BROWSER_STORAGE *Storage; 3110 FORMSET_STORAGE *FormSetStorage; 3111 FORM_BROWSER_FORM *Form; 3112 BOOLEAN HasInserted; 3113 FORM_BROWSER_STATEMENT *Question; 3114 3115 HasInserted = FALSE; 3116 3117 if (!IsNvUpdateRequiredForFormSet (FormSet)) { 3118 return EFI_SUCCESS; 3119 } 3120 3121 Form = NULL; 3122 Status = NoSubmitCheck (FormSet, &Form, &Question); 3123 if (EFI_ERROR (Status)) { 3124 if (SkipProcessFail) { 3125 // 3126 // Process NO_SUBMIT check first, so insert it at head. 3127 // 3128 FormSet->SaveFailForm = Form; 3129 FormSet->SaveFailStatement = Question; 3130 InsertHeadList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); 3131 } 3132 3133 return Status; 3134 } 3135 3136 Form = NULL; 3137 Question = NULL; 3138 // 3139 // Submit Buffer storage or Name/Value storage 3140 // 3141 Link = GetFirstNode (&FormSet->StorageListHead); 3142 while (!IsNull (&FormSet->StorageListHead, Link)) { 3143 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 3144 Storage = FormSetStorage->BrowserStorage; 3145 Link = GetNextNode (&FormSet->StorageListHead, Link); 3146 3147 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 3148 continue; 3149 } 3150 3151 // 3152 // Skip if there is no RequestElement 3153 // 3154 if (FormSetStorage->ElementCount == 0) { 3155 continue; 3156 } 3157 3158 // 3159 // 1. Prepare <ConfigResp> 3160 // 3161 Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE); 3162 if (EFI_ERROR (Status)) { 3163 return Status; 3164 } 3165 3166 // 3167 // 2. Send <ConfigResp> to Routine config Protocol. 3168 // 3169 Status = mHiiConfigRouting->RouteConfig ( 3170 mHiiConfigRouting, 3171 ConfigResp, 3172 &Progress 3173 ); 3174 if (EFI_ERROR (Status)) { 3175 InsertTailList (&FormSet->SaveFailStorageListHead, &FormSetStorage->SaveFailLink); 3176 if (!HasInserted) { 3177 // 3178 // Call submit formset for system level, save the formset info 3179 // and process later. 3180 // 3181 FindQuestionFromProgress(FormSet, Storage, Progress, &Form, &Question); 3182 ASSERT (Form != NULL && Question != NULL); 3183 FormSet->SaveFailForm = Form; 3184 FormSet->SaveFailStatement = Question; 3185 if (SkipProcessFail) { 3186 InsertTailList (&gBrowserSaveFailFormSetList, &FormSet->SaveFailLink); 3187 } 3188 HasInserted = TRUE; 3189 } 3190 3191 FreePool (ConfigResp); 3192 continue; 3193 } 3194 3195 FreePool (ConfigResp); 3196 // 3197 // 3. Config success, update storage shadow Buffer 3198 // 3199 SynchronizeStorage (Storage, FormSetStorage->ConfigRequest, TRUE); 3200 } 3201 3202 // 3203 // 4. Has save fail storage need to handle. 3204 // 3205 if (Form != NULL) { 3206 if (!SkipProcessFail) { 3207 // 3208 // If not in system level, just handl the save failed storage here. 3209 // 3210 if (ConfirmSaveFail (Form->FormTitle, FormSet->HiiHandle) == BROWSER_ACTION_DISCARD) { 3211 Link = GetFirstNode (&FormSet->SaveFailStorageListHead); 3212 while (!IsNull (&FormSet->SaveFailStorageListHead, Link)) { 3213 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); 3214 Storage = FormSetStorage->BrowserStorage; 3215 Link = GetNextNode (&FormSet->SaveFailStorageListHead, Link); 3216 3217 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); 3218 3219 Status = EFI_SUCCESS; 3220 } 3221 } else { 3222 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); 3223 3224 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; 3225 gCurrentSelection->Handle = FormSet->HiiHandle; 3226 CopyGuid (&gCurrentSelection->FormSetGuid, &FormSet->Guid); 3227 gCurrentSelection->FormId = Form->FormId; 3228 gCurrentSelection->QuestionId = Question->QuestionId; 3229 3230 Status = EFI_UNSUPPORTED; 3231 } 3232 3233 // 3234 // Free FormSet save fail list. 3235 // 3236 while (!IsListEmpty (&FormSet->SaveFailStorageListHead)) { 3237 Link = GetFirstNode (&FormSet->SaveFailStorageListHead); 3238 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (Link); 3239 RemoveEntryList (&FormSetStorage->SaveFailLink); 3240 } 3241 } else { 3242 // 3243 // If in system level, just return error and handle the failed formset later. 3244 // 3245 Status = EFI_UNSUPPORTED; 3246 } 3247 } 3248 3249 // 3250 // 5. Update the NV flag. 3251 // 3252 ValueChangeResetFlagUpdate(TRUE, FormSet, NULL); 3253 3254 return Status; 3255 } 3256 3257 /** 3258 Submit data for all formsets. 3259 3260 @retval EFI_SUCCESS The function completed successfully. 3261 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3262 3263 **/ 3264 EFI_STATUS 3265 SubmitForSystem ( 3266 VOID 3267 ) 3268 { 3269 EFI_STATUS Status; 3270 LIST_ENTRY *Link; 3271 LIST_ENTRY *StorageLink; 3272 FORMSET_STORAGE *FormSetStorage; 3273 FORM_BROWSER_FORM *Form; 3274 FORM_BROWSER_FORMSET *LocalFormSet; 3275 UINT32 UserSelection; 3276 FORM_BROWSER_STATEMENT *Question; 3277 3278 mSystemSubmit = TRUE; 3279 Link = GetFirstNode (&gBrowserFormSetList); 3280 while (!IsNull (&gBrowserFormSetList, Link)) { 3281 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 3282 Link = GetNextNode (&gBrowserFormSetList, Link); 3283 if (!ValidateFormSet(LocalFormSet)) { 3284 continue; 3285 } 3286 3287 Status = SubmitForFormSet (LocalFormSet, TRUE); 3288 if (EFI_ERROR (Status)) { 3289 continue; 3290 } 3291 3292 // 3293 // Remove maintain backup list after save except for the current using FormSet. 3294 // 3295 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { 3296 CleanBrowserStorage(LocalFormSet); 3297 RemoveEntryList (&LocalFormSet->Link); 3298 DestroyFormSet (LocalFormSet); 3299 } 3300 } 3301 mSystemSubmit = FALSE; 3302 3303 Status = EFI_SUCCESS; 3304 3305 // 3306 // Process the save failed formsets. 3307 // 3308 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3309 while (!IsNull (&gBrowserSaveFailFormSetList, Link)) { 3310 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); 3311 Link = GetNextNode (&gBrowserSaveFailFormSetList, Link); 3312 3313 if (!ValidateFormSet(LocalFormSet)) { 3314 continue; 3315 } 3316 3317 Form = LocalFormSet->SaveFailForm; 3318 Question= LocalFormSet->SaveFailStatement; 3319 3320 // 3321 // Confirm with user, get user input. 3322 // 3323 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3324 // 3325 // NULL for SaveFailStorageListHead means error caused by NO_SUBMIT_IF check. 3326 // 3327 UserSelection = ConfirmNoSubmitFail (Form->FormTitle, LocalFormSet->HiiHandle); 3328 } else { 3329 UserSelection = ConfirmSaveFail (Form->FormTitle, LocalFormSet->HiiHandle); 3330 } 3331 3332 if (UserSelection == BROWSER_ACTION_DISCARD) { 3333 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3334 StorageLink = GetFirstNode (&LocalFormSet->StorageListHead); 3335 while (!IsNull (&LocalFormSet->StorageListHead, StorageLink)) { 3336 FormSetStorage = FORMSET_STORAGE_FROM_LINK (StorageLink); 3337 StorageLink = GetNextNode (&LocalFormSet->StorageListHead, StorageLink); 3338 3339 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); 3340 } 3341 } else { 3342 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); 3343 while (!IsNull (&LocalFormSet->SaveFailStorageListHead, StorageLink)) { 3344 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); 3345 StorageLink = GetNextNode (&LocalFormSet->SaveFailStorageListHead, StorageLink); 3346 3347 SynchronizeStorage(FormSetStorage->BrowserStorage, FormSetStorage->ConfigRequest, FALSE); 3348 } 3349 } 3350 3351 if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { 3352 CleanBrowserStorage(LocalFormSet); 3353 RemoveEntryList (&LocalFormSet->Link); 3354 RemoveEntryList (&LocalFormSet->SaveFailLink); 3355 DestroyFormSet (LocalFormSet); 3356 } else { 3357 ValueChangeResetFlagUpdate(FALSE, LocalFormSet, NULL); 3358 } 3359 } else { 3360 if (IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3361 NoSubmitCheck (LocalFormSet, &Form, &Question); 3362 } 3363 3364 UiCopyMenuList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &Form->FormViewListHead); 3365 3366 gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET; 3367 gCurrentSelection->Handle = LocalFormSet->HiiHandle; 3368 CopyGuid (&gCurrentSelection->FormSetGuid, &LocalFormSet->Guid); 3369 gCurrentSelection->FormId = Form->FormId; 3370 gCurrentSelection->QuestionId = Question->QuestionId; 3371 3372 Status = EFI_UNSUPPORTED; 3373 break; 3374 } 3375 } 3376 3377 // 3378 // Clean the list which will not process. 3379 // 3380 while (!IsListEmpty (&gBrowserSaveFailFormSetList)) { 3381 Link = GetFirstNode (&gBrowserSaveFailFormSetList); 3382 LocalFormSet = FORM_BROWSER_FORMSET_FROM_SAVE_FAIL_LINK (Link); 3383 RemoveEntryList (&LocalFormSet->SaveFailLink); 3384 3385 while (!IsListEmpty (&LocalFormSet->SaveFailStorageListHead)) { 3386 StorageLink = GetFirstNode (&LocalFormSet->SaveFailStorageListHead); 3387 FormSetStorage = FORMSET_STORAGE_FROM_SAVE_FAIL_LINK (StorageLink); 3388 RemoveEntryList (&FormSetStorage->SaveFailLink); 3389 } 3390 } 3391 3392 return Status; 3393 } 3394 3395 /** 3396 Submit data based on the input Setting level (Form, FormSet or System). 3397 3398 @param FormSet FormSet data structure. 3399 @param Form Form data structure. 3400 @param SettingScope Setting Scope for Submit action. 3401 3402 @retval EFI_SUCCESS The function completed successfully. 3403 @retval EFI_UNSUPPORTED Unsupport SettingScope. 3404 3405 **/ 3406 EFI_STATUS 3407 SubmitForm ( 3408 IN FORM_BROWSER_FORMSET *FormSet, 3409 IN FORM_BROWSER_FORM *Form, 3410 IN BROWSER_SETTING_SCOPE SettingScope 3411 ) 3412 { 3413 EFI_STATUS Status; 3414 3415 switch (SettingScope) { 3416 case FormLevel: 3417 Status = SubmitForForm(FormSet, Form); 3418 break; 3419 3420 case FormSetLevel: 3421 Status = SubmitForFormSet (FormSet, FALSE); 3422 break; 3423 3424 case SystemLevel: 3425 Status = SubmitForSystem (); 3426 break; 3427 3428 default: 3429 Status = EFI_UNSUPPORTED; 3430 break; 3431 } 3432 3433 return Status; 3434 } 3435 3436 /** 3437 Converts the unicode character of the string from uppercase to lowercase. 3438 This is a internal function. 3439 3440 @param ConfigString String to be converted 3441 3442 **/ 3443 VOID 3444 EFIAPI 3445 HiiToLower ( 3446 IN EFI_STRING ConfigString 3447 ) 3448 { 3449 EFI_STRING String; 3450 BOOLEAN Lower; 3451 3452 ASSERT (ConfigString != NULL); 3453 3454 // 3455 // Convert all hex digits in range [A-F] in the configuration header to [a-f] 3456 // 3457 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { 3458 if (*String == L'=') { 3459 Lower = TRUE; 3460 } else if (*String == L'&') { 3461 Lower = FALSE; 3462 } else if (Lower && *String >= L'A' && *String <= L'F') { 3463 *String = (CHAR16) (*String - L'A' + L'a'); 3464 } 3465 } 3466 } 3467 3468 /** 3469 Find the point in the ConfigResp string for this question. 3470 3471 @param Question The question. 3472 @param ConfigResp Get ConfigResp string. 3473 3474 @retval point to the offset where is for this question. 3475 3476 **/ 3477 CHAR16 * 3478 GetOffsetFromConfigResp ( 3479 IN FORM_BROWSER_STATEMENT *Question, 3480 IN CHAR16 *ConfigResp 3481 ) 3482 { 3483 CHAR16 *RequestElement; 3484 CHAR16 *BlockData; 3485 3486 // 3487 // Type is EFI_HII_VARSTORE_NAME_VALUE. 3488 // 3489 if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 3490 RequestElement = StrStr (ConfigResp, Question->VariableName); 3491 if (RequestElement != NULL) { 3492 // 3493 // Skip the "VariableName=" field. 3494 // 3495 RequestElement += StrLen (Question->VariableName) + 1; 3496 } 3497 3498 return RequestElement; 3499 } 3500 3501 // 3502 // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3503 // 3504 3505 // 3506 // 1. Directly use Question->BlockName to find. 3507 // 3508 RequestElement = StrStr (ConfigResp, Question->BlockName); 3509 if (RequestElement != NULL) { 3510 // 3511 // Skip the "Question->BlockName&VALUE=" field. 3512 // 3513 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); 3514 return RequestElement; 3515 } 3516 3517 // 3518 // 2. Change all hex digits in Question->BlockName to lower and compare again. 3519 // 3520 BlockData = AllocateCopyPool (StrSize(Question->BlockName), Question->BlockName); 3521 ASSERT (BlockData != NULL); 3522 HiiToLower (BlockData); 3523 RequestElement = StrStr (ConfigResp, BlockData); 3524 FreePool (BlockData); 3525 3526 if (RequestElement != NULL) { 3527 // 3528 // Skip the "Question->BlockName&VALUE=" field. 3529 // 3530 RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE="); 3531 } 3532 3533 return RequestElement; 3534 } 3535 3536 /** 3537 Get Question default value from AltCfg string. 3538 3539 @param FormSet The form set. 3540 @param Form The form 3541 @param Question The question. 3542 3543 @retval EFI_SUCCESS Question is reset to default value. 3544 3545 **/ 3546 EFI_STATUS 3547 GetDefaultValueFromAltCfg ( 3548 IN FORM_BROWSER_FORMSET *FormSet, 3549 IN FORM_BROWSER_FORM *Form, 3550 IN OUT FORM_BROWSER_STATEMENT *Question 3551 ) 3552 { 3553 BROWSER_STORAGE *Storage; 3554 FORMSET_STORAGE *FormSetStorage; 3555 CHAR16 *ConfigResp; 3556 CHAR16 *Value; 3557 LIST_ENTRY *Link; 3558 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 3559 3560 Storage = Question->Storage; 3561 if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { 3562 return EFI_NOT_FOUND; 3563 } 3564 3565 // 3566 // Try to get AltCfg string from form. If not found it, then 3567 // try to get it from formset. 3568 // 3569 ConfigResp = NULL; 3570 Link = GetFirstNode (&Form->ConfigRequestHead); 3571 while (!IsNull (&Form->ConfigRequestHead, Link)) { 3572 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 3573 Link = GetNextNode (&Form->ConfigRequestHead, Link); 3574 3575 if (Storage == ConfigInfo->Storage) { 3576 ConfigResp = ConfigInfo->ConfigAltResp; 3577 break; 3578 } 3579 } 3580 3581 if (ConfigResp == NULL) { 3582 Link = GetFirstNode (&FormSet->StorageListHead); 3583 while (!IsNull (&FormSet->StorageListHead, Link)) { 3584 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 3585 Link = GetNextNode (&FormSet->StorageListHead, Link); 3586 3587 if (Storage == FormSetStorage->BrowserStorage) { 3588 ConfigResp = FormSetStorage->ConfigAltResp; 3589 break; 3590 } 3591 } 3592 } 3593 3594 if (ConfigResp == NULL) { 3595 return EFI_NOT_FOUND; 3596 } 3597 3598 Value = GetOffsetFromConfigResp (Question, ConfigResp); 3599 if (Value == NULL) { 3600 return EFI_NOT_FOUND; 3601 } 3602 3603 return BufferToValue (Question, Value); 3604 } 3605 3606 /** 3607 Get default Id value used for browser. 3608 3609 @param DefaultId The default id value used by hii. 3610 3611 @retval Browser used default value. 3612 3613 **/ 3614 INTN 3615 GetDefaultIdForCallBack ( 3616 UINTN DefaultId 3617 ) 3618 { 3619 if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) { 3620 return EFI_BROWSER_ACTION_DEFAULT_STANDARD; 3621 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 3622 return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING; 3623 } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) { 3624 return EFI_BROWSER_ACTION_DEFAULT_SAFE; 3625 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) { 3626 return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN; 3627 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) { 3628 return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN; 3629 } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) { 3630 return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN; 3631 } else { 3632 return -1; 3633 } 3634 } 3635 3636 3637 3638 /** 3639 Return data element in an Array by its Index. 3640 3641 @param Array The data array. 3642 @param Type Type of the data in this array. 3643 @param Index Zero based index for data in this array. 3644 3645 @retval Value The data to be returned 3646 3647 **/ 3648 UINT64 3649 GetArrayData ( 3650 IN VOID *Array, 3651 IN UINT8 Type, 3652 IN UINTN Index 3653 ) 3654 { 3655 UINT64 Data; 3656 3657 ASSERT (Array != NULL); 3658 3659 Data = 0; 3660 switch (Type) { 3661 case EFI_IFR_TYPE_NUM_SIZE_8: 3662 Data = (UINT64) *(((UINT8 *) Array) + Index); 3663 break; 3664 3665 case EFI_IFR_TYPE_NUM_SIZE_16: 3666 Data = (UINT64) *(((UINT16 *) Array) + Index); 3667 break; 3668 3669 case EFI_IFR_TYPE_NUM_SIZE_32: 3670 Data = (UINT64) *(((UINT32 *) Array) + Index); 3671 break; 3672 3673 case EFI_IFR_TYPE_NUM_SIZE_64: 3674 Data = (UINT64) *(((UINT64 *) Array) + Index); 3675 break; 3676 3677 default: 3678 break; 3679 } 3680 3681 return Data; 3682 } 3683 3684 3685 /** 3686 Set value of a data element in an Array by its Index. 3687 3688 @param Array The data array. 3689 @param Type Type of the data in this array. 3690 @param Index Zero based index for data in this array. 3691 @param Value The value to be set. 3692 3693 **/ 3694 VOID 3695 SetArrayData ( 3696 IN VOID *Array, 3697 IN UINT8 Type, 3698 IN UINTN Index, 3699 IN UINT64 Value 3700 ) 3701 { 3702 3703 ASSERT (Array != NULL); 3704 3705 switch (Type) { 3706 case EFI_IFR_TYPE_NUM_SIZE_8: 3707 *(((UINT8 *) Array) + Index) = (UINT8) Value; 3708 break; 3709 3710 case EFI_IFR_TYPE_NUM_SIZE_16: 3711 *(((UINT16 *) Array) + Index) = (UINT16) Value; 3712 break; 3713 3714 case EFI_IFR_TYPE_NUM_SIZE_32: 3715 *(((UINT32 *) Array) + Index) = (UINT32) Value; 3716 break; 3717 3718 case EFI_IFR_TYPE_NUM_SIZE_64: 3719 *(((UINT64 *) Array) + Index) = (UINT64) Value; 3720 break; 3721 3722 default: 3723 break; 3724 } 3725 } 3726 3727 /** 3728 Search an Option of a Question by its value. 3729 3730 @param Question The Question 3731 @param OptionValue Value for Option to be searched. 3732 3733 @retval Pointer Pointer to the found Option. 3734 @retval NULL Option not found. 3735 3736 **/ 3737 QUESTION_OPTION * 3738 ValueToOption ( 3739 IN FORM_BROWSER_STATEMENT *Question, 3740 IN EFI_HII_VALUE *OptionValue 3741 ) 3742 { 3743 LIST_ENTRY *Link; 3744 QUESTION_OPTION *Option; 3745 INTN Result; 3746 3747 Link = GetFirstNode (&Question->OptionListHead); 3748 while (!IsNull (&Question->OptionListHead, Link)) { 3749 Option = QUESTION_OPTION_FROM_LINK (Link); 3750 3751 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { 3752 // 3753 // Check the suppressif condition, only a valid option can be return. 3754 // 3755 if ((Option->SuppressExpression == NULL) || 3756 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) { 3757 return Option; 3758 } 3759 } 3760 3761 Link = GetNextNode (&Question->OptionListHead, Link); 3762 } 3763 3764 return NULL; 3765 } 3766 3767 3768 /** 3769 Reset Question to its default value. 3770 3771 @param FormSet The form set. 3772 @param Form The form. 3773 @param Question The question. 3774 @param DefaultId The Class of the default. 3775 3776 @retval EFI_SUCCESS Question is reset to default value. 3777 3778 **/ 3779 EFI_STATUS 3780 GetQuestionDefault ( 3781 IN FORM_BROWSER_FORMSET *FormSet, 3782 IN FORM_BROWSER_FORM *Form, 3783 IN FORM_BROWSER_STATEMENT *Question, 3784 IN UINT16 DefaultId 3785 ) 3786 { 3787 EFI_STATUS Status; 3788 LIST_ENTRY *Link; 3789 QUESTION_DEFAULT *Default; 3790 QUESTION_OPTION *Option; 3791 EFI_HII_VALUE *HiiValue; 3792 UINT8 Index; 3793 EFI_STRING StrValue; 3794 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 3795 EFI_BROWSER_ACTION_REQUEST ActionRequest; 3796 INTN Action; 3797 CHAR16 *NewString; 3798 3799 Status = EFI_NOT_FOUND; 3800 StrValue = NULL; 3801 3802 // 3803 // Statement don't have storage, skip them 3804 // 3805 if (Question->QuestionId == 0) { 3806 return Status; 3807 } 3808 3809 // 3810 // There are Five ways to specify default value for a Question: 3811 // 1, use call back function (highest priority) 3812 // 2, use ExtractConfig function 3813 // 3, use nested EFI_IFR_DEFAULT 3814 // 4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) 3815 // 5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) 3816 // 3817 HiiValue = &Question->HiiValue; 3818 3819 // 3820 // Get Question defaut value from call back function. 3821 // 3822 ConfigAccess = FormSet->ConfigAccess; 3823 Action = GetDefaultIdForCallBack (DefaultId); 3824 if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) { 3825 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 3826 Status = ConfigAccess->Callback ( 3827 ConfigAccess, 3828 Action, 3829 Question->QuestionId, 3830 HiiValue->Type, 3831 &HiiValue->Value, 3832 &ActionRequest 3833 ); 3834 if (!EFI_ERROR (Status)) { 3835 if (HiiValue->Type == EFI_IFR_TYPE_STRING) { 3836 NewString = GetToken (Question->HiiValue.Value.string, FormSet->HiiHandle); 3837 ASSERT (NewString != NULL); 3838 3839 ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth); 3840 if (StrLen (NewString) * sizeof (CHAR16) <= Question->StorageWidth) { 3841 CopyMem (Question->BufferValue, NewString, StrSize (NewString)); 3842 } else { 3843 CopyMem (Question->BufferValue, NewString, Question->StorageWidth); 3844 } 3845 3846 FreePool (NewString); 3847 } 3848 return Status; 3849 } 3850 } 3851 3852 // 3853 // Get default value from altcfg string. 3854 // 3855 if (ConfigAccess != NULL) { 3856 Status = GetDefaultValueFromAltCfg(FormSet, Form, Question); 3857 if (!EFI_ERROR (Status)) { 3858 return Status; 3859 } 3860 } 3861 3862 // 3863 // EFI_IFR_DEFAULT has highest priority 3864 // 3865 if (!IsListEmpty (&Question->DefaultListHead)) { 3866 Link = GetFirstNode (&Question->DefaultListHead); 3867 while (!IsNull (&Question->DefaultListHead, Link)) { 3868 Default = QUESTION_DEFAULT_FROM_LINK (Link); 3869 3870 if (Default->DefaultId == DefaultId) { 3871 if (Default->ValueExpression != NULL) { 3872 // 3873 // Default is provided by an Expression, evaluate it 3874 // 3875 Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); 3876 if (EFI_ERROR (Status)) { 3877 return Status; 3878 } 3879 3880 if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) { 3881 ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && Question->BufferValue != NULL); 3882 if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) { 3883 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen); 3884 Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen; 3885 } else { 3886 CopyMem (Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth); 3887 Question->HiiValue.BufferLen = Question->StorageWidth; 3888 } 3889 FreePool (Default->ValueExpression->Result.Buffer); 3890 } 3891 HiiValue->Type = Default->ValueExpression->Result.Type; 3892 CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE)); 3893 } else { 3894 // 3895 // Default value is embedded in EFI_IFR_DEFAULT 3896 // 3897 if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) { 3898 ASSERT (HiiValue->Buffer != NULL); 3899 CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen); 3900 } else { 3901 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); 3902 } 3903 } 3904 3905 if (HiiValue->Type == EFI_IFR_TYPE_STRING) { 3906 StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL); 3907 if (StrValue == NULL) { 3908 return EFI_NOT_FOUND; 3909 } 3910 if (Question->StorageWidth > StrSize (StrValue)) { 3911 CopyMem (Question->BufferValue, StrValue, StrSize (StrValue)); 3912 } else { 3913 CopyMem (Question->BufferValue, StrValue, Question->StorageWidth); 3914 } 3915 } 3916 3917 return EFI_SUCCESS; 3918 } 3919 3920 Link = GetNextNode (&Question->DefaultListHead, Link); 3921 } 3922 } 3923 3924 // 3925 // EFI_ONE_OF_OPTION 3926 // 3927 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { 3928 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 3929 // 3930 // OneOfOption could only provide Standard and Manufacturing default 3931 // 3932 Link = GetFirstNode (&Question->OptionListHead); 3933 while (!IsNull (&Question->OptionListHead, Link)) { 3934 Option = QUESTION_OPTION_FROM_LINK (Link); 3935 Link = GetNextNode (&Question->OptionListHead, Link); 3936 3937 if ((Option->SuppressExpression != NULL) && 3938 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { 3939 continue; 3940 } 3941 3942 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) || 3943 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0)) 3944 ) { 3945 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); 3946 3947 return EFI_SUCCESS; 3948 } 3949 } 3950 } 3951 } 3952 3953 // 3954 // EFI_IFR_CHECKBOX - lowest priority 3955 // 3956 if (Question->Operand == EFI_IFR_CHECKBOX_OP) { 3957 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 3958 // 3959 // Checkbox could only provide Standard and Manufacturing default 3960 // 3961 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) || 3962 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0)) 3963 ) { 3964 HiiValue->Value.b = TRUE; 3965 } else { 3966 HiiValue->Value.b = FALSE; 3967 } 3968 3969 return EFI_SUCCESS; 3970 } 3971 } 3972 3973 // 3974 // For Questions without default 3975 // 3976 Status = EFI_NOT_FOUND; 3977 switch (Question->Operand) { 3978 case EFI_IFR_NUMERIC_OP: 3979 // 3980 // Take minimum value as numeric default value 3981 // 3982 if ((Question->Flags & EFI_IFR_DISPLAY) == 0) { 3983 // 3984 // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type. 3985 // 3986 switch (Question->Flags & EFI_IFR_NUMERIC_SIZE) { 3987 case EFI_IFR_NUMERIC_SIZE_1: 3988 if (((INT8) HiiValue->Value.u8 < (INT8) Question->Minimum) || ((INT8) HiiValue->Value.u8 > (INT8) Question->Maximum)) { 3989 HiiValue->Value.u8 = (UINT8) Question->Minimum; 3990 Status = EFI_SUCCESS; 3991 } 3992 break; 3993 case EFI_IFR_NUMERIC_SIZE_2: 3994 if (((INT16) HiiValue->Value.u16 < (INT16) Question->Minimum) || ((INT16) HiiValue->Value.u16 > (INT16) Question->Maximum)) { 3995 HiiValue->Value.u16 = (UINT16) Question->Minimum; 3996 Status = EFI_SUCCESS; 3997 } 3998 break; 3999 case EFI_IFR_NUMERIC_SIZE_4: 4000 if (((INT32) HiiValue->Value.u32 < (INT32) Question->Minimum) || ((INT32) HiiValue->Value.u32 > (INT32) Question->Maximum)) { 4001 HiiValue->Value.u32 = (UINT32) Question->Minimum; 4002 Status = EFI_SUCCESS; 4003 } 4004 break; 4005 case EFI_IFR_NUMERIC_SIZE_8: 4006 if (((INT64) HiiValue->Value.u64 < (INT64) Question->Minimum) || ((INT64) HiiValue->Value.u64 > (INT64) Question->Maximum)) { 4007 HiiValue->Value.u64 = Question->Minimum; 4008 Status = EFI_SUCCESS; 4009 } 4010 break; 4011 default: 4012 break; 4013 } 4014 } else { 4015 if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) { 4016 HiiValue->Value.u64 = Question->Minimum; 4017 Status = EFI_SUCCESS; 4018 } 4019 } 4020 break; 4021 4022 case EFI_IFR_ONE_OF_OP: 4023 // 4024 // Take first oneof option as oneof's default value 4025 // 4026 if (ValueToOption (Question, HiiValue) == NULL) { 4027 Link = GetFirstNode (&Question->OptionListHead); 4028 while (!IsNull (&Question->OptionListHead, Link)) { 4029 Option = QUESTION_OPTION_FROM_LINK (Link); 4030 Link = GetNextNode (&Question->OptionListHead, Link); 4031 4032 if ((Option->SuppressExpression != NULL) && 4033 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { 4034 continue; 4035 } 4036 4037 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); 4038 Status = EFI_SUCCESS; 4039 break; 4040 } 4041 } 4042 break; 4043 4044 case EFI_IFR_ORDERED_LIST_OP: 4045 // 4046 // Take option sequence in IFR as ordered list's default value 4047 // 4048 Index = 0; 4049 Link = GetFirstNode (&Question->OptionListHead); 4050 while (!IsNull (&Question->OptionListHead, Link)) { 4051 Status = EFI_SUCCESS; 4052 Option = QUESTION_OPTION_FROM_LINK (Link); 4053 Link = GetNextNode (&Question->OptionListHead, Link); 4054 4055 if ((Option->SuppressExpression != NULL) && 4056 EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) { 4057 continue; 4058 } 4059 4060 SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64); 4061 4062 Index++; 4063 if (Index >= Question->MaxContainers) { 4064 break; 4065 } 4066 } 4067 break; 4068 4069 default: 4070 break; 4071 } 4072 4073 return Status; 4074 } 4075 4076 /** 4077 Get AltCfg string for current form. 4078 4079 @param FormSet Form data structure. 4080 @param Form Form data structure. 4081 @param DefaultId The Class of the default. 4082 @param BrowserStorage The input request storage for the questions. 4083 4084 **/ 4085 VOID 4086 ExtractAltCfgForForm ( 4087 IN FORM_BROWSER_FORMSET *FormSet, 4088 IN FORM_BROWSER_FORM *Form, 4089 IN UINT16 DefaultId, 4090 IN BROWSER_STORAGE *BrowserStorage 4091 ) 4092 { 4093 EFI_STATUS Status; 4094 LIST_ENTRY *Link; 4095 CHAR16 *ConfigResp; 4096 CHAR16 *Progress; 4097 CHAR16 *Result; 4098 BROWSER_STORAGE *Storage; 4099 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 4100 FORMSET_STORAGE *FormSetStorage; 4101 4102 // 4103 // Check whether has get AltCfg string for this formset. 4104 // If yes, no need to get AltCfg for form. 4105 // 4106 Link = GetFirstNode (&FormSet->StorageListHead); 4107 while (!IsNull (&FormSet->StorageListHead, Link)) { 4108 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 4109 Storage = FormSetStorage->BrowserStorage; 4110 Link = GetNextNode (&FormSet->StorageListHead, Link); 4111 if (BrowserStorage != NULL && BrowserStorage != Storage) { 4112 continue; 4113 } 4114 4115 if (Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE && 4116 FormSetStorage->ElementCount != 0 && 4117 FormSetStorage->HasCallAltCfg) { 4118 return; 4119 } 4120 } 4121 4122 // 4123 // Get AltCfg string for each form. 4124 // 4125 Link = GetFirstNode (&Form->ConfigRequestHead); 4126 while (!IsNull (&Form->ConfigRequestHead, Link)) { 4127 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 4128 Link = GetNextNode (&Form->ConfigRequestHead, Link); 4129 4130 Storage = ConfigInfo->Storage; 4131 if (BrowserStorage != NULL && BrowserStorage != Storage) { 4132 continue; 4133 } 4134 4135 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 4136 continue; 4137 } 4138 4139 // 4140 // 1. Skip if there is no RequestElement 4141 // 4142 if (ConfigInfo->ElementCount == 0) { 4143 continue; 4144 } 4145 4146 // 4147 // 2. Get value through hii config routine protocol. 4148 // 4149 Status = mHiiConfigRouting->ExtractConfig ( 4150 mHiiConfigRouting, 4151 ConfigInfo->ConfigRequest, 4152 &Progress, 4153 &Result 4154 ); 4155 if (EFI_ERROR (Status)) { 4156 continue; 4157 } 4158 4159 // 4160 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp) 4161 // Get the default configuration string according to the default ID. 4162 // 4163 Status = mHiiConfigRouting->GetAltConfig ( 4164 mHiiConfigRouting, 4165 Result, 4166 &Storage->Guid, 4167 Storage->Name, 4168 NULL, 4169 &DefaultId, // it can be NULL to get the current setting. 4170 &ConfigResp 4171 ); 4172 FreePool (Result); 4173 if (EFI_ERROR (Status)) { 4174 continue; 4175 } 4176 4177 ConfigInfo->ConfigAltResp = ConfigResp; 4178 } 4179 } 4180 4181 /** 4182 Clean AltCfg string for current form. 4183 4184 @param Form Form data structure. 4185 4186 **/ 4187 VOID 4188 CleanAltCfgForForm ( 4189 IN FORM_BROWSER_FORM *Form 4190 ) 4191 { 4192 LIST_ENTRY *Link; 4193 FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; 4194 4195 Link = GetFirstNode (&Form->ConfigRequestHead); 4196 while (!IsNull (&Form->ConfigRequestHead, Link)) { 4197 ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); 4198 Link = GetNextNode (&Form->ConfigRequestHead, Link); 4199 4200 if (ConfigInfo->ConfigAltResp != NULL) { 4201 FreePool (ConfigInfo->ConfigAltResp); 4202 ConfigInfo->ConfigAltResp = NULL; 4203 } 4204 } 4205 } 4206 4207 /** 4208 Get AltCfg string for current formset. 4209 4210 @param FormSet Form data structure. 4211 @param DefaultId The Class of the default. 4212 @param BrowserStorage The input request storage for the questions. 4213 4214 **/ 4215 VOID 4216 ExtractAltCfgForFormSet ( 4217 IN FORM_BROWSER_FORMSET *FormSet, 4218 IN UINT16 DefaultId, 4219 IN BROWSER_STORAGE *BrowserStorage 4220 ) 4221 { 4222 EFI_STATUS Status; 4223 LIST_ENTRY *Link; 4224 CHAR16 *ConfigResp; 4225 CHAR16 *Progress; 4226 CHAR16 *Result; 4227 BROWSER_STORAGE *Storage; 4228 FORMSET_STORAGE *FormSetStorage; 4229 4230 Link = GetFirstNode (&FormSet->StorageListHead); 4231 while (!IsNull (&FormSet->StorageListHead, Link)) { 4232 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 4233 Storage = FormSetStorage->BrowserStorage; 4234 Link = GetNextNode (&FormSet->StorageListHead, Link); 4235 4236 if (BrowserStorage != NULL && BrowserStorage != Storage) { 4237 continue; 4238 } 4239 4240 if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { 4241 continue; 4242 } 4243 4244 // 4245 // 1. Skip if there is no RequestElement 4246 // 4247 if (FormSetStorage->ElementCount == 0) { 4248 continue; 4249 } 4250 4251 FormSetStorage->HasCallAltCfg = TRUE; 4252 4253 // 4254 // 2. Get value through hii config routine protocol. 4255 // 4256 Status = mHiiConfigRouting->ExtractConfig ( 4257 mHiiConfigRouting, 4258 FormSetStorage->ConfigRequest, 4259 &Progress, 4260 &Result 4261 ); 4262 if (EFI_ERROR (Status)) { 4263 continue; 4264 } 4265 4266 // 4267 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp) 4268 // Get the default configuration string according to the default ID. 4269 // 4270 Status = mHiiConfigRouting->GetAltConfig ( 4271 mHiiConfigRouting, 4272 Result, 4273 &Storage->Guid, 4274 Storage->Name, 4275 NULL, 4276 &DefaultId, // it can be NULL to get the current setting. 4277 &ConfigResp 4278 ); 4279 4280 FreePool (Result); 4281 if (EFI_ERROR (Status)) { 4282 continue; 4283 } 4284 4285 FormSetStorage->ConfigAltResp = ConfigResp; 4286 } 4287 4288 } 4289 4290 /** 4291 Clean AltCfg string for current formset. 4292 4293 @param FormSet Form data structure. 4294 4295 **/ 4296 VOID 4297 CleanAltCfgForFormSet ( 4298 IN FORM_BROWSER_FORMSET *FormSet 4299 ) 4300 { 4301 LIST_ENTRY *Link; 4302 FORMSET_STORAGE *FormSetStorage; 4303 4304 Link = GetFirstNode (&FormSet->StorageListHead); 4305 while (!IsNull (&FormSet->StorageListHead, Link)) { 4306 FormSetStorage = FORMSET_STORAGE_FROM_LINK (Link); 4307 Link = GetNextNode (&FormSet->StorageListHead, Link); 4308 4309 if (FormSetStorage->ConfigAltResp != NULL) { 4310 FreePool (FormSetStorage->ConfigAltResp); 4311 FormSetStorage->ConfigAltResp = NULL; 4312 } 4313 4314 FormSetStorage->HasCallAltCfg = FALSE; 4315 } 4316 } 4317 4318 /** 4319 Reset Questions to their initial value or default value in a Form, Formset or System. 4320 4321 GetDefaultValueScope parameter decides which questions will reset 4322 to its default value. 4323 4324 @param FormSet FormSet data structure. 4325 @param Form Form data structure. 4326 @param DefaultId The Class of the default. 4327 @param SettingScope Setting Scope for Default action. 4328 @param GetDefaultValueScope Get default value scope. 4329 @param Storage Get default value only for this storage. 4330 @param RetrieveValueFirst Whether call the retrieve call back to 4331 get the initial value before get default 4332 value. 4333 @param SkipGetAltCfg Whether skip the get altcfg string process. 4334 4335 @retval EFI_SUCCESS The function completed successfully. 4336 @retval EFI_UNSUPPORTED Unsupport SettingScope. 4337 4338 **/ 4339 EFI_STATUS 4340 ExtractDefault ( 4341 IN FORM_BROWSER_FORMSET *FormSet, 4342 IN FORM_BROWSER_FORM *Form, 4343 IN UINT16 DefaultId, 4344 IN BROWSER_SETTING_SCOPE SettingScope, 4345 IN BROWSER_GET_DEFAULT_VALUE GetDefaultValueScope, 4346 IN BROWSER_STORAGE *Storage OPTIONAL, 4347 IN BOOLEAN RetrieveValueFirst, 4348 IN BOOLEAN SkipGetAltCfg 4349 ) 4350 { 4351 EFI_STATUS Status; 4352 LIST_ENTRY *FormLink; 4353 LIST_ENTRY *Link; 4354 FORM_BROWSER_STATEMENT *Question; 4355 FORM_BROWSER_FORMSET *LocalFormSet; 4356 FORM_BROWSER_FORMSET *OldFormSet; 4357 4358 Status = EFI_SUCCESS; 4359 4360 // 4361 // Check the supported setting level. 4362 // 4363 if (SettingScope >= MaxLevel || GetDefaultValueScope >= GetDefaultForMax) { 4364 return EFI_UNSUPPORTED; 4365 } 4366 4367 if (GetDefaultValueScope == GetDefaultForStorage && Storage == NULL) { 4368 return EFI_UNSUPPORTED; 4369 } 4370 4371 if (SettingScope == FormLevel) { 4372 // 4373 // Prepare the AltCfg String for form. 4374 // 4375 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4376 ExtractAltCfgForForm (FormSet, Form, DefaultId, Storage); 4377 } 4378 4379 // 4380 // Extract Form default 4381 // 4382 Link = GetFirstNode (&Form->StatementListHead); 4383 while (!IsNull (&Form->StatementListHead, Link)) { 4384 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 4385 Link = GetNextNode (&Form->StatementListHead, Link); 4386 4387 // 4388 // If get default value only for this storage, check the storage first. 4389 // 4390 if ((GetDefaultValueScope == GetDefaultForStorage) && (Question->Storage != Storage)) { 4391 continue; 4392 } 4393 4394 // 4395 // If get default value only for no storage question, just skip the question which has storage. 4396 // 4397 if ((GetDefaultValueScope == GetDefaultForNoStorage) && (Question->Storage != NULL)) { 4398 continue; 4399 } 4400 4401 // 4402 // If Question is disabled, don't reset it to default 4403 // 4404 if (Question->Expression != NULL) { 4405 if (EvaluateExpressionList(Question->Expression, TRUE, FormSet, Form) == ExpressDisable) { 4406 continue; 4407 } 4408 } 4409 4410 if (RetrieveValueFirst) { 4411 // 4412 // Call the Retrieve call back to get the initial question value. 4413 // 4414 Status = ProcessRetrieveForQuestion(FormSet->ConfigAccess, Question, FormSet); 4415 } 4416 4417 // 4418 // If not request to get the initial value or get initial value fail, then get default value. 4419 // 4420 if (!RetrieveValueFirst || EFI_ERROR (Status)) { 4421 Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); 4422 if (EFI_ERROR (Status)) { 4423 continue; 4424 } 4425 } 4426 4427 // 4428 // Synchronize Buffer storage's Edit buffer 4429 // 4430 if ((Question->Storage != NULL) && 4431 (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { 4432 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 4433 } 4434 } 4435 4436 // 4437 // Clean the AltCfg String. 4438 // 4439 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4440 CleanAltCfgForForm(Form); 4441 } 4442 } else if (SettingScope == FormSetLevel) { 4443 // 4444 // Prepare the AltCfg String for formset. 4445 // 4446 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4447 ExtractAltCfgForFormSet (FormSet, DefaultId, Storage); 4448 } 4449 4450 FormLink = GetFirstNode (&FormSet->FormListHead); 4451 while (!IsNull (&FormSet->FormListHead, FormLink)) { 4452 Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); 4453 ExtractDefault (FormSet, Form, DefaultId, FormLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); 4454 FormLink = GetNextNode (&FormSet->FormListHead, FormLink); 4455 } 4456 4457 // 4458 // Clean the AltCfg String. 4459 // 4460 if (!SkipGetAltCfg && (GetDefaultValueScope != GetDefaultForNoStorage)) { 4461 CleanAltCfgForFormSet (FormSet); 4462 } 4463 } else if (SettingScope == SystemLevel) { 4464 // 4465 // Preload all Hii formset. 4466 // 4467 LoadAllHiiFormset(); 4468 4469 OldFormSet = mSystemLevelFormSet; 4470 4471 // 4472 // Set Default Value for each FormSet in the maintain list. 4473 // 4474 Link = GetFirstNode (&gBrowserFormSetList); 4475 while (!IsNull (&gBrowserFormSetList, Link)) { 4476 LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 4477 Link = GetNextNode (&gBrowserFormSetList, Link); 4478 if (!ValidateFormSet(LocalFormSet)) { 4479 continue; 4480 } 4481 4482 mSystemLevelFormSet = LocalFormSet; 4483 4484 ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel, GetDefaultValueScope, Storage, RetrieveValueFirst, SkipGetAltCfg); 4485 } 4486 4487 mSystemLevelFormSet = OldFormSet; 4488 } 4489 4490 return EFI_SUCCESS; 4491 } 4492 4493 4494 /** 4495 Validate whether this question's value has changed. 4496 4497 @param FormSet FormSet data structure. 4498 @param Form Form data structure. 4499 @param Question Question to be initialized. 4500 @param GetValueFrom Where to get value, may from editbuffer, buffer or hii driver. 4501 4502 @retval TRUE Question's value has changed. 4503 @retval FALSE Question's value has not changed 4504 4505 **/ 4506 BOOLEAN 4507 IsQuestionValueChanged ( 4508 IN FORM_BROWSER_FORMSET *FormSet, 4509 IN FORM_BROWSER_FORM *Form, 4510 IN OUT FORM_BROWSER_STATEMENT *Question, 4511 IN GET_SET_QUESTION_VALUE_WITH GetValueFrom 4512 ) 4513 { 4514 EFI_HII_VALUE BackUpValue; 4515 CHAR8 *BackUpBuffer; 4516 EFI_HII_VALUE BackUpValue2; 4517 CHAR8 *BackUpBuffer2; 4518 EFI_STATUS Status; 4519 BOOLEAN ValueChanged; 4520 UINTN BufferWidth; 4521 4522 // 4523 // For quetion without storage, always mark it as data not changed. 4524 // 4525 if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) { 4526 return FALSE; 4527 } 4528 4529 BackUpBuffer = NULL; 4530 BackUpBuffer2 = NULL; 4531 ValueChanged = FALSE; 4532 4533 switch (Question->Operand) { 4534 case EFI_IFR_ORDERED_LIST_OP: 4535 BufferWidth = Question->StorageWidth; 4536 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); 4537 ASSERT (BackUpBuffer != NULL); 4538 break; 4539 4540 case EFI_IFR_STRING_OP: 4541 case EFI_IFR_PASSWORD_OP: 4542 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); 4543 BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue); 4544 ASSERT (BackUpBuffer != NULL); 4545 break; 4546 4547 default: 4548 BufferWidth = 0; 4549 break; 4550 } 4551 CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)); 4552 4553 if (GetValueFrom == GetSetValueWithBothBuffer) { 4554 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 4555 ASSERT_EFI_ERROR(Status); 4556 4557 switch (Question->Operand) { 4558 case EFI_IFR_ORDERED_LIST_OP: 4559 BufferWidth = Question->StorageWidth; 4560 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); 4561 ASSERT (BackUpBuffer2 != NULL); 4562 break; 4563 4564 case EFI_IFR_STRING_OP: 4565 case EFI_IFR_PASSWORD_OP: 4566 BufferWidth = (UINTN) Question->Maximum * sizeof (CHAR16); 4567 BackUpBuffer2 = AllocateCopyPool (BufferWidth, Question->BufferValue); 4568 ASSERT (BackUpBuffer2 != NULL); 4569 break; 4570 4571 default: 4572 BufferWidth = 0; 4573 break; 4574 } 4575 CopyMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)); 4576 4577 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer); 4578 ASSERT_EFI_ERROR(Status); 4579 4580 if (CompareMem (&BackUpValue2, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || 4581 CompareMem (BackUpBuffer2, Question->BufferValue, BufferWidth) != 0) { 4582 ValueChanged = TRUE; 4583 } 4584 } else { 4585 Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom); 4586 ASSERT_EFI_ERROR(Status); 4587 4588 if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 || 4589 CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) { 4590 ValueChanged = TRUE; 4591 } 4592 } 4593 4594 CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE)); 4595 if (BackUpBuffer != NULL) { 4596 CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth); 4597 FreePool (BackUpBuffer); 4598 } 4599 4600 if (BackUpBuffer2 != NULL) { 4601 FreePool (BackUpBuffer2); 4602 } 4603 4604 Question->ValueChanged = ValueChanged; 4605 4606 return ValueChanged; 4607 } 4608 4609 /** 4610 Initialize Question's Edit copy from Storage. 4611 4612 @param Selection Selection contains the information about 4613 the Selection, form and formset to be displayed. 4614 Selection action may be updated in retrieve callback. 4615 If Selection is NULL, only initialize Question value. 4616 @param FormSet FormSet data structure. 4617 @param Form Form data structure. 4618 4619 @retval EFI_SUCCESS The function completed successfully. 4620 4621 **/ 4622 EFI_STATUS 4623 LoadFormConfig ( 4624 IN OUT UI_MENU_SELECTION *Selection, 4625 IN FORM_BROWSER_FORMSET *FormSet, 4626 IN FORM_BROWSER_FORM *Form 4627 ) 4628 { 4629 EFI_STATUS Status; 4630 LIST_ENTRY *Link; 4631 FORM_BROWSER_STATEMENT *Question; 4632 4633 Link = GetFirstNode (&Form->StatementListHead); 4634 while (!IsNull (&Form->StatementListHead, Link)) { 4635 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 4636 4637 // 4638 // Initialize local copy of Value for each Question 4639 // 4640 if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) { 4641 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver); 4642 } else { 4643 Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer); 4644 } 4645 if (EFI_ERROR (Status)) { 4646 return Status; 4647 } 4648 4649 if ((Question->Operand == EFI_IFR_STRING_OP) || (Question->Operand == EFI_IFR_PASSWORD_OP)) { 4650 HiiSetString (FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL); 4651 } 4652 4653 Link = GetNextNode (&Form->StatementListHead, Link); 4654 } 4655 4656 return EFI_SUCCESS; 4657 } 4658 4659 /** 4660 Initialize Question's Edit copy from Storage for the whole Formset. 4661 4662 @param Selection Selection contains the information about 4663 the Selection, form and formset to be displayed. 4664 Selection action may be updated in retrieve callback. 4665 If Selection is NULL, only initialize Question value. 4666 @param FormSet FormSet data structure. 4667 4668 @retval EFI_SUCCESS The function completed successfully. 4669 4670 **/ 4671 EFI_STATUS 4672 LoadFormSetConfig ( 4673 IN OUT UI_MENU_SELECTION *Selection, 4674 IN FORM_BROWSER_FORMSET *FormSet 4675 ) 4676 { 4677 EFI_STATUS Status; 4678 LIST_ENTRY *Link; 4679 FORM_BROWSER_FORM *Form; 4680 4681 Link = GetFirstNode (&FormSet->FormListHead); 4682 while (!IsNull (&FormSet->FormListHead, Link)) { 4683 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 4684 4685 // 4686 // Initialize local copy of Value for each Form 4687 // 4688 Status = LoadFormConfig (Selection, FormSet, Form); 4689 if (EFI_ERROR (Status)) { 4690 return Status; 4691 } 4692 4693 Link = GetNextNode (&FormSet->FormListHead, Link); 4694 } 4695 4696 // 4697 // Finished question initialization. 4698 // 4699 FormSet->QuestionInited = TRUE; 4700 4701 return EFI_SUCCESS; 4702 } 4703 4704 /** 4705 Remove the Request element from the Config Request. 4706 4707 @param Storage Pointer to the browser storage. 4708 @param RequestElement The pointer to the Request element. 4709 4710 **/ 4711 VOID 4712 RemoveElement ( 4713 IN OUT BROWSER_STORAGE *Storage, 4714 IN CHAR16 *RequestElement 4715 ) 4716 { 4717 CHAR16 *NewStr; 4718 CHAR16 *DestStr; 4719 4720 ASSERT (Storage->ConfigRequest != NULL && RequestElement != NULL); 4721 4722 NewStr = StrStr (Storage->ConfigRequest, RequestElement); 4723 4724 if (NewStr == NULL) { 4725 return; 4726 } 4727 4728 // 4729 // Remove this element from this ConfigRequest. 4730 // 4731 DestStr = NewStr; 4732 NewStr += StrLen (RequestElement); 4733 CopyMem (DestStr, NewStr, StrSize (NewStr)); 4734 4735 Storage->SpareStrLen += StrLen (RequestElement); 4736 } 4737 4738 /** 4739 Adjust config request in storage, remove the request elements existed in the input ConfigRequest. 4740 4741 @param Storage Pointer to the formset storage. 4742 @param ConfigRequest The pointer to the Request element. 4743 4744 **/ 4745 VOID 4746 RemoveConfigRequest ( 4747 FORMSET_STORAGE *Storage, 4748 CHAR16 *ConfigRequest 4749 ) 4750 { 4751 CHAR16 *RequestElement; 4752 CHAR16 *NextRequestElement; 4753 CHAR16 *SearchKey; 4754 4755 // 4756 // No request element in it, just return. 4757 // 4758 if (ConfigRequest == NULL) { 4759 return; 4760 } 4761 4762 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 4763 // 4764 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage 4765 // 4766 SearchKey = L"&"; 4767 } else { 4768 // 4769 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage 4770 // 4771 SearchKey = L"&OFFSET"; 4772 } 4773 4774 // 4775 // Find SearchKey storage 4776 // 4777 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 4778 RequestElement = StrStr (ConfigRequest, L"PATH"); 4779 ASSERT (RequestElement != NULL); 4780 RequestElement = StrStr (RequestElement, SearchKey); 4781 } else { 4782 RequestElement = StrStr (ConfigRequest, SearchKey); 4783 } 4784 4785 while (RequestElement != NULL) { 4786 // 4787 // +1 to avoid find header itself. 4788 // 4789 NextRequestElement = StrStr (RequestElement + 1, SearchKey); 4790 4791 // 4792 // The last Request element in configRequest string. 4793 // 4794 if (NextRequestElement != NULL) { 4795 // 4796 // Replace "&" with '\0'. 4797 // 4798 *NextRequestElement = L'\0'; 4799 } 4800 4801 RemoveElement (Storage->BrowserStorage, RequestElement); 4802 4803 if (NextRequestElement != NULL) { 4804 // 4805 // Restore '&' with '\0' for later used. 4806 // 4807 *NextRequestElement = L'&'; 4808 } 4809 4810 RequestElement = NextRequestElement; 4811 } 4812 4813 // 4814 // If no request element remain, just remove the ConfigRequest string. 4815 // 4816 if (StrCmp (Storage->BrowserStorage->ConfigRequest, Storage->ConfigHdr) == 0) { 4817 FreePool (Storage->BrowserStorage->ConfigRequest); 4818 Storage->BrowserStorage->ConfigRequest = NULL; 4819 Storage->BrowserStorage->SpareStrLen = 0; 4820 } 4821 } 4822 4823 /** 4824 Base on the current formset info, clean the ConfigRequest string in browser storage. 4825 4826 @param FormSet Pointer of the FormSet 4827 4828 **/ 4829 VOID 4830 CleanBrowserStorage ( 4831 IN OUT FORM_BROWSER_FORMSET *FormSet 4832 ) 4833 { 4834 LIST_ENTRY *Link; 4835 FORMSET_STORAGE *Storage; 4836 4837 Link = GetFirstNode (&FormSet->StorageListHead); 4838 while (!IsNull (&FormSet->StorageListHead, Link)) { 4839 Storage = FORMSET_STORAGE_FROM_LINK (Link); 4840 Link = GetNextNode (&FormSet->StorageListHead, Link); 4841 4842 if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) { 4843 if (Storage->ConfigRequest == NULL || Storage->BrowserStorage->ConfigRequest == NULL) { 4844 continue; 4845 } 4846 4847 RemoveConfigRequest (Storage, Storage->ConfigRequest); 4848 } else if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER || 4849 Storage->BrowserStorage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 4850 if (Storage->BrowserStorage->ConfigRequest != NULL) { 4851 FreePool (Storage->BrowserStorage->ConfigRequest); 4852 Storage->BrowserStorage->ConfigRequest = NULL; 4853 } 4854 Storage->BrowserStorage->Initialized = FALSE; 4855 } 4856 } 4857 } 4858 4859 /** 4860 Check whether current element in the ConfigReqeust string. 4861 4862 @param BrowserStorage Storage which includes ConfigReqeust. 4863 @param RequestElement New element need to check. 4864 4865 @retval TRUE The Element is in the ConfigReqeust string. 4866 @retval FALSE The Element not in the configReqeust String. 4867 4868 **/ 4869 BOOLEAN 4870 ElementValidation ( 4871 BROWSER_STORAGE *BrowserStorage, 4872 CHAR16 *RequestElement 4873 ) 4874 { 4875 return StrStr (BrowserStorage->ConfigRequest, RequestElement) != NULL ? TRUE : FALSE; 4876 } 4877 4878 /** 4879 Append the Request element to the Config Request. 4880 4881 @param ConfigRequest Current ConfigRequest info. 4882 @param SpareStrLen Current remain free buffer for config reqeust. 4883 @param RequestElement New Request element. 4884 4885 **/ 4886 VOID 4887 AppendConfigRequest ( 4888 IN OUT CHAR16 **ConfigRequest, 4889 IN OUT UINTN *SpareStrLen, 4890 IN CHAR16 *RequestElement 4891 ) 4892 { 4893 CHAR16 *NewStr; 4894 UINTN StringSize; 4895 UINTN StrLength; 4896 UINTN MaxLen; 4897 4898 StrLength = StrLen (RequestElement); 4899 StringSize = (*ConfigRequest != NULL) ? StrSize (*ConfigRequest) : sizeof (CHAR16); 4900 MaxLen = StringSize / sizeof (CHAR16) + *SpareStrLen; 4901 4902 // 4903 // Append <RequestElement> to <ConfigRequest> 4904 // 4905 if (StrLength > *SpareStrLen) { 4906 // 4907 // Old String buffer is not sufficient for RequestElement, allocate a new one 4908 // 4909 MaxLen = StringSize / sizeof (CHAR16) + CONFIG_REQUEST_STRING_INCREMENTAL; 4910 NewStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 4911 ASSERT (NewStr != NULL); 4912 4913 if (*ConfigRequest != NULL) { 4914 CopyMem (NewStr, *ConfigRequest, StringSize); 4915 FreePool (*ConfigRequest); 4916 } 4917 *ConfigRequest = NewStr; 4918 *SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; 4919 } 4920 4921 StrCatS (*ConfigRequest, MaxLen, RequestElement); 4922 *SpareStrLen -= StrLength; 4923 } 4924 4925 /** 4926 Adjust the config request info, remove the request elements which already in AllConfigRequest string. 4927 4928 @param Storage Form set Storage. 4929 @param Request The input request string. 4930 @param RespString Whether the input is ConfigRequest or ConfigResp format. 4931 4932 @retval TRUE Has element not covered by current used elements, need to continue to call ExtractConfig 4933 @retval FALSE All elements covered by current used elements. 4934 4935 **/ 4936 BOOLEAN 4937 ConfigRequestAdjust ( 4938 IN BROWSER_STORAGE *Storage, 4939 IN CHAR16 *Request, 4940 IN BOOLEAN RespString 4941 ) 4942 { 4943 CHAR16 *RequestElement; 4944 CHAR16 *NextRequestElement; 4945 CHAR16 *NextElementBakup; 4946 CHAR16 *SearchKey; 4947 CHAR16 *ValueKey; 4948 BOOLEAN RetVal; 4949 CHAR16 *ConfigRequest; 4950 4951 RetVal = FALSE; 4952 NextElementBakup = NULL; 4953 ValueKey = NULL; 4954 4955 if (Request != NULL) { 4956 ConfigRequest = Request; 4957 } else { 4958 ConfigRequest = Storage->ConfigRequest; 4959 } 4960 4961 if (Storage->ConfigRequest == NULL) { 4962 Storage->ConfigRequest = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); 4963 return TRUE; 4964 } 4965 4966 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 4967 // 4968 // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage 4969 // 4970 SearchKey = L"&"; 4971 } else { 4972 // 4973 // "&OFFSET=####&WIDTH=####" section for EFI_HII_VARSTORE_BUFFER storage 4974 // 4975 SearchKey = L"&OFFSET"; 4976 ValueKey = L"&VALUE"; 4977 } 4978 4979 // 4980 // Find SearchKey storage 4981 // 4982 if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { 4983 RequestElement = StrStr (ConfigRequest, L"PATH"); 4984 ASSERT (RequestElement != NULL); 4985 RequestElement = StrStr (RequestElement, SearchKey); 4986 } else { 4987 RequestElement = StrStr (ConfigRequest, SearchKey); 4988 } 4989 4990 while (RequestElement != NULL) { 4991 4992 // 4993 // +1 to avoid find header itself. 4994 // 4995 NextRequestElement = StrStr (RequestElement + 1, SearchKey); 4996 4997 // 4998 // The last Request element in configRequest string. 4999 // 5000 if (NextRequestElement != NULL) { 5001 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 5002 NextElementBakup = NextRequestElement; 5003 NextRequestElement = StrStr (RequestElement, ValueKey); 5004 ASSERT (NextRequestElement != NULL); 5005 } 5006 // 5007 // Replace "&" with '\0'. 5008 // 5009 *NextRequestElement = L'\0'; 5010 } else { 5011 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 5012 NextElementBakup = NextRequestElement; 5013 NextRequestElement = StrStr (RequestElement, ValueKey); 5014 ASSERT (NextRequestElement != NULL); 5015 // 5016 // Replace "&" with '\0'. 5017 // 5018 *NextRequestElement = L'\0'; 5019 } 5020 } 5021 5022 if (!ElementValidation (Storage, RequestElement)) { 5023 // 5024 // Add this element to the Storage->BrowserStorage->AllRequestElement. 5025 // 5026 AppendConfigRequest(&Storage->ConfigRequest, &Storage->SpareStrLen, RequestElement); 5027 RetVal = TRUE; 5028 } 5029 5030 if (NextRequestElement != NULL) { 5031 // 5032 // Restore '&' with '\0' for later used. 5033 // 5034 *NextRequestElement = L'&'; 5035 } 5036 5037 if (RespString && (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { 5038 RequestElement = NextElementBakup; 5039 } else { 5040 RequestElement = NextRequestElement; 5041 } 5042 } 5043 5044 return RetVal; 5045 } 5046 5047 /** 5048 Fill storage's edit copy with settings requested from Configuration Driver. 5049 5050 @param FormSet FormSet data structure. 5051 @param Storage Buffer Storage. 5052 5053 **/ 5054 VOID 5055 LoadStorage ( 5056 IN FORM_BROWSER_FORMSET *FormSet, 5057 IN FORMSET_STORAGE *Storage 5058 ) 5059 { 5060 EFI_STATUS Status; 5061 EFI_STRING Progress; 5062 EFI_STRING Result; 5063 CHAR16 *StrPtr; 5064 EFI_STRING ConfigRequest; 5065 UINTN StrLen; 5066 5067 ConfigRequest = NULL; 5068 5069 switch (Storage->BrowserStorage->Type) { 5070 case EFI_HII_VARSTORE_EFI_VARIABLE: 5071 return; 5072 5073 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER: 5074 if (Storage->BrowserStorage->ConfigRequest != NULL) { 5075 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); 5076 return; 5077 } 5078 break; 5079 5080 case EFI_HII_VARSTORE_BUFFER: 5081 case EFI_HII_VARSTORE_NAME_VALUE: 5082 // 5083 // Skip if there is no RequestElement. 5084 // 5085 if (Storage->ElementCount == 0) { 5086 return; 5087 } 5088 5089 // 5090 // Just update the ConfigRequest, if storage already initialized. 5091 // 5092 if (Storage->BrowserStorage->Initialized) { 5093 ConfigRequestAdjust(Storage->BrowserStorage, Storage->ConfigRequest, FALSE); 5094 return; 5095 } 5096 5097 Storage->BrowserStorage->Initialized = TRUE; 5098 break; 5099 5100 default: 5101 return; 5102 } 5103 5104 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { 5105 // 5106 // Create the config request string to get all fields for this storage. 5107 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template 5108 // followed by "&OFFSET=0&WIDTH=WWWW"followed by a Null-terminator 5109 // 5110 StrLen = StrSize (Storage->ConfigHdr) + 20 * sizeof (CHAR16); 5111 ConfigRequest = AllocateZeroPool (StrLen); 5112 ASSERT (ConfigRequest != NULL); 5113 UnicodeSPrint ( 5114 ConfigRequest, 5115 StrLen, 5116 L"%s&OFFSET=0&WIDTH=%04x", 5117 Storage->ConfigHdr, 5118 Storage->BrowserStorage->Size); 5119 } else { 5120 ConfigRequest = Storage->ConfigRequest; 5121 } 5122 5123 // 5124 // Request current settings from Configuration Driver 5125 // 5126 Status = mHiiConfigRouting->ExtractConfig ( 5127 mHiiConfigRouting, 5128 ConfigRequest, 5129 &Progress, 5130 &Result 5131 ); 5132 5133 // 5134 // If get value fail, extract default from IFR binary 5135 // 5136 if (EFI_ERROR (Status)) { 5137 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE, TRUE); 5138 } else { 5139 // 5140 // Convert Result from <ConfigAltResp> to <ConfigResp> 5141 // 5142 StrPtr = StrStr (Result, L"&GUID="); 5143 if (StrPtr != NULL) { 5144 *StrPtr = L'\0'; 5145 } 5146 5147 Status = ConfigRespToStorage (Storage->BrowserStorage, Result); 5148 FreePool (Result); 5149 } 5150 5151 Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest); 5152 5153 // 5154 // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. 5155 // 5156 SynchronizeStorage(Storage->BrowserStorage, NULL, TRUE); 5157 5158 if (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) { 5159 if (ConfigRequest != NULL) { 5160 FreePool (ConfigRequest); 5161 } 5162 } 5163 } 5164 5165 /** 5166 Get Value changed status from old question. 5167 5168 @param NewFormSet FormSet data structure. 5169 @param OldQuestion Old question which has value changed. 5170 5171 **/ 5172 VOID 5173 SyncStatusForQuestion ( 5174 IN OUT FORM_BROWSER_FORMSET *NewFormSet, 5175 IN FORM_BROWSER_STATEMENT *OldQuestion 5176 ) 5177 { 5178 LIST_ENTRY *Link; 5179 LIST_ENTRY *QuestionLink; 5180 FORM_BROWSER_FORM *Form; 5181 FORM_BROWSER_STATEMENT *Question; 5182 5183 // 5184 // For each form in one formset. 5185 // 5186 Link = GetFirstNode (&NewFormSet->FormListHead); 5187 while (!IsNull (&NewFormSet->FormListHead, Link)) { 5188 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 5189 Link = GetNextNode (&NewFormSet->FormListHead, Link); 5190 5191 // 5192 // for each question in one form. 5193 // 5194 QuestionLink = GetFirstNode (&Form->StatementListHead); 5195 while (!IsNull (&Form->StatementListHead, QuestionLink)) { 5196 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); 5197 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); 5198 5199 if (Question->QuestionId == OldQuestion->QuestionId) { 5200 Question->ValueChanged = TRUE; 5201 return; 5202 } 5203 } 5204 } 5205 } 5206 5207 /** 5208 Get Value changed status from old formset. 5209 5210 @param NewFormSet FormSet data structure. 5211 @param OldFormSet FormSet data structure. 5212 5213 **/ 5214 VOID 5215 SyncStatusForFormSet ( 5216 IN OUT FORM_BROWSER_FORMSET *NewFormSet, 5217 IN FORM_BROWSER_FORMSET *OldFormSet 5218 ) 5219 { 5220 LIST_ENTRY *Link; 5221 LIST_ENTRY *QuestionLink; 5222 FORM_BROWSER_FORM *Form; 5223 FORM_BROWSER_STATEMENT *Question; 5224 5225 // 5226 // For each form in one formset. 5227 // 5228 Link = GetFirstNode (&OldFormSet->FormListHead); 5229 while (!IsNull (&OldFormSet->FormListHead, Link)) { 5230 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 5231 Link = GetNextNode (&OldFormSet->FormListHead, Link); 5232 5233 // 5234 // for each question in one form. 5235 // 5236 QuestionLink = GetFirstNode (&Form->StatementListHead); 5237 while (!IsNull (&Form->StatementListHead, QuestionLink)) { 5238 Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); 5239 QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink); 5240 5241 if (!Question->ValueChanged) { 5242 continue; 5243 } 5244 5245 // 5246 // Find the same question in new formset and update the value changed flag. 5247 // 5248 SyncStatusForQuestion (NewFormSet, Question); 5249 } 5250 } 5251 } 5252 5253 /** 5254 Get current setting of Questions. 5255 5256 @param FormSet FormSet data structure. 5257 5258 **/ 5259 VOID 5260 InitializeCurrentSetting ( 5261 IN OUT FORM_BROWSER_FORMSET *FormSet 5262 ) 5263 { 5264 LIST_ENTRY *Link; 5265 FORMSET_STORAGE *Storage; 5266 FORM_BROWSER_FORMSET *OldFormSet; 5267 5268 // 5269 // Try to find pre FormSet in the maintain backup list. 5270 // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList. 5271 // 5272 OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle); 5273 if (OldFormSet != NULL) { 5274 SyncStatusForFormSet (FormSet, OldFormSet); 5275 RemoveEntryList (&OldFormSet->Link); 5276 DestroyFormSet (OldFormSet); 5277 } 5278 InsertTailList (&gBrowserFormSetList, &FormSet->Link); 5279 5280 // 5281 // Extract default from IFR binary for no storage questions. 5282 // 5283 ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForNoStorage, NULL, TRUE, FALSE); 5284 5285 // 5286 // Request current settings from Configuration Driver 5287 // 5288 Link = GetFirstNode (&FormSet->StorageListHead); 5289 while (!IsNull (&FormSet->StorageListHead, Link)) { 5290 Storage = FORMSET_STORAGE_FROM_LINK (Link); 5291 5292 LoadStorage (FormSet, Storage); 5293 5294 Link = GetNextNode (&FormSet->StorageListHead, Link); 5295 } 5296 } 5297 5298 5299 /** 5300 Fetch the Ifr binary data of a FormSet. 5301 5302 @param Handle PackageList Handle 5303 @param FormSetGuid On input, GUID or class GUID of a formset. If not 5304 specified (NULL or zero GUID), take the first 5305 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID 5306 found in package list. 5307 On output, GUID of the formset found(if not NULL). 5308 @param BinaryLength The length of the FormSet IFR binary. 5309 @param BinaryData The buffer designed to receive the FormSet. 5310 5311 @retval EFI_SUCCESS Buffer filled with the requested FormSet. 5312 BufferLength was updated. 5313 @retval EFI_INVALID_PARAMETER The handle is unknown. 5314 @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot 5315 be found with the requested FormId. 5316 5317 **/ 5318 EFI_STATUS 5319 GetIfrBinaryData ( 5320 IN EFI_HII_HANDLE Handle, 5321 IN OUT EFI_GUID *FormSetGuid, 5322 OUT UINTN *BinaryLength, 5323 OUT UINT8 **BinaryData 5324 ) 5325 { 5326 EFI_STATUS Status; 5327 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; 5328 UINTN BufferSize; 5329 UINT8 *Package; 5330 UINT8 *OpCodeData; 5331 UINT32 Offset; 5332 UINT32 Offset2; 5333 UINT32 PackageListLength; 5334 EFI_HII_PACKAGE_HEADER PackageHeader; 5335 UINT8 Index; 5336 UINT8 NumberOfClassGuid; 5337 BOOLEAN ClassGuidMatch; 5338 EFI_GUID *ClassGuid; 5339 EFI_GUID *ComparingGuid; 5340 5341 OpCodeData = NULL; 5342 Package = NULL; 5343 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER)); 5344 5345 // 5346 // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list 5347 // 5348 if (FormSetGuid == NULL) { 5349 ComparingGuid = &gZeroGuid; 5350 } else { 5351 ComparingGuid = FormSetGuid; 5352 } 5353 5354 // 5355 // Get HII PackageList 5356 // 5357 BufferSize = 0; 5358 HiiPackageList = NULL; 5359 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); 5360 if (Status == EFI_BUFFER_TOO_SMALL) { 5361 HiiPackageList = AllocatePool (BufferSize); 5362 ASSERT (HiiPackageList != NULL); 5363 5364 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); 5365 } 5366 if (EFI_ERROR (Status)) { 5367 return Status; 5368 } 5369 ASSERT (HiiPackageList != NULL); 5370 5371 // 5372 // Get Form package from this HII package List 5373 // 5374 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); 5375 Offset2 = 0; 5376 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); 5377 5378 ClassGuidMatch = FALSE; 5379 while (Offset < PackageListLength) { 5380 Package = ((UINT8 *) HiiPackageList) + Offset; 5381 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); 5382 5383 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { 5384 // 5385 // Search FormSet in this Form Package 5386 // 5387 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); 5388 while (Offset2 < PackageHeader.Length) { 5389 OpCodeData = Package + Offset2; 5390 5391 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { 5392 // 5393 // Try to compare against formset GUID 5394 // 5395 if (CompareGuid (FormSetGuid, &gZeroGuid) || 5396 CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { 5397 break; 5398 } 5399 5400 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) { 5401 // 5402 // Try to compare against formset class GUID 5403 // 5404 NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3); 5405 ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET)); 5406 for (Index = 0; Index < NumberOfClassGuid; Index++) { 5407 if (CompareGuid (ComparingGuid, ClassGuid + Index)) { 5408 ClassGuidMatch = TRUE; 5409 break; 5410 } 5411 } 5412 if (ClassGuidMatch) { 5413 break; 5414 } 5415 } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) { 5416 ClassGuidMatch = TRUE; 5417 break; 5418 } 5419 } 5420 5421 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; 5422 } 5423 5424 if (Offset2 < PackageHeader.Length) { 5425 // 5426 // Target formset found 5427 // 5428 break; 5429 } 5430 } 5431 5432 Offset += PackageHeader.Length; 5433 } 5434 5435 if (Offset >= PackageListLength) { 5436 // 5437 // Form package not found in this Package List 5438 // 5439 FreePool (HiiPackageList); 5440 return EFI_NOT_FOUND; 5441 } 5442 5443 if (FormSetGuid != NULL) { 5444 // 5445 // Return the FormSet GUID 5446 // 5447 CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); 5448 } 5449 5450 // 5451 // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes 5452 // in this FormSet; So, here just simply copy the data from start of a FormSet to the end 5453 // of the Form Package. 5454 // 5455 *BinaryLength = PackageHeader.Length - Offset2; 5456 *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); 5457 5458 FreePool (HiiPackageList); 5459 5460 if (*BinaryData == NULL) { 5461 return EFI_OUT_OF_RESOURCES; 5462 } 5463 5464 return EFI_SUCCESS; 5465 } 5466 5467 5468 /** 5469 Initialize the internal data structure of a FormSet. 5470 5471 @param Handle PackageList Handle 5472 @param FormSetGuid On input, GUID or class GUID of a formset. If not 5473 specified (NULL or zero GUID), take the first 5474 FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID 5475 found in package list. 5476 On output, GUID of the formset found(if not NULL). 5477 @param FormSet FormSet data structure. 5478 5479 @retval EFI_SUCCESS The function completed successfully. 5480 @retval EFI_NOT_FOUND The specified FormSet could not be found. 5481 5482 **/ 5483 EFI_STATUS 5484 InitializeFormSet ( 5485 IN EFI_HII_HANDLE Handle, 5486 IN OUT EFI_GUID *FormSetGuid, 5487 OUT FORM_BROWSER_FORMSET *FormSet 5488 ) 5489 { 5490 EFI_STATUS Status; 5491 EFI_HANDLE DriverHandle; 5492 5493 Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); 5494 if (EFI_ERROR (Status)) { 5495 return Status; 5496 } 5497 5498 FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE; 5499 FormSet->HiiHandle = Handle; 5500 CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); 5501 FormSet->QuestionInited = FALSE; 5502 5503 // 5504 // Retrieve ConfigAccess Protocol associated with this HiiPackageList 5505 // 5506 Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); 5507 if (EFI_ERROR (Status)) { 5508 return Status; 5509 } 5510 FormSet->DriverHandle = DriverHandle; 5511 Status = gBS->HandleProtocol ( 5512 DriverHandle, 5513 &gEfiHiiConfigAccessProtocolGuid, 5514 (VOID **) &FormSet->ConfigAccess 5515 ); 5516 if (EFI_ERROR (Status)) { 5517 // 5518 // Configuration Driver don't attach ConfigAccess protocol to its HII package 5519 // list, then there will be no configuration action required 5520 // 5521 FormSet->ConfigAccess = NULL; 5522 } 5523 5524 // 5525 // Parse the IFR binary OpCodes 5526 // 5527 Status = ParseOpCodes (FormSet); 5528 5529 return Status; 5530 } 5531 5532 5533 /** 5534 Save globals used by previous call to SendForm(). SendForm() may be called from 5535 HiiConfigAccess.Callback(), this will cause SendForm() be reentried. 5536 So, save globals of previous call to SendForm() and restore them upon exit. 5537 5538 **/ 5539 VOID 5540 SaveBrowserContext ( 5541 VOID 5542 ) 5543 { 5544 BROWSER_CONTEXT *Context; 5545 FORM_ENTRY_INFO *MenuList; 5546 FORM_BROWSER_FORMSET *FormSet; 5547 5548 gBrowserContextCount++; 5549 if (gBrowserContextCount == 1) { 5550 // 5551 // This is not reentry of SendForm(), no context to save 5552 // 5553 return; 5554 } 5555 5556 Context = AllocatePool (sizeof (BROWSER_CONTEXT)); 5557 ASSERT (Context != NULL); 5558 5559 Context->Signature = BROWSER_CONTEXT_SIGNATURE; 5560 5561 // 5562 // Save FormBrowser context 5563 // 5564 Context->Selection = gCurrentSelection; 5565 Context->ResetRequired = gResetRequired; 5566 Context->FlagReconnect = gFlagReconnect; 5567 Context->CallbackReconnect = gCallbackReconnect; 5568 Context->ExitRequired = gExitRequired; 5569 Context->HiiHandle = mCurrentHiiHandle; 5570 Context->FormId = mCurrentFormId; 5571 CopyGuid (&Context->FormSetGuid, &mCurrentFormSetGuid); 5572 Context->SystemLevelFormSet = mSystemLevelFormSet; 5573 Context->CurFakeQestId = mCurFakeQestId; 5574 Context->HiiPackageListUpdated = mHiiPackageListUpdated; 5575 Context->FinishRetrieveCall = mFinishRetrieveCall; 5576 5577 // 5578 // Save the menu history data. 5579 // 5580 InitializeListHead(&Context->FormHistoryList); 5581 while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) { 5582 MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink); 5583 RemoveEntryList (&MenuList->Link); 5584 5585 InsertTailList(&Context->FormHistoryList, &MenuList->Link); 5586 } 5587 5588 // 5589 // Save formset list. 5590 // 5591 InitializeListHead(&Context->FormSetList); 5592 while (!IsListEmpty (&gBrowserFormSetList)) { 5593 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (gBrowserFormSetList.ForwardLink); 5594 RemoveEntryList (&FormSet->Link); 5595 5596 InsertTailList(&Context->FormSetList, &FormSet->Link); 5597 } 5598 5599 // 5600 // Insert to FormBrowser context list 5601 // 5602 InsertHeadList (&gBrowserContextList, &Context->Link); 5603 } 5604 5605 5606 /** 5607 Restore globals used by previous call to SendForm(). 5608 5609 **/ 5610 VOID 5611 RestoreBrowserContext ( 5612 VOID 5613 ) 5614 { 5615 LIST_ENTRY *Link; 5616 BROWSER_CONTEXT *Context; 5617 FORM_ENTRY_INFO *MenuList; 5618 FORM_BROWSER_FORMSET *FormSet; 5619 5620 ASSERT (gBrowserContextCount != 0); 5621 gBrowserContextCount--; 5622 if (gBrowserContextCount == 0) { 5623 // 5624 // This is not reentry of SendForm(), no context to restore 5625 // 5626 return; 5627 } 5628 5629 ASSERT (!IsListEmpty (&gBrowserContextList)); 5630 5631 Link = GetFirstNode (&gBrowserContextList); 5632 Context = BROWSER_CONTEXT_FROM_LINK (Link); 5633 5634 // 5635 // Restore FormBrowser context 5636 // 5637 gCurrentSelection = Context->Selection; 5638 gResetRequired = Context->ResetRequired; 5639 gFlagReconnect = Context->FlagReconnect; 5640 gCallbackReconnect = Context->CallbackReconnect; 5641 gExitRequired = Context->ExitRequired; 5642 mCurrentHiiHandle = Context->HiiHandle; 5643 mCurrentFormId = Context->FormId; 5644 CopyGuid (&mCurrentFormSetGuid, &Context->FormSetGuid); 5645 mSystemLevelFormSet = Context->SystemLevelFormSet; 5646 mCurFakeQestId = Context->CurFakeQestId; 5647 mHiiPackageListUpdated = Context->HiiPackageListUpdated; 5648 mFinishRetrieveCall = Context->FinishRetrieveCall; 5649 5650 // 5651 // Restore the menu history data. 5652 // 5653 while (!IsListEmpty (&Context->FormHistoryList)) { 5654 MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink); 5655 RemoveEntryList (&MenuList->Link); 5656 5657 InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link); 5658 } 5659 5660 // 5661 // Restore the Formset data. 5662 // 5663 while (!IsListEmpty (&Context->FormSetList)) { 5664 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Context->FormSetList.ForwardLink); 5665 RemoveEntryList (&FormSet->Link); 5666 5667 InsertTailList(&gBrowserFormSetList, &FormSet->Link); 5668 } 5669 5670 // 5671 // Remove from FormBrowser context list 5672 // 5673 RemoveEntryList (&Context->Link); 5674 gBS->FreePool (Context); 5675 } 5676 5677 /** 5678 Find the matched FormSet context in the backup maintain list based on HiiHandle. 5679 5680 @param Handle The Hii Handle. 5681 5682 @return the found FormSet context. If no found, NULL will return. 5683 5684 **/ 5685 FORM_BROWSER_FORMSET * 5686 GetFormSetFromHiiHandle ( 5687 EFI_HII_HANDLE Handle 5688 ) 5689 { 5690 LIST_ENTRY *Link; 5691 FORM_BROWSER_FORMSET *FormSet; 5692 5693 Link = GetFirstNode (&gBrowserFormSetList); 5694 while (!IsNull (&gBrowserFormSetList, Link)) { 5695 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 5696 Link = GetNextNode (&gBrowserFormSetList, Link); 5697 if (!ValidateFormSet(FormSet)) { 5698 continue; 5699 } 5700 if (FormSet->HiiHandle == Handle) { 5701 return FormSet; 5702 } 5703 } 5704 5705 return NULL; 5706 } 5707 5708 /** 5709 Check whether the input HII handle is the FormSet that is being used. 5710 5711 @param Handle The Hii Handle. 5712 5713 @retval TRUE HII handle is being used. 5714 @retval FALSE HII handle is not being used. 5715 5716 **/ 5717 BOOLEAN 5718 IsHiiHandleInBrowserContext ( 5719 EFI_HII_HANDLE Handle 5720 ) 5721 { 5722 LIST_ENTRY *Link; 5723 BROWSER_CONTEXT *Context; 5724 5725 // 5726 // HiiHandle is Current FormSet. 5727 // 5728 if (mCurrentHiiHandle == Handle) { 5729 return TRUE; 5730 } 5731 5732 // 5733 // Check whether HiiHandle is in BrowserContext. 5734 // 5735 Link = GetFirstNode (&gBrowserContextList); 5736 while (!IsNull (&gBrowserContextList, Link)) { 5737 Context = BROWSER_CONTEXT_FROM_LINK (Link); 5738 if (Context->HiiHandle == Handle) { 5739 // 5740 // HiiHandle is in BrowserContext 5741 // 5742 return TRUE; 5743 } 5744 Link = GetNextNode (&gBrowserContextList, Link); 5745 } 5746 5747 return FALSE; 5748 } 5749 5750 /** 5751 Perform Password check. 5752 Passwork may be encrypted by driver that requires the specific check. 5753 5754 @param Form Form where Password Statement is in. 5755 @param Statement Password statement 5756 @param PasswordString Password string to be checked. It may be NULL. 5757 NULL means to restore password. 5758 "" string can be used to checked whether old password does exist. 5759 5760 @return Status Status of Password check. 5761 **/ 5762 EFI_STATUS 5763 EFIAPI 5764 PasswordCheck ( 5765 IN FORM_DISPLAY_ENGINE_FORM *Form, 5766 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement, 5767 IN EFI_STRING PasswordString OPTIONAL 5768 ) 5769 { 5770 EFI_STATUS Status; 5771 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; 5772 EFI_BROWSER_ACTION_REQUEST ActionRequest; 5773 EFI_IFR_TYPE_VALUE IfrTypeValue; 5774 FORM_BROWSER_STATEMENT *Question; 5775 5776 ConfigAccess = gCurrentSelection->FormSet->ConfigAccess; 5777 Question = GetBrowserStatement(Statement); 5778 ASSERT (Question != NULL); 5779 5780 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) { 5781 if (ConfigAccess == NULL) { 5782 return EFI_UNSUPPORTED; 5783 } 5784 } else { 5785 if (PasswordString == NULL) { 5786 return EFI_SUCCESS; 5787 } 5788 5789 // 5790 // Check whether has preexisted password. 5791 // 5792 if (PasswordString[0] == 0) { 5793 if (*((CHAR16 *) Question->BufferValue) == 0) { 5794 return EFI_SUCCESS; 5795 } else { 5796 return EFI_NOT_READY; 5797 } 5798 } 5799 5800 // 5801 // Check whether the input password is same as preexisted password. 5802 // 5803 if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) { 5804 return EFI_SUCCESS; 5805 } else { 5806 return EFI_NOT_READY; 5807 } 5808 } 5809 5810 // 5811 // Prepare password string in HII database 5812 // 5813 if (PasswordString != NULL) { 5814 IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle); 5815 } else { 5816 IfrTypeValue.string = 0; 5817 } 5818 5819 // 5820 // Send password to Configuration Driver for validation 5821 // 5822 Status = ConfigAccess->Callback ( 5823 ConfigAccess, 5824 EFI_BROWSER_ACTION_CHANGING, 5825 Question->QuestionId, 5826 Question->HiiValue.Type, 5827 &IfrTypeValue, 5828 &ActionRequest 5829 ); 5830 5831 // 5832 // Remove password string from HII database 5833 // 5834 if (PasswordString != NULL) { 5835 DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle); 5836 } 5837 5838 return Status; 5839 } 5840 5841 /** 5842 Find the registered HotKey based on KeyData. 5843 5844 @param[in] KeyData A pointer to a buffer that describes the keystroke 5845 information for the hot key. 5846 5847 @return The registered HotKey context. If no found, NULL will return. 5848 **/ 5849 BROWSER_HOT_KEY * 5850 GetHotKeyFromRegisterList ( 5851 IN EFI_INPUT_KEY *KeyData 5852 ) 5853 { 5854 LIST_ENTRY *Link; 5855 BROWSER_HOT_KEY *HotKey; 5856 5857 Link = GetFirstNode (&gBrowserHotKeyList); 5858 while (!IsNull (&gBrowserHotKeyList, Link)) { 5859 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); 5860 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) { 5861 return HotKey; 5862 } 5863 Link = GetNextNode (&gBrowserHotKeyList, Link); 5864 } 5865 5866 return NULL; 5867 } 5868 5869 /** 5870 Configure what scope the hot key will impact. 5871 All hot keys have the same scope. The mixed hot keys with the different level are not supported. 5872 If no scope is set, the default scope will be FormSet level. 5873 After all registered hot keys are removed, previous Scope can reset to another level. 5874 5875 @param[in] Scope Scope level to be set. 5876 5877 @retval EFI_SUCCESS Scope is set correctly. 5878 @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. 5879 @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. 5880 5881 **/ 5882 EFI_STATUS 5883 EFIAPI 5884 SetScope ( 5885 IN BROWSER_SETTING_SCOPE Scope 5886 ) 5887 { 5888 if (Scope >= MaxLevel) { 5889 return EFI_INVALID_PARAMETER; 5890 } 5891 5892 // 5893 // When no hot key registered in system or on the first setting, 5894 // Scope can be set. 5895 // 5896 if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) { 5897 gBrowserSettingScope = Scope; 5898 mBrowserScopeFirstSet = FALSE; 5899 } else if (Scope != gBrowserSettingScope) { 5900 return EFI_UNSUPPORTED; 5901 } 5902 5903 return EFI_SUCCESS; 5904 } 5905 5906 /** 5907 Register the hot key with its browser action, or unregistered the hot key. 5908 Only support hot key that is not printable character (control key, function key, etc.). 5909 If the action value is zero, the hot key will be unregistered if it has been registered. 5910 If the same hot key has been registered, the new action and help string will override the previous ones. 5911 5912 @param[in] KeyData A pointer to a buffer that describes the keystroke 5913 information for the hot key. Its type is EFI_INPUT_KEY to 5914 be supported by all ConsoleIn devices. 5915 @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. 5916 @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. 5917 @param[in] HelpString Help string that describes the hot key information. 5918 Its value may be NULL for the unregistered hot key. 5919 5920 @retval EFI_SUCCESS Hot key is registered or unregistered. 5921 @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register. 5922 @retval EFI_NOT_FOUND KeyData is not found to be unregistered. 5923 @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. 5924 @retval EFI_ALREADY_STARTED Key already been registered for one hot key. 5925 **/ 5926 EFI_STATUS 5927 EFIAPI 5928 RegisterHotKey ( 5929 IN EFI_INPUT_KEY *KeyData, 5930 IN UINT32 Action, 5931 IN UINT16 DefaultId, 5932 IN EFI_STRING HelpString OPTIONAL 5933 ) 5934 { 5935 BROWSER_HOT_KEY *HotKey; 5936 5937 // 5938 // Check input parameters. 5939 // 5940 if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || 5941 (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) { 5942 return EFI_INVALID_PARAMETER; 5943 } 5944 5945 // 5946 // Check whether the input KeyData is in BrowserHotKeyList. 5947 // 5948 HotKey = GetHotKeyFromRegisterList (KeyData); 5949 5950 // 5951 // Unregister HotKey 5952 // 5953 if (Action == BROWSER_ACTION_UNREGISTER) { 5954 if (HotKey != NULL) { 5955 // 5956 // The registered HotKey is found. 5957 // Remove it from List, and free its resource. 5958 // 5959 RemoveEntryList (&HotKey->Link); 5960 FreePool (HotKey->KeyData); 5961 FreePool (HotKey->HelpString); 5962 return EFI_SUCCESS; 5963 } else { 5964 // 5965 // The registered HotKey is not found. 5966 // 5967 return EFI_NOT_FOUND; 5968 } 5969 } 5970 5971 if (HotKey != NULL) { 5972 return EFI_ALREADY_STARTED; 5973 } 5974 5975 // 5976 // Create new Key, and add it into List. 5977 // 5978 HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY)); 5979 ASSERT (HotKey != NULL); 5980 HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE; 5981 HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData); 5982 InsertTailList (&gBrowserHotKeyList, &HotKey->Link); 5983 5984 // 5985 // Fill HotKey information. 5986 // 5987 HotKey->Action = Action; 5988 HotKey->DefaultId = DefaultId; 5989 if (HotKey->HelpString != NULL) { 5990 FreePool (HotKey->HelpString); 5991 } 5992 HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString); 5993 5994 return EFI_SUCCESS; 5995 } 5996 5997 /** 5998 Register Exit handler function. 5999 When more than one handler function is registered, the latter one will override the previous one. 6000 When NULL handler is specified, the previous Exit handler will be unregistered. 6001 6002 @param[in] Handler Pointer to handler function. 6003 6004 **/ 6005 VOID 6006 EFIAPI 6007 RegiserExitHandler ( 6008 IN EXIT_HANDLER Handler 6009 ) 6010 { 6011 ExitHandlerFunction = Handler; 6012 return; 6013 } 6014 6015 /** 6016 Check whether the browser data has been modified. 6017 6018 @retval TRUE Browser data is modified. 6019 @retval FALSE No browser data is modified. 6020 6021 **/ 6022 BOOLEAN 6023 EFIAPI 6024 IsBrowserDataModified ( 6025 VOID 6026 ) 6027 { 6028 LIST_ENTRY *Link; 6029 FORM_BROWSER_FORMSET *FormSet; 6030 6031 switch (gBrowserSettingScope) { 6032 case FormLevel: 6033 if (gCurrentSelection == NULL) { 6034 return FALSE; 6035 } 6036 return IsNvUpdateRequiredForForm (gCurrentSelection->Form); 6037 6038 case FormSetLevel: 6039 if (gCurrentSelection == NULL) { 6040 return FALSE; 6041 } 6042 return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet); 6043 6044 case SystemLevel: 6045 Link = GetFirstNode (&gBrowserFormSetList); 6046 while (!IsNull (&gBrowserFormSetList, Link)) { 6047 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 6048 if (!ValidateFormSet(FormSet)) { 6049 continue; 6050 } 6051 6052 if (IsNvUpdateRequiredForFormSet (FormSet)) { 6053 return TRUE; 6054 } 6055 Link = GetNextNode (&gBrowserFormSetList, Link); 6056 } 6057 return FALSE; 6058 6059 default: 6060 return FALSE; 6061 } 6062 } 6063 6064 /** 6065 Execute the action requested by the Action parameter. 6066 6067 @param[in] Action Execute the request action. 6068 @param[in] DefaultId The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT. 6069 6070 @retval EFI_SUCCESS Execute the request action succss. 6071 @retval EFI_INVALID_PARAMETER The input action value is invalid. 6072 6073 **/ 6074 EFI_STATUS 6075 EFIAPI 6076 ExecuteAction ( 6077 IN UINT32 Action, 6078 IN UINT16 DefaultId 6079 ) 6080 { 6081 EFI_STATUS Status; 6082 FORM_BROWSER_FORMSET *FormSet; 6083 FORM_BROWSER_FORM *Form; 6084 6085 if (gBrowserSettingScope < SystemLevel && gCurrentSelection == NULL) { 6086 return EFI_NOT_READY; 6087 } 6088 6089 Status = EFI_SUCCESS; 6090 FormSet = NULL; 6091 Form = NULL; 6092 if (gBrowserSettingScope < SystemLevel) { 6093 FormSet = gCurrentSelection->FormSet; 6094 Form = gCurrentSelection->Form; 6095 } 6096 6097 // 6098 // Executet the discard action. 6099 // 6100 if ((Action & BROWSER_ACTION_DISCARD) != 0) { 6101 Status = DiscardForm (FormSet, Form, gBrowserSettingScope); 6102 if (EFI_ERROR (Status)) { 6103 return Status; 6104 } 6105 } 6106 6107 // 6108 // Executet the difault action. 6109 // 6110 if ((Action & BROWSER_ACTION_DEFAULT) != 0) { 6111 Status = ExtractDefault (FormSet, Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE); 6112 if (EFI_ERROR (Status)) { 6113 return Status; 6114 } 6115 UpdateStatementStatus (FormSet, Form, gBrowserSettingScope); 6116 } 6117 6118 // 6119 // Executet the submit action. 6120 // 6121 if ((Action & BROWSER_ACTION_SUBMIT) != 0) { 6122 Status = SubmitForm (FormSet, Form, gBrowserSettingScope); 6123 if (EFI_ERROR (Status)) { 6124 return Status; 6125 } 6126 } 6127 6128 // 6129 // Executet the reset action. 6130 // 6131 if ((Action & BROWSER_ACTION_RESET) != 0) { 6132 gResetRequired = TRUE; 6133 } 6134 6135 // 6136 // Executet the exit action. 6137 // 6138 if ((Action & BROWSER_ACTION_EXIT) != 0) { 6139 DiscardForm (FormSet, Form, gBrowserSettingScope); 6140 if (gBrowserSettingScope == SystemLevel) { 6141 if (ExitHandlerFunction != NULL) { 6142 ExitHandlerFunction (); 6143 } 6144 } 6145 6146 gExitRequired = TRUE; 6147 } 6148 6149 return Status; 6150 } 6151 6152 /** 6153 Create reminder to let user to choose save or discard the changed browser data. 6154 Caller can use it to actively check the changed browser data. 6155 6156 @retval BROWSER_NO_CHANGES No browser data is changed. 6157 @retval BROWSER_SAVE_CHANGES The changed browser data is saved. 6158 @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. 6159 @retval BROWSER_KEEP_CURRENT Browser keep current changes. 6160 6161 **/ 6162 UINT32 6163 EFIAPI 6164 SaveReminder ( 6165 VOID 6166 ) 6167 { 6168 LIST_ENTRY *Link; 6169 FORM_BROWSER_FORMSET *FormSet; 6170 BOOLEAN IsDataChanged; 6171 UINT32 DataSavedAction; 6172 UINT32 ConfirmRet; 6173 6174 DataSavedAction = BROWSER_NO_CHANGES; 6175 IsDataChanged = FALSE; 6176 Link = GetFirstNode (&gBrowserFormSetList); 6177 while (!IsNull (&gBrowserFormSetList, Link)) { 6178 FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); 6179 Link = GetNextNode (&gBrowserFormSetList, Link); 6180 if (!ValidateFormSet(FormSet)) { 6181 continue; 6182 } 6183 if (IsNvUpdateRequiredForFormSet (FormSet)) { 6184 IsDataChanged = TRUE; 6185 break; 6186 } 6187 } 6188 6189 // 6190 // No data is changed. No save is required. 6191 // 6192 if (!IsDataChanged) { 6193 return DataSavedAction; 6194 } 6195 6196 // 6197 // If data is changed, prompt user to save or discard it. 6198 // 6199 do { 6200 ConfirmRet = (UINT32) mFormDisplay->ConfirmDataChange(); 6201 6202 if (ConfirmRet == BROWSER_ACTION_SUBMIT) { 6203 SubmitForm (NULL, NULL, SystemLevel); 6204 DataSavedAction = BROWSER_SAVE_CHANGES; 6205 break; 6206 } else if (ConfirmRet == BROWSER_ACTION_DISCARD) { 6207 DiscardForm (NULL, NULL, SystemLevel); 6208 DataSavedAction = BROWSER_DISCARD_CHANGES; 6209 break; 6210 } else if (ConfirmRet == BROWSER_ACTION_NONE) { 6211 DataSavedAction = BROWSER_KEEP_CURRENT; 6212 break; 6213 } 6214 } while (1); 6215 6216 return DataSavedAction; 6217 } 6218 6219 /** 6220 Check whether the Reset Required for the browser 6221 6222 @retval TRUE Browser required to reset after exit. 6223 @retval FALSE Browser not need to reset after exit. 6224 6225 **/ 6226 BOOLEAN 6227 EFIAPI 6228 IsResetRequired ( 6229 VOID 6230 ) 6231 { 6232 return gResetRequired; 6233 } 6234 6235