1/** @file 2 Implement ReadOnly Variable Services required by PEIM and install 3 PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space. 4 5Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 6This program and the accompanying materials 7are licensed and made available under the terms and conditions of the BSD License 8which accompanies this distribution. The full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16 17#include "Variable.h" 18 19// 20// Module globals 21// 22EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = { 23 PeiGetVariable, 24 PeiGetNextVariableName 25}; 26 27EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = { 28 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 29 &gEfiPeiReadOnlyVariable2PpiGuid, 30 &mVariablePpi 31}; 32 33 34/** 35 Provide the functionality of the variable services. 36 37 @param FileHandle Handle of the file being invoked. 38 Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile(). 39 @param PeiServices General purpose services available to every PEIM. 40 41 @retval EFI_SUCCESS If the interface could be successfully installed 42 @retval Others Returned from PeiServicesInstallPpi() 43**/ 44EFI_STATUS 45EFIAPI 46PeimInitializeVariableServices ( 47 IN EFI_PEI_FILE_HANDLE FileHandle, 48 IN CONST EFI_PEI_SERVICES **PeiServices 49 ) 50{ 51 return PeiServicesInstallPpi (&mPpiListVariable); 52} 53 54/** 55 56 Gets the pointer to the first variable header in given variable store area. 57 58 @param VarStoreHeader Pointer to the Variable Store Header. 59 60 @return Pointer to the first variable header 61 62**/ 63VARIABLE_HEADER * 64GetStartPointer ( 65 IN VARIABLE_STORE_HEADER *VarStoreHeader 66 ) 67{ 68 // 69 // The end of variable store 70 // 71 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1); 72} 73 74 75/** 76 This code gets the pointer to the last variable memory pointer byte. 77 78 @param VarStoreHeader Pointer to the Variable Store Header. 79 80 @return VARIABLE_HEADER* pointer to last unavailable Variable Header. 81 82**/ 83VARIABLE_HEADER * 84GetEndPointer ( 85 IN VARIABLE_STORE_HEADER *VarStoreHeader 86 ) 87{ 88 // 89 // The end of variable store 90 // 91 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size); 92} 93 94 95/** 96 This code checks if variable header is valid or not. 97 98 @param Variable Pointer to the Variable Header. 99 100 @retval TRUE Variable header is valid. 101 @retval FALSE Variable header is not valid. 102 103**/ 104BOOLEAN 105IsValidVariableHeader ( 106 IN VARIABLE_HEADER *Variable 107 ) 108{ 109 if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) { 110 return FALSE; 111 } 112 113 return TRUE; 114} 115 116/** 117 This code gets the size of variable header. 118 119 @param AuthFlag Authenticated variable flag. 120 121 @return Size of variable header in bytes in type UINTN. 122 123**/ 124UINTN 125GetVariableHeaderSize ( 126 IN BOOLEAN AuthFlag 127 ) 128{ 129 UINTN Value; 130 131 if (AuthFlag) { 132 Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); 133 } else { 134 Value = sizeof (VARIABLE_HEADER); 135 } 136 137 return Value; 138} 139 140/** 141 This code gets the size of name of variable. 142 143 @param Variable Pointer to the Variable Header. 144 @param AuthFlag Authenticated variable flag. 145 146 @return Size of variable in bytes in type UINTN. 147 148**/ 149UINTN 150NameSizeOfVariable ( 151 IN VARIABLE_HEADER *Variable, 152 IN BOOLEAN AuthFlag 153 ) 154{ 155 AUTHENTICATED_VARIABLE_HEADER *AuthVariable; 156 157 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; 158 if (AuthFlag) { 159 if (AuthVariable->State == (UINT8) (-1) || 160 AuthVariable->DataSize == (UINT32) (-1) || 161 AuthVariable->NameSize == (UINT32) (-1) || 162 AuthVariable->Attributes == (UINT32) (-1)) { 163 return 0; 164 } 165 return (UINTN) AuthVariable->NameSize; 166 } else { 167 if (Variable->State == (UINT8) (-1) || 168 Variable->DataSize == (UINT32) (-1) || 169 Variable->NameSize == (UINT32) (-1) || 170 Variable->Attributes == (UINT32) (-1)) { 171 return 0; 172 } 173 return (UINTN) Variable->NameSize; 174 } 175} 176 177 178/** 179 This code gets the size of data of variable. 180 181 @param Variable Pointer to the Variable Header. 182 @param AuthFlag Authenticated variable flag. 183 184 @return Size of variable in bytes in type UINTN. 185 186**/ 187UINTN 188DataSizeOfVariable ( 189 IN VARIABLE_HEADER *Variable, 190 IN BOOLEAN AuthFlag 191 ) 192{ 193 AUTHENTICATED_VARIABLE_HEADER *AuthVariable; 194 195 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; 196 if (AuthFlag) { 197 if (AuthVariable->State == (UINT8) (-1) || 198 AuthVariable->DataSize == (UINT32) (-1) || 199 AuthVariable->NameSize == (UINT32) (-1) || 200 AuthVariable->Attributes == (UINT32) (-1)) { 201 return 0; 202 } 203 return (UINTN) AuthVariable->DataSize; 204 } else { 205 if (Variable->State == (UINT8) (-1) || 206 Variable->DataSize == (UINT32) (-1) || 207 Variable->NameSize == (UINT32) (-1) || 208 Variable->Attributes == (UINT32) (-1)) { 209 return 0; 210 } 211 return (UINTN) Variable->DataSize; 212 } 213} 214 215/** 216 This code gets the pointer to the variable name. 217 218 @param Variable Pointer to the Variable Header. 219 @param AuthFlag Authenticated variable flag. 220 221 @return A CHAR16* pointer to Variable Name. 222 223**/ 224CHAR16 * 225GetVariableNamePtr ( 226 IN VARIABLE_HEADER *Variable, 227 IN BOOLEAN AuthFlag 228 ) 229{ 230 return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize (AuthFlag)); 231} 232 233/** 234 This code gets the pointer to the variable guid. 235 236 @param Variable Pointer to the Variable Header. 237 @param AuthFlag Authenticated variable flag. 238 239 @return A EFI_GUID* pointer to Vendor Guid. 240 241**/ 242EFI_GUID * 243GetVendorGuidPtr ( 244 IN VARIABLE_HEADER *Variable, 245 IN BOOLEAN AuthFlag 246 ) 247{ 248 AUTHENTICATED_VARIABLE_HEADER *AuthVariable; 249 250 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable; 251 if (AuthFlag) { 252 return &AuthVariable->VendorGuid; 253 } else { 254 return &Variable->VendorGuid; 255 } 256} 257 258/** 259 This code gets the pointer to the variable data. 260 261 @param Variable Pointer to the Variable Header. 262 @param VariableHeader Pointer to the Variable Header that has consecutive content. 263 @param AuthFlag Authenticated variable flag. 264 265 @return A UINT8* pointer to Variable Data. 266 267**/ 268UINT8 * 269GetVariableDataPtr ( 270 IN VARIABLE_HEADER *Variable, 271 IN VARIABLE_HEADER *VariableHeader, 272 IN BOOLEAN AuthFlag 273 ) 274{ 275 UINTN Value; 276 277 // 278 // Be careful about pad size for alignment 279 // 280 Value = (UINTN) GetVariableNamePtr (Variable, AuthFlag); 281 Value += NameSizeOfVariable (VariableHeader, AuthFlag); 282 Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag)); 283 284 return (UINT8 *) Value; 285} 286 287 288/** 289 This code gets the pointer to the next variable header. 290 291 @param StoreInfo Pointer to variable store info structure. 292 @param Variable Pointer to the Variable Header. 293 @param VariableHeader Pointer to the Variable Header that has consecutive content. 294 295 @return A VARIABLE_HEADER* pointer to next variable header. 296 297**/ 298VARIABLE_HEADER * 299GetNextVariablePtr ( 300 IN VARIABLE_STORE_INFO *StoreInfo, 301 IN VARIABLE_HEADER *Variable, 302 IN VARIABLE_HEADER *VariableHeader 303 ) 304{ 305 EFI_PHYSICAL_ADDRESS TargetAddress; 306 EFI_PHYSICAL_ADDRESS SpareAddress; 307 UINTN Value; 308 309 Value = (UINTN) GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag); 310 Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag); 311 Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag)); 312 // 313 // Be careful about pad size for alignment 314 // 315 Value = HEADER_ALIGN (Value); 316 317 if (StoreInfo->FtwLastWriteData != NULL) { 318 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; 319 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; 320 if (((UINTN) Variable < (UINTN) TargetAddress) && (Value >= (UINTN) TargetAddress)) { 321 // 322 // Next variable is in spare block. 323 // 324 Value = (UINTN) SpareAddress + (Value - (UINTN) TargetAddress); 325 } 326 } 327 328 return (VARIABLE_HEADER *) Value; 329} 330 331/** 332 Get variable store status. 333 334 @param VarStoreHeader Pointer to the Variable Store Header. 335 336 @retval EfiRaw Variable store is raw 337 @retval EfiValid Variable store is valid 338 @retval EfiInvalid Variable store is invalid 339 340**/ 341VARIABLE_STORE_STATUS 342GetVariableStoreStatus ( 343 IN VARIABLE_STORE_HEADER *VarStoreHeader 344 ) 345{ 346 if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || 347 CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && 348 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && 349 VarStoreHeader->State == VARIABLE_STORE_HEALTHY 350 ) { 351 352 return EfiValid; 353 } 354 355 if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff && 356 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff && 357 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff && 358 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff && 359 VarStoreHeader->Size == 0xffffffff && 360 VarStoreHeader->Format == 0xff && 361 VarStoreHeader->State == 0xff 362 ) { 363 364 return EfiRaw; 365 } else { 366 return EfiInvalid; 367 } 368} 369 370/** 371 Compare two variable names, one of them may be inconsecutive. 372 373 @param StoreInfo Pointer to variable store info structure. 374 @param Name1 Pointer to one variable name. 375 @param Name2 Pointer to another variable name. 376 @param NameSize Variable name size. 377 378 @retval TRUE Name1 and Name2 are identical. 379 @retval FALSE Name1 and Name2 are not identical. 380 381**/ 382BOOLEAN 383CompareVariableName ( 384 IN VARIABLE_STORE_INFO *StoreInfo, 385 IN CONST CHAR16 *Name1, 386 IN CONST CHAR16 *Name2, 387 IN UINTN NameSize 388 ) 389{ 390 EFI_PHYSICAL_ADDRESS TargetAddress; 391 EFI_PHYSICAL_ADDRESS SpareAddress; 392 UINTN PartialNameSize; 393 394 if (StoreInfo->FtwLastWriteData != NULL) { 395 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; 396 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; 397 if (((UINTN) Name1 < (UINTN) TargetAddress) && (((UINTN) Name1 + NameSize) > (UINTN) TargetAddress)) { 398 // 399 // Name1 is inconsecutive. 400 // 401 PartialNameSize = (UINTN) TargetAddress - (UINTN) Name1; 402 // 403 // Partial content is in NV storage. 404 // 405 if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, PartialNameSize) == 0) { 406 // 407 // Another partial content is in spare block. 408 // 409 if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) { 410 return TRUE; 411 } 412 } 413 return FALSE; 414 } else if (((UINTN) Name2 < (UINTN) TargetAddress) && (((UINTN) Name2 + NameSize) > (UINTN) TargetAddress)) { 415 // 416 // Name2 is inconsecutive. 417 // 418 PartialNameSize = (UINTN) TargetAddress - (UINTN) Name2; 419 // 420 // Partial content is in NV storage. 421 // 422 if (CompareMem ((UINT8 *) Name2, (UINT8 *) Name1, PartialNameSize) == 0) { 423 // 424 // Another partial content is in spare block. 425 // 426 if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) { 427 return TRUE; 428 } 429 } 430 return FALSE; 431 } 432 } 433 434 // 435 // Both Name1 and Name2 are consecutive. 436 // 437 if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) { 438 return TRUE; 439 } 440 return FALSE; 441} 442 443/** 444 This function compares a variable with variable entries in database. 445 446 @param StoreInfo Pointer to variable store info structure. 447 @param Variable Pointer to the variable in our database 448 @param VariableHeader Pointer to the Variable Header that has consecutive content. 449 @param VariableName Name of the variable to compare to 'Variable' 450 @param VendorGuid GUID of the variable to compare to 'Variable' 451 @param PtrTrack Variable Track Pointer structure that contains Variable Information. 452 453 @retval EFI_SUCCESS Found match variable 454 @retval EFI_NOT_FOUND Variable not found 455 456**/ 457EFI_STATUS 458CompareWithValidVariable ( 459 IN VARIABLE_STORE_INFO *StoreInfo, 460 IN VARIABLE_HEADER *Variable, 461 IN VARIABLE_HEADER *VariableHeader, 462 IN CONST CHAR16 *VariableName, 463 IN CONST EFI_GUID *VendorGuid, 464 OUT VARIABLE_POINTER_TRACK *PtrTrack 465 ) 466{ 467 VOID *Point; 468 EFI_GUID *TempVendorGuid; 469 470 TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag); 471 472 if (VariableName[0] == 0) { 473 PtrTrack->CurrPtr = Variable; 474 return EFI_SUCCESS; 475 } else { 476 // 477 // Don't use CompareGuid function here for performance reasons. 478 // Instead we compare the GUID a UINT32 at a time and branch 479 // on the first failed comparison. 480 // 481 if ((((INT32 *) VendorGuid)[0] == ((INT32 *) TempVendorGuid)[0]) && 482 (((INT32 *) VendorGuid)[1] == ((INT32 *) TempVendorGuid)[1]) && 483 (((INT32 *) VendorGuid)[2] == ((INT32 *) TempVendorGuid)[2]) && 484 (((INT32 *) VendorGuid)[3] == ((INT32 *) TempVendorGuid)[3]) 485 ) { 486 ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0); 487 Point = (VOID *) GetVariableNamePtr (Variable, StoreInfo->AuthFlag); 488 if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) { 489 PtrTrack->CurrPtr = Variable; 490 return EFI_SUCCESS; 491 } 492 } 493 } 494 495 return EFI_NOT_FOUND; 496} 497 498/** 499 Return the variable store header and the store info based on the Index. 500 501 @param Type The type of the variable store. 502 @param StoreInfo Return the store info. 503 504 @return Pointer to the variable store header. 505**/ 506VARIABLE_STORE_HEADER * 507GetVariableStore ( 508 IN VARIABLE_STORE_TYPE Type, 509 OUT VARIABLE_STORE_INFO *StoreInfo 510 ) 511{ 512 EFI_HOB_GUID_TYPE *GuidHob; 513 EFI_FIRMWARE_VOLUME_HEADER *FvHeader; 514 VARIABLE_STORE_HEADER *VariableStoreHeader; 515 EFI_PHYSICAL_ADDRESS NvStorageBase; 516 UINT32 NvStorageSize; 517 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; 518 UINT32 BackUpOffset; 519 520 StoreInfo->IndexTable = NULL; 521 StoreInfo->FtwLastWriteData = NULL; 522 StoreInfo->AuthFlag = FALSE; 523 VariableStoreHeader = NULL; 524 switch (Type) { 525 case VariableStoreTypeHob: 526 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); 527 if (GuidHob != NULL) { 528 VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob); 529 StoreInfo->AuthFlag = TRUE; 530 } else { 531 GuidHob = GetFirstGuidHob (&gEfiVariableGuid); 532 if (GuidHob != NULL) { 533 VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob); 534 StoreInfo->AuthFlag = FALSE; 535 } 536 } 537 break; 538 539 case VariableStoreTypeNv: 540 if (GetBootModeHob () != BOOT_IN_RECOVERY_MODE) { 541 // 542 // The content of NV storage for variable is not reliable in recovery boot mode. 543 // 544 545 NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); 546 NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? 547 PcdGet64 (PcdFlashNvStorageVariableBase64) : 548 PcdGet32 (PcdFlashNvStorageVariableBase) 549 ); 550 // 551 // First let FvHeader point to NV storage base. 552 // 553 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase; 554 555 // 556 // Check the FTW last write data hob. 557 // 558 BackUpOffset = 0; 559 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); 560 if (GuidHob != NULL) { 561 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob); 562 if (FtwLastWriteData->TargetAddress == NvStorageBase) { 563 // 564 // Let FvHeader point to spare block. 565 // 566 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress; 567 DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress)); 568 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { 569 StoreInfo->FtwLastWriteData = FtwLastWriteData; 570 // 571 // Flash NV storage from the offset is backed up in spare block. 572 // 573 BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); 574 DEBUG ((EFI_D_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress)); 575 // 576 // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base. 577 // 578 } 579 } 580 581 // 582 // Check if the Firmware Volume is not corrupted 583 // 584 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { 585 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n")); 586 break; 587 } 588 589 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength); 590 591 StoreInfo->AuthFlag = (BOOLEAN) (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)); 592 593 GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); 594 if (GuidHob != NULL) { 595 StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob); 596 } else { 597 // 598 // If it's the first time to access variable region in flash, create a guid hob to record 599 // VAR_ADDED type variable info. 600 // Note that as the resource of PEI phase is limited, only store the limited number of 601 // VAR_ADDED type variables to reduce access time. 602 // 603 StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); 604 StoreInfo->IndexTable->Length = 0; 605 StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader); 606 StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader); 607 StoreInfo->IndexTable->GoneThrough = 0; 608 } 609 } 610 break; 611 612 default: 613 ASSERT (FALSE); 614 break; 615 } 616 617 StoreInfo->VariableStoreHeader = VariableStoreHeader; 618 return VariableStoreHeader; 619} 620 621/** 622 Get variable header that has consecutive content. 623 624 @param StoreInfo Pointer to variable store info structure. 625 @param Variable Pointer to the Variable Header. 626 @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content. 627 628 @retval TRUE Variable header is valid. 629 @retval FALSE Variable header is not valid. 630 631**/ 632BOOLEAN 633GetVariableHeader ( 634 IN VARIABLE_STORE_INFO *StoreInfo, 635 IN VARIABLE_HEADER *Variable, 636 OUT VARIABLE_HEADER **VariableHeader 637 ) 638{ 639 EFI_PHYSICAL_ADDRESS TargetAddress; 640 EFI_PHYSICAL_ADDRESS SpareAddress; 641 EFI_HOB_GUID_TYPE *GuidHob; 642 UINTN PartialHeaderSize; 643 644 if (Variable == NULL) { 645 return FALSE; 646 } 647 648 // 649 // First assume variable header pointed by Variable is consecutive. 650 // 651 *VariableHeader = Variable; 652 653 if (StoreInfo->FtwLastWriteData != NULL) { 654 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; 655 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; 656 if (((UINTN) Variable > (UINTN) SpareAddress) && 657 (((UINTN) Variable - (UINTN) SpareAddress + (UINTN) TargetAddress) >= (UINTN) GetEndPointer (StoreInfo->VariableStoreHeader))) { 658 // 659 // Reach the end of variable store. 660 // 661 return FALSE; 662 } 663 if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN) TargetAddress)) { 664 // 665 // Variable header pointed by Variable is inconsecutive, 666 // create a guid hob to combine the two partial variable header content together. 667 // 668 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid); 669 if (GuidHob != NULL) { 670 *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob); 671 } else { 672 *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag)); 673 PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable; 674 // 675 // Partial content is in NV storage. 676 // 677 CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize); 678 // 679 // Another partial content is in spare block. 680 // 681 CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize); 682 } 683 } 684 } else { 685 if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) { 686 // 687 // Reach the end of variable store. 688 // 689 return FALSE; 690 } 691 } 692 693 return IsValidVariableHeader (*VariableHeader); 694} 695 696/** 697 Get variable name or data to output buffer. 698 699 @param StoreInfo Pointer to variable store info structure. 700 @param NameOrData Pointer to the variable name/data that may be inconsecutive. 701 @param Size Variable name/data size. 702 @param Buffer Pointer to output buffer to hold the variable name/data. 703 704**/ 705VOID 706GetVariableNameOrData ( 707 IN VARIABLE_STORE_INFO *StoreInfo, 708 IN UINT8 *NameOrData, 709 IN UINTN Size, 710 OUT UINT8 *Buffer 711 ) 712{ 713 EFI_PHYSICAL_ADDRESS TargetAddress; 714 EFI_PHYSICAL_ADDRESS SpareAddress; 715 UINTN PartialSize; 716 717 if (StoreInfo->FtwLastWriteData != NULL) { 718 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; 719 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; 720 if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) { 721 // 722 // Variable name/data is inconsecutive. 723 // 724 PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData; 725 // 726 // Partial content is in NV storage. 727 // 728 CopyMem (Buffer, NameOrData, PartialSize); 729 // 730 // Another partial content is in spare block. 731 // 732 CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize); 733 return; 734 } 735 } 736 737 // 738 // Variable name/data is consecutive. 739 // 740 CopyMem (Buffer, NameOrData, Size); 741} 742 743/** 744 Find the variable in the specified variable store. 745 746 @param StoreInfo Pointer to the store info structure. 747 @param VariableName Name of the variable to be found 748 @param VendorGuid Vendor GUID to be found. 749 @param PtrTrack Variable Track Pointer structure that contains Variable Information. 750 751 @retval EFI_SUCCESS Variable found successfully 752 @retval EFI_NOT_FOUND Variable not found 753 @retval EFI_INVALID_PARAMETER Invalid variable name 754 755**/ 756EFI_STATUS 757FindVariableEx ( 758 IN VARIABLE_STORE_INFO *StoreInfo, 759 IN CONST CHAR16 *VariableName, 760 IN CONST EFI_GUID *VendorGuid, 761 OUT VARIABLE_POINTER_TRACK *PtrTrack 762 ) 763{ 764 VARIABLE_HEADER *Variable; 765 VARIABLE_HEADER *LastVariable; 766 VARIABLE_HEADER *MaxIndex; 767 UINTN Index; 768 UINTN Offset; 769 BOOLEAN StopRecord; 770 VARIABLE_HEADER *InDeletedVariable; 771 VARIABLE_STORE_HEADER *VariableStoreHeader; 772 VARIABLE_INDEX_TABLE *IndexTable; 773 VARIABLE_HEADER *VariableHeader; 774 775 VariableStoreHeader = StoreInfo->VariableStoreHeader; 776 777 if (VariableStoreHeader == NULL) { 778 return EFI_INVALID_PARAMETER; 779 } 780 781 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { 782 return EFI_UNSUPPORTED; 783 } 784 785 if (~VariableStoreHeader->Size == 0) { 786 return EFI_NOT_FOUND; 787 } 788 789 IndexTable = StoreInfo->IndexTable; 790 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader); 791 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader); 792 793 InDeletedVariable = NULL; 794 795 // 796 // No Variable Address equals zero, so 0 as initial value is safe. 797 // 798 MaxIndex = NULL; 799 VariableHeader = NULL; 800 801 if (IndexTable != NULL) { 802 // 803 // traverse the variable index table to look for varible. 804 // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables. 805 // 806 for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) { 807 ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0])); 808 Offset += IndexTable->Index[Index]; 809 MaxIndex = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset); 810 GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader); 811 if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { 812 if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { 813 InDeletedVariable = PtrTrack->CurrPtr; 814 } else { 815 return EFI_SUCCESS; 816 } 817 } 818 } 819 820 if (IndexTable->GoneThrough != 0) { 821 // 822 // If the table has all the existing variables indexed, return. 823 // 824 PtrTrack->CurrPtr = InDeletedVariable; 825 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; 826 } 827 } 828 829 if (MaxIndex != NULL) { 830 // 831 // HOB exists but the variable cannot be found in HOB 832 // If not found in HOB, then let's start from the MaxIndex we've found. 833 // 834 Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader); 835 LastVariable = MaxIndex; 836 } else { 837 // 838 // Start Pointers for the variable. 839 // Actual Data Pointer where data can be written. 840 // 841 Variable = PtrTrack->StartPtr; 842 LastVariable = PtrTrack->StartPtr; 843 } 844 845 // 846 // Find the variable by walk through variable store 847 // 848 StopRecord = FALSE; 849 while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) { 850 if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { 851 // 852 // Record Variable in VariableIndex HOB 853 // 854 if ((IndexTable != NULL) && !StopRecord) { 855 Offset = (UINTN) Variable - (UINTN) LastVariable; 856 if ((Offset > 0x0FFFF) || (IndexTable->Length == sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) { 857 // 858 // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16), 859 // or the record buffer is full. 860 // 861 StopRecord = TRUE; 862 } else { 863 IndexTable->Index[IndexTable->Length++] = (UINT16) Offset; 864 LastVariable = Variable; 865 } 866 } 867 868 if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { 869 if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { 870 InDeletedVariable = PtrTrack->CurrPtr; 871 } else { 872 return EFI_SUCCESS; 873 } 874 } 875 } 876 877 Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader); 878 } 879 // 880 // If gone through the VariableStore, that means we never find in Firmware any more. 881 // 882 if ((IndexTable != NULL) && !StopRecord) { 883 IndexTable->GoneThrough = 1; 884 } 885 886 PtrTrack->CurrPtr = InDeletedVariable; 887 888 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; 889} 890 891/** 892 Find the variable in HOB and Non-Volatile variable storages. 893 894 @param VariableName Name of the variable to be found 895 @param VendorGuid Vendor GUID to be found. 896 @param PtrTrack Variable Track Pointer structure that contains Variable Information. 897 @param StoreInfo Return the store info. 898 899 @retval EFI_SUCCESS Variable found successfully 900 @retval EFI_NOT_FOUND Variable not found 901 @retval EFI_INVALID_PARAMETER Invalid variable name 902**/ 903EFI_STATUS 904FindVariable ( 905 IN CONST CHAR16 *VariableName, 906 IN CONST EFI_GUID *VendorGuid, 907 OUT VARIABLE_POINTER_TRACK *PtrTrack, 908 OUT VARIABLE_STORE_INFO *StoreInfo 909 ) 910{ 911 EFI_STATUS Status; 912 VARIABLE_STORE_TYPE Type; 913 914 if (VariableName[0] != 0 && VendorGuid == NULL) { 915 return EFI_INVALID_PARAMETER; 916 } 917 918 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { 919 GetVariableStore (Type, StoreInfo); 920 Status = FindVariableEx ( 921 StoreInfo, 922 VariableName, 923 VendorGuid, 924 PtrTrack 925 ); 926 if (!EFI_ERROR (Status)) { 927 return Status; 928 } 929 } 930 931 return EFI_NOT_FOUND; 932} 933 934/** 935 This service retrieves a variable's value using its name and GUID. 936 937 Read the specified variable from the UEFI variable store. If the Data 938 buffer is too small to hold the contents of the variable, the error 939 EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer 940 size to obtain the data. 941 942 @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. 943 @param VariableName A pointer to a null-terminated string that is the variable's name. 944 @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of 945 VariableGuid and VariableName must be unique. 946 @param Attributes If non-NULL, on return, points to the variable's attributes. 947 @param DataSize On entry, points to the size in bytes of the Data buffer. 948 On return, points to the size of the data returned in Data. 949 @param Data Points to the buffer which will hold the returned variable value. 950 951 @retval EFI_SUCCESS The variable was read successfully. 952 @retval EFI_NOT_FOUND The variable could not be found. 953 @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. 954 DataSize is updated with the size required for 955 the specified variable. 956 @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. 957 @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. 958 959**/ 960EFI_STATUS 961EFIAPI 962PeiGetVariable ( 963 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, 964 IN CONST CHAR16 *VariableName, 965 IN CONST EFI_GUID *VariableGuid, 966 OUT UINT32 *Attributes, 967 IN OUT UINTN *DataSize, 968 OUT VOID *Data 969 ) 970{ 971 VARIABLE_POINTER_TRACK Variable; 972 UINTN VarDataSize; 973 EFI_STATUS Status; 974 VARIABLE_STORE_INFO StoreInfo; 975 VARIABLE_HEADER *VariableHeader; 976 977 if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) { 978 return EFI_INVALID_PARAMETER; 979 } 980 981 if (VariableName[0] == 0) { 982 return EFI_NOT_FOUND; 983 } 984 985 VariableHeader = NULL; 986 987 // 988 // Find existing variable 989 // 990 Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo); 991 if (EFI_ERROR (Status)) { 992 return Status; 993 } 994 GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader); 995 996 // 997 // Get data size 998 // 999 VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag); 1000 if (*DataSize >= VarDataSize) { 1001 if (Data == NULL) { 1002 return EFI_INVALID_PARAMETER; 1003 } 1004 1005 GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data); 1006 1007 if (Attributes != NULL) { 1008 *Attributes = VariableHeader->Attributes; 1009 } 1010 1011 *DataSize = VarDataSize; 1012 return EFI_SUCCESS; 1013 } else { 1014 *DataSize = VarDataSize; 1015 return EFI_BUFFER_TOO_SMALL; 1016 } 1017} 1018 1019/** 1020 Return the next variable name and GUID. 1021 1022 This function is called multiple times to retrieve the VariableName 1023 and VariableGuid of all variables currently available in the system. 1024 On each call, the previous results are passed into the interface, 1025 and, on return, the interface returns the data for the next 1026 interface. When the entire variable list has been returned, 1027 EFI_NOT_FOUND is returned. 1028 1029 @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. 1030 1031 @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. 1032 On return, the size of the variable name buffer. 1033 @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. 1034 On return, points to the next variable's null-terminated name string. 1035 @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID. 1036 On return, a pointer to the next variable's GUID. 1037 1038 @retval EFI_SUCCESS The variable was read successfully. 1039 @retval EFI_NOT_FOUND The variable could not be found. 1040 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting 1041 data. VariableNameSize is updated with the size 1042 required for the specified variable. 1043 @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or 1044 VariableNameSize is NULL. 1045 @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. 1046 1047**/ 1048EFI_STATUS 1049EFIAPI 1050PeiGetNextVariableName ( 1051 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, 1052 IN OUT UINTN *VariableNameSize, 1053 IN OUT CHAR16 *VariableName, 1054 IN OUT EFI_GUID *VariableGuid 1055 ) 1056{ 1057 VARIABLE_STORE_TYPE Type; 1058 VARIABLE_POINTER_TRACK Variable; 1059 VARIABLE_POINTER_TRACK VariableInHob; 1060 VARIABLE_POINTER_TRACK VariablePtrTrack; 1061 UINTN VarNameSize; 1062 EFI_STATUS Status; 1063 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; 1064 VARIABLE_HEADER *VariableHeader; 1065 VARIABLE_STORE_INFO StoreInfo; 1066 VARIABLE_STORE_INFO StoreInfoForNv; 1067 VARIABLE_STORE_INFO StoreInfoForHob; 1068 1069 if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) { 1070 return EFI_INVALID_PARAMETER; 1071 } 1072 1073 VariableHeader = NULL; 1074 1075 Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo); 1076 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { 1077 return Status; 1078 } 1079 1080 if (VariableName[0] != 0) { 1081 // 1082 // If variable name is not NULL, get next variable 1083 // 1084 GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader); 1085 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); 1086 } 1087 1088 VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob); 1089 VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv); 1090 1091 while (TRUE) { 1092 // 1093 // Switch from HOB to Non-Volatile. 1094 // 1095 while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) { 1096 // 1097 // Find current storage index 1098 // 1099 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { 1100 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) { 1101 break; 1102 } 1103 } 1104 ASSERT (Type < VariableStoreTypeMax); 1105 // 1106 // Switch to next storage 1107 // 1108 for (Type++; Type < VariableStoreTypeMax; Type++) { 1109 if (VariableStoreHeader[Type] != NULL) { 1110 break; 1111 } 1112 } 1113 // 1114 // Capture the case that 1115 // 1. current storage is the last one, or 1116 // 2. no further storage 1117 // 1118 if (Type == VariableStoreTypeMax) { 1119 return EFI_NOT_FOUND; 1120 } 1121 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]); 1122 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]); 1123 Variable.CurrPtr = Variable.StartPtr; 1124 GetVariableStore (Type, &StoreInfo); 1125 } 1126 1127 if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { 1128 if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { 1129 // 1130 // If it is a IN_DELETED_TRANSITION variable, 1131 // and there is also a same ADDED one at the same time, 1132 // don't return it. 1133 // 1134 Status = FindVariableEx ( 1135 &StoreInfo, 1136 GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), 1137 GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), 1138 &VariablePtrTrack 1139 ); 1140 if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) { 1141 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); 1142 continue; 1143 } 1144 } 1145 1146 // 1147 // Don't return NV variable when HOB overrides it 1148 // 1149 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && 1150 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) 1151 ) { 1152 Status = FindVariableEx ( 1153 &StoreInfoForHob, 1154 GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), 1155 GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), 1156 &VariableInHob 1157 ); 1158 if (!EFI_ERROR (Status)) { 1159 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); 1160 continue; 1161 } 1162 } 1163 1164 VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag); 1165 ASSERT (VarNameSize != 0); 1166 1167 if (VarNameSize <= *VariableNameSize) { 1168 GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *) VariableName); 1169 1170 CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID)); 1171 1172 Status = EFI_SUCCESS; 1173 } else { 1174 Status = EFI_BUFFER_TOO_SMALL; 1175 } 1176 1177 *VariableNameSize = VarNameSize; 1178 // 1179 // Variable is found 1180 // 1181 return Status; 1182 } else { 1183 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); 1184 } 1185 } 1186} 1187