1 /** @file 2 3 Internal generic functions to operate flash block. 4 5 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "FaultTolerantWrite.h" 17 18 /** 19 20 Check whether a flash buffer is erased. 21 22 @param Buffer Buffer to check 23 @param BufferSize Size of the buffer 24 25 @return A BOOLEAN value indicating erased or not. 26 27 **/ 28 BOOLEAN 29 IsErasedFlashBuffer ( 30 IN UINT8 *Buffer, 31 IN UINTN BufferSize 32 ) 33 { 34 BOOLEAN IsEmpty; 35 UINT8 *Ptr; 36 UINTN Index; 37 38 Ptr = Buffer; 39 IsEmpty = TRUE; 40 for (Index = 0; Index < BufferSize; Index += 1) { 41 if (*Ptr++ != FTW_ERASED_BYTE) { 42 IsEmpty = FALSE; 43 break; 44 } 45 } 46 47 return IsEmpty; 48 } 49 50 /** 51 To erase the block with specified blocks. 52 53 54 @param FtwDevice The private data of FTW driver 55 @param FvBlock FVB Protocol interface 56 @param Lba Lba of the firmware block 57 @param NumberOfBlocks The number of consecutive blocks starting with Lba 58 59 @retval EFI_SUCCESS Block LBA is Erased successfully 60 @retval Others Error occurs 61 62 **/ 63 EFI_STATUS 64 FtwEraseBlock ( 65 IN EFI_FTW_DEVICE *FtwDevice, 66 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, 67 EFI_LBA Lba, 68 UINTN NumberOfBlocks 69 ) 70 { 71 return FvBlock->EraseBlocks ( 72 FvBlock, 73 Lba, 74 NumberOfBlocks, 75 EFI_LBA_LIST_TERMINATOR 76 ); 77 } 78 79 /** 80 Erase spare block. 81 82 @param FtwDevice The private data of FTW driver 83 84 @retval EFI_SUCCESS The erase request was successfully completed. 85 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. 86 @retval EFI_DEVICE_ERROR The block device is not functioning 87 correctly and could not be written. 88 The firmware device may have been 89 partially erased. 90 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed 91 in the variable argument list do 92 not exist in the firmware volume. 93 94 95 **/ 96 EFI_STATUS 97 FtwEraseSpareBlock ( 98 IN EFI_FTW_DEVICE *FtwDevice 99 ) 100 { 101 return FtwDevice->FtwBackupFvb->EraseBlocks ( 102 FtwDevice->FtwBackupFvb, 103 FtwDevice->FtwSpareLba, 104 FtwDevice->NumberOfSpareBlock, 105 EFI_LBA_LIST_TERMINATOR 106 ); 107 } 108 109 /** 110 111 Is it in working block? 112 113 @param FtwDevice The private data of FTW driver 114 @param FvBlock Fvb protocol instance 115 @param Lba The block specified 116 117 @return A BOOLEAN value indicating in working block or not. 118 119 **/ 120 BOOLEAN 121 IsWorkingBlock ( 122 EFI_FTW_DEVICE *FtwDevice, 123 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, 124 EFI_LBA Lba 125 ) 126 { 127 // 128 // If matching the following condition, the target block is in working block. 129 // 1. Target block is on the FV of working block (Using the same FVB protocol instance). 130 // 2. Lba falls into the range of working block. 131 // 132 return (BOOLEAN) 133 ( 134 (FvBlock == FtwDevice->FtwFvBlock) && 135 (Lba >= FtwDevice->FtwWorkBlockLba) && 136 (Lba <= FtwDevice->FtwWorkSpaceLba) 137 ); 138 } 139 140 /** 141 142 Get firmware volume block by address. 143 144 145 @param Address Address specified the block 146 @param FvBlock The block caller wanted 147 148 @retval EFI_SUCCESS The protocol instance if found. 149 @retval EFI_NOT_FOUND Block not found 150 151 **/ 152 EFI_HANDLE 153 GetFvbByAddress ( 154 IN EFI_PHYSICAL_ADDRESS Address, 155 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock 156 ) 157 { 158 EFI_STATUS Status; 159 EFI_HANDLE *HandleBuffer; 160 UINTN HandleCount; 161 UINTN Index; 162 EFI_PHYSICAL_ADDRESS FvbBaseAddress; 163 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; 164 EFI_HANDLE FvbHandle; 165 UINTN BlockSize; 166 UINTN NumberOfBlocks; 167 168 *FvBlock = NULL; 169 FvbHandle = NULL; 170 HandleBuffer = NULL; 171 // 172 // Locate all handles of Fvb protocol 173 // 174 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); 175 if (EFI_ERROR (Status)) { 176 return NULL; 177 } 178 // 179 // Get the FVB to access variable store 180 // 181 for (Index = 0; Index < HandleCount; Index += 1) { 182 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb); 183 if (EFI_ERROR (Status)) { 184 break; 185 } 186 // 187 // Compare the address and select the right one 188 // 189 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); 190 if (EFI_ERROR (Status)) { 191 continue; 192 } 193 194 // 195 // Now, one FVB has one type of BlockSize 196 // 197 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks); 198 if (EFI_ERROR (Status)) { 199 continue; 200 } 201 202 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) { 203 *FvBlock = Fvb; 204 FvbHandle = HandleBuffer[Index]; 205 break; 206 } 207 } 208 209 FreePool (HandleBuffer); 210 return FvbHandle; 211 } 212 213 /** 214 215 Is it in boot block? 216 217 @param FtwDevice The private data of FTW driver 218 @param FvBlock Fvb protocol instance 219 220 @return A BOOLEAN value indicating in boot block or not. 221 222 **/ 223 BOOLEAN 224 IsBootBlock ( 225 EFI_FTW_DEVICE *FtwDevice, 226 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock 227 ) 228 { 229 EFI_STATUS Status; 230 EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol; 231 EFI_PHYSICAL_ADDRESS BootBlockBase; 232 UINTN BootBlockSize; 233 EFI_PHYSICAL_ADDRESS BackupBlockBase; 234 UINTN BackupBlockSize; 235 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb; 236 BOOLEAN IsSwapped; 237 EFI_HANDLE FvbHandle; 238 239 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) { 240 return FALSE; 241 } 242 243 Status = FtwGetSarProtocol ((VOID **) &SarProtocol); 244 if (EFI_ERROR (Status)) { 245 return FALSE; 246 } 247 // 248 // Get the boot block range 249 // 250 Status = SarProtocol->GetRangeLocation ( 251 SarProtocol, 252 &BootBlockBase, 253 &BootBlockSize, 254 &BackupBlockBase, 255 &BackupBlockSize 256 ); 257 if (EFI_ERROR (Status)) { 258 return FALSE; 259 } 260 261 Status = SarProtocol->GetSwapState (SarProtocol, &IsSwapped); 262 if (EFI_ERROR (Status)) { 263 return FALSE; 264 } 265 // 266 // Get FVB by address 267 // 268 if (!IsSwapped) { 269 FvbHandle = GetFvbByAddress (BootBlockBase, &BootFvb); 270 } else { 271 FvbHandle = GetFvbByAddress (BackupBlockBase, &BootFvb); 272 } 273 274 if (FvbHandle == NULL) { 275 return FALSE; 276 } 277 // 278 // Compare the Fvb 279 // 280 return (BOOLEAN) (FvBlock == BootFvb); 281 } 282 283 /** 284 Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE. 285 Spare block is accessed by FTW working FVB protocol interface. 286 Target block is accessed by FvBlock protocol interface. 287 288 FTW will do extra work on boot block update. 289 FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL, 290 which is produced by a chipset driver. 291 FTW updating boot block steps may be: 292 1. GetRangeLocation(), if the Range is inside the boot block, FTW know 293 that boot block will be update. It shall add a FLAG in the working block. 294 2. When spare block is ready, 295 3. SetSwapState(SWAPPED) 296 4. erasing boot block, 297 5. programming boot block until the boot block is ok. 298 6. SetSwapState(UNSWAPPED) 299 FTW shall not allow to update boot block when battery state is error. 300 301 @param FtwDevice The private data of FTW driver 302 303 @retval EFI_SUCCESS Spare block content is copied to boot block 304 @retval EFI_INVALID_PARAMETER Input parameter error 305 @retval EFI_OUT_OF_RESOURCES Allocate memory error 306 @retval EFI_ABORTED The function could not complete successfully 307 308 **/ 309 EFI_STATUS 310 FlushSpareBlockToBootBlock ( 311 EFI_FTW_DEVICE *FtwDevice 312 ) 313 { 314 EFI_STATUS Status; 315 UINTN Length; 316 UINT8 *Buffer; 317 UINTN Count; 318 UINT8 *Ptr; 319 UINTN Index; 320 BOOLEAN TopSwap; 321 EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol; 322 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb; 323 EFI_LBA BootLba; 324 325 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) { 326 return EFI_UNSUPPORTED; 327 } 328 329 // 330 // Locate swap address range protocol 331 // 332 Status = FtwGetSarProtocol ((VOID **) &SarProtocol); 333 if (EFI_ERROR (Status)) { 334 return Status; 335 } 336 // 337 // Allocate a memory buffer 338 // 339 Length = FtwDevice->SpareAreaLength; 340 Buffer = AllocatePool (Length); 341 if (Buffer == NULL) { 342 return EFI_OUT_OF_RESOURCES; 343 } 344 // 345 // Get TopSwap bit state 346 // 347 Status = SarProtocol->GetSwapState (SarProtocol, &TopSwap); 348 if (EFI_ERROR (Status)) { 349 DEBUG ((EFI_D_ERROR, "Ftw: Get Top Swapped status - %r\n", Status)); 350 FreePool (Buffer); 351 return EFI_ABORTED; 352 } 353 354 if (TopSwap) { 355 // 356 // Get FVB of current boot block 357 // 358 if (GetFvbByAddress (FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength, &BootFvb) == NULL) { 359 FreePool (Buffer); 360 return EFI_ABORTED; 361 } 362 // 363 // Read data from current boot block 364 // 365 BootLba = 0; 366 Ptr = Buffer; 367 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { 368 Count = FtwDevice->SpareBlockSize; 369 Status = BootFvb->Read ( 370 BootFvb, 371 BootLba + Index, 372 0, 373 &Count, 374 Ptr 375 ); 376 if (EFI_ERROR (Status)) { 377 FreePool (Buffer); 378 return Status; 379 } 380 381 Ptr += Count; 382 } 383 } else { 384 // 385 // Read data from spare block 386 // 387 Ptr = Buffer; 388 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { 389 Count = FtwDevice->SpareBlockSize; 390 Status = FtwDevice->FtwBackupFvb->Read ( 391 FtwDevice->FtwBackupFvb, 392 FtwDevice->FtwSpareLba + Index, 393 0, 394 &Count, 395 Ptr 396 ); 397 if (EFI_ERROR (Status)) { 398 FreePool (Buffer); 399 return Status; 400 } 401 402 Ptr += Count; 403 } 404 // 405 // Set TopSwap bit 406 // 407 Status = SarProtocol->SetSwapState (SarProtocol, TRUE); 408 if (EFI_ERROR (Status)) { 409 FreePool (Buffer); 410 return Status; 411 } 412 } 413 // 414 // Erase current spare block 415 // Because TopSwap is set, this actually erase the top block (boot block)! 416 // 417 Status = FtwEraseSpareBlock (FtwDevice); 418 if (EFI_ERROR (Status)) { 419 FreePool (Buffer); 420 return EFI_ABORTED; 421 } 422 // 423 // Write memory buffer to current spare block. Still top block. 424 // 425 Ptr = Buffer; 426 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { 427 Count = FtwDevice->SpareBlockSize; 428 Status = FtwDevice->FtwBackupFvb->Write ( 429 FtwDevice->FtwBackupFvb, 430 FtwDevice->FtwSpareLba + Index, 431 0, 432 &Count, 433 Ptr 434 ); 435 if (EFI_ERROR (Status)) { 436 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write boot block - %r\n", Status)); 437 FreePool (Buffer); 438 return Status; 439 } 440 441 Ptr += Count; 442 } 443 444 FreePool (Buffer); 445 446 // 447 // Clear TopSwap bit 448 // 449 Status = SarProtocol->SetSwapState (SarProtocol, FALSE); 450 451 return Status; 452 } 453 454 /** 455 Copy the content of spare block to a target block. 456 Spare block is accessed by FTW backup FVB protocol interface. 457 Target block is accessed by FvBlock protocol interface. 458 459 460 @param FtwDevice The private data of FTW driver 461 @param FvBlock FVB Protocol interface to access target block 462 @param Lba Lba of the target block 463 @param BlockSize The size of the block 464 @param NumberOfBlocks The number of consecutive blocks starting with Lba 465 466 @retval EFI_SUCCESS Spare block content is copied to target block 467 @retval EFI_INVALID_PARAMETER Input parameter error 468 @retval EFI_OUT_OF_RESOURCES Allocate memory error 469 @retval EFI_ABORTED The function could not complete successfully 470 471 **/ 472 EFI_STATUS 473 FlushSpareBlockToTargetBlock ( 474 EFI_FTW_DEVICE *FtwDevice, 475 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, 476 EFI_LBA Lba, 477 UINTN BlockSize, 478 UINTN NumberOfBlocks 479 ) 480 { 481 EFI_STATUS Status; 482 UINTN Length; 483 UINT8 *Buffer; 484 UINTN Count; 485 UINT8 *Ptr; 486 UINTN Index; 487 488 if ((FtwDevice == NULL) || (FvBlock == NULL)) { 489 return EFI_INVALID_PARAMETER; 490 } 491 // 492 // Allocate a memory buffer 493 // 494 Length = FtwDevice->SpareAreaLength; 495 Buffer = AllocatePool (Length); 496 if (Buffer == NULL) { 497 return EFI_OUT_OF_RESOURCES; 498 } 499 // 500 // Read all content of spare block to memory buffer 501 // 502 Ptr = Buffer; 503 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { 504 Count = FtwDevice->SpareBlockSize; 505 Status = FtwDevice->FtwBackupFvb->Read ( 506 FtwDevice->FtwBackupFvb, 507 FtwDevice->FtwSpareLba + Index, 508 0, 509 &Count, 510 Ptr 511 ); 512 if (EFI_ERROR (Status)) { 513 FreePool (Buffer); 514 return Status; 515 } 516 517 Ptr += Count; 518 } 519 // 520 // Erase the target block 521 // 522 Status = FtwEraseBlock (FtwDevice, FvBlock, Lba, NumberOfBlocks); 523 if (EFI_ERROR (Status)) { 524 FreePool (Buffer); 525 return EFI_ABORTED; 526 } 527 // 528 // Write memory buffer to block, using the FvBlock protocol interface 529 // 530 Ptr = Buffer; 531 for (Index = 0; Index < NumberOfBlocks; Index += 1) { 532 Count = BlockSize; 533 Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr); 534 if (EFI_ERROR (Status)) { 535 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status)); 536 FreePool (Buffer); 537 return Status; 538 } 539 540 Ptr += Count; 541 } 542 543 FreePool (Buffer); 544 545 return Status; 546 } 547 548 /** 549 Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE. 550 Spare block is accessed by FTW backup FVB protocol interface. LBA is 551 FtwDevice->FtwSpareLba. 552 Working block is accessed by FTW working FVB protocol interface. LBA is 553 FtwDevice->FtwWorkBlockLba. 554 555 Since the working block header is important when FTW initializes, the 556 state of the operation should be handled carefully. The Crc value is 557 calculated without STATE element. 558 559 @param FtwDevice The private data of FTW driver 560 561 @retval EFI_SUCCESS Spare block content is copied to target block 562 @retval EFI_OUT_OF_RESOURCES Allocate memory error 563 @retval EFI_ABORTED The function could not complete successfully 564 565 **/ 566 EFI_STATUS 567 FlushSpareBlockToWorkingBlock ( 568 EFI_FTW_DEVICE *FtwDevice 569 ) 570 { 571 EFI_STATUS Status; 572 UINTN Length; 573 UINT8 *Buffer; 574 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader; 575 UINTN Count; 576 UINT8 *Ptr; 577 UINTN Index; 578 579 // 580 // Allocate a memory buffer 581 // 582 Length = FtwDevice->SpareAreaLength; 583 Buffer = AllocatePool (Length); 584 if (Buffer == NULL) { 585 return EFI_OUT_OF_RESOURCES; 586 } 587 588 // 589 // To guarantee that the WorkingBlockValid is set on spare block 590 // 591 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, 592 // WorkingBlockValid); 593 // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32). 594 // 595 FtwUpdateFvState ( 596 FtwDevice->FtwBackupFvb, 597 FtwDevice->SpareBlockSize, 598 FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare, 599 FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32), 600 WORKING_BLOCK_VALID 601 ); 602 // 603 // Read from spare block to memory buffer 604 // 605 Ptr = Buffer; 606 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) { 607 Count = FtwDevice->SpareBlockSize; 608 Status = FtwDevice->FtwBackupFvb->Read ( 609 FtwDevice->FtwBackupFvb, 610 FtwDevice->FtwSpareLba + Index, 611 0, 612 &Count, 613 Ptr 614 ); 615 if (EFI_ERROR (Status)) { 616 FreePool (Buffer); 617 return Status; 618 } 619 620 Ptr += Count; 621 } 622 // 623 // Clear the CRC and STATE, copy data from spare to working block. 624 // 625 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) FtwDevice->FtwWorkSpaceLbaInSpare * FtwDevice->SpareBlockSize + FtwDevice->FtwWorkSpaceBaseInSpare); 626 InitWorkSpaceHeader (WorkingBlockHeader); 627 WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY; 628 WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY; 629 630 // 631 // target block is working block, then 632 // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER 633 // before erase the working block. 634 // 635 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, 636 // WorkingBlockInvalid); 637 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to 638 // skip Signature and Crc. 639 // 640 Status = FtwUpdateFvState ( 641 FtwDevice->FtwFvBlock, 642 FtwDevice->WorkBlockSize, 643 FtwDevice->FtwWorkSpaceLba, 644 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32), 645 WORKING_BLOCK_INVALID 646 ); 647 if (EFI_ERROR (Status)) { 648 FreePool (Buffer); 649 return EFI_ABORTED; 650 } 651 652 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE; 653 654 // 655 // Erase the working block 656 // 657 Status = FtwEraseBlock (FtwDevice, FtwDevice->FtwFvBlock, FtwDevice->FtwWorkBlockLba, FtwDevice->NumberOfWorkBlock); 658 if (EFI_ERROR (Status)) { 659 FreePool (Buffer); 660 return EFI_ABORTED; 661 } 662 // 663 // Write memory buffer to working block, using the FvBlock protocol interface 664 // 665 Ptr = Buffer; 666 for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) { 667 Count = FtwDevice->WorkBlockSize; 668 Status = FtwDevice->FtwFvBlock->Write ( 669 FtwDevice->FtwFvBlock, 670 FtwDevice->FtwWorkBlockLba + Index, 671 0, 672 &Count, 673 Ptr 674 ); 675 if (EFI_ERROR (Status)) { 676 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status)); 677 FreePool (Buffer); 678 return Status; 679 } 680 681 Ptr += Count; 682 } 683 // 684 // Since the memory buffer will not be used, free memory Buffer. 685 // 686 FreePool (Buffer); 687 688 // 689 // Update the VALID of the working block 690 // 691 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, WorkingBlockValid); 692 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to skip Signature and Crc. 693 // 694 Status = FtwUpdateFvState ( 695 FtwDevice->FtwFvBlock, 696 FtwDevice->WorkBlockSize, 697 FtwDevice->FtwWorkSpaceLba, 698 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32), 699 WORKING_BLOCK_VALID 700 ); 701 if (EFI_ERROR (Status)) { 702 return EFI_ABORTED; 703 } 704 705 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_INVALID_STATE; 706 FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE; 707 708 return EFI_SUCCESS; 709 } 710 711 /** 712 Update a bit of state on a block device. The location of the bit is 713 calculated by the (Lba, Offset, bit). Here bit is determined by the 714 the name of a certain bit. 715 716 717 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock 718 @param BlockSize The size of the block 719 @param Lba Lba of a block 720 @param Offset Offset on the Lba 721 @param NewBit New value that will override the old value if it can be change 722 723 @retval EFI_SUCCESS A state bit has been updated successfully 724 @retval Others Access block device error. 725 Notes: 726 Assume all bits of State are inside the same BYTE. 727 @retval EFI_ABORTED Read block fail 728 729 **/ 730 EFI_STATUS 731 FtwUpdateFvState ( 732 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, 733 IN UINTN BlockSize, 734 IN EFI_LBA Lba, 735 IN UINTN Offset, 736 IN UINT8 NewBit 737 ) 738 { 739 EFI_STATUS Status; 740 UINT8 State; 741 UINTN Length; 742 743 // 744 // Calculate the real Offset and Lba to write. 745 // 746 while (Offset >= BlockSize) { 747 Offset -= BlockSize; 748 Lba++; 749 } 750 751 // 752 // Read state from device, assume State is only one byte. 753 // 754 Length = sizeof (UINT8); 755 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State); 756 if (EFI_ERROR (Status)) { 757 return EFI_ABORTED; 758 } 759 760 State ^= FTW_POLARITY_REVERT; 761 State = (UINT8) (State | NewBit); 762 State ^= FTW_POLARITY_REVERT; 763 764 // 765 // Write state back to device 766 // 767 Length = sizeof (UINT8); 768 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State); 769 770 return Status; 771 } 772 773 /** 774 Get the last Write Header pointer. 775 The last write header is the header whose 'complete' state hasn't been set. 776 After all, this header may be a EMPTY header entry for next Allocate. 777 778 779 @param FtwWorkSpaceHeader Pointer of the working block header 780 @param FtwWorkSpaceSize Size of the work space 781 @param FtwWriteHeader Pointer to retrieve the last write header 782 783 @retval EFI_SUCCESS Get the last write record successfully 784 @retval EFI_ABORTED The FTW work space is damaged 785 786 **/ 787 EFI_STATUS 788 FtwGetLastWriteHeader ( 789 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader, 790 IN UINTN FtwWorkSpaceSize, 791 OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader 792 ) 793 { 794 UINTN Offset; 795 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader; 796 797 *FtwWriteHeader = NULL; 798 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1); 799 Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER); 800 801 while (FtwHeader->Complete == FTW_VALID_STATE) { 802 Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); 803 // 804 // If Offset exceed the FTW work space boudary, return error. 805 // 806 if (Offset >= FtwWorkSpaceSize) { 807 *FtwWriteHeader = FtwHeader; 808 return EFI_ABORTED; 809 } 810 811 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset); 812 } 813 // 814 // Last write header is found 815 // 816 *FtwWriteHeader = FtwHeader; 817 818 return EFI_SUCCESS; 819 } 820 821 /** 822 Get the last Write Record pointer. The last write Record is the Record 823 whose DestinationCompleted state hasn't been set. After all, this Record 824 may be a EMPTY record entry for next write. 825 826 827 @param FtwWriteHeader Pointer to the write record header 828 @param FtwWriteRecord Pointer to retrieve the last write record 829 830 @retval EFI_SUCCESS Get the last write record successfully 831 @retval EFI_ABORTED The FTW work space is damaged 832 833 **/ 834 EFI_STATUS 835 FtwGetLastWriteRecord ( 836 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader, 837 OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord 838 ) 839 { 840 UINTN Index; 841 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord; 842 843 *FtwWriteRecord = NULL; 844 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1); 845 846 // 847 // Try to find the last write record "that has not completed" 848 // 849 for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) { 850 if (FtwRecord->DestinationComplete != FTW_VALID_STATE) { 851 // 852 // The last write record is found 853 // 854 *FtwWriteRecord = FtwRecord; 855 return EFI_SUCCESS; 856 } 857 858 FtwRecord++; 859 860 if (FtwWriteHeader->PrivateDataSize != 0) { 861 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize); 862 } 863 } 864 // 865 // if Index == NumberOfWrites, then 866 // the last record has been written successfully, 867 // but the Header->Complete Flag has not been set. 868 // also return the last record. 869 // 870 if (Index == FtwWriteHeader->NumberOfWrites) { 871 *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize)); 872 return EFI_SUCCESS; 873 } 874 875 return EFI_ABORTED; 876 } 877 878 /** 879 To check if FtwRecord is the first record of FtwHeader. 880 881 @param FtwHeader Pointer to the write record header 882 @param FtwRecord Pointer to the write record 883 884 @retval TRUE FtwRecord is the first Record of the FtwHeader 885 @retval FALSE FtwRecord is not the first Record of the FtwHeader 886 887 **/ 888 BOOLEAN 889 IsFirstRecordOfWrites ( 890 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader, 891 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord 892 ) 893 { 894 UINT8 *Head; 895 UINT8 *Ptr; 896 897 Head = (UINT8 *) FtwHeader; 898 Ptr = (UINT8 *) FtwRecord; 899 900 Head += sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER); 901 return (BOOLEAN) (Head == Ptr); 902 } 903 904 /** 905 To check if FtwRecord is the last record of FtwHeader. Because the 906 FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be 907 determined if it is the last record of FtwHeader. 908 909 @param FtwHeader Pointer to the write record header 910 @param FtwRecord Pointer to the write record 911 912 @retval TRUE FtwRecord is the last Record of the FtwHeader 913 @retval FALSE FtwRecord is not the last Record of the FtwHeader 914 915 **/ 916 BOOLEAN 917 IsLastRecordOfWrites ( 918 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader, 919 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord 920 ) 921 { 922 UINT8 *Head; 923 UINT8 *Ptr; 924 925 Head = (UINT8 *) FtwHeader; 926 Ptr = (UINT8 *) FtwRecord; 927 928 Head += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize); 929 return (BOOLEAN) (Head == Ptr); 930 } 931 932 /** 933 To check if FtwRecord is the first record of FtwHeader. 934 935 @param FtwHeader Pointer to the write record header 936 @param FtwRecord Pointer to retrieve the previous write record 937 938 @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return. 939 @retval EFI_SUCCESS The previous write record is found. 940 941 **/ 942 EFI_STATUS 943 GetPreviousRecordOfWrites ( 944 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader, 945 IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord 946 ) 947 { 948 UINT8 *Ptr; 949 950 if (IsFirstRecordOfWrites (FtwHeader, *FtwRecord)) { 951 *FtwRecord = NULL; 952 return EFI_ACCESS_DENIED; 953 } 954 955 Ptr = (UINT8 *) (*FtwRecord); 956 Ptr -= FTW_RECORD_SIZE (FtwHeader->PrivateDataSize); 957 *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr; 958 return EFI_SUCCESS; 959 } 960 961 /** 962 Allocate private data for FTW driver and initialize it. 963 964 @param[out] FtwData Pointer to the FTW device structure 965 966 @retval EFI_SUCCESS Initialize the FTW device successfully. 967 @retval EFI_OUT_OF_RESOURCES Allocate memory error 968 @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist 969 970 **/ 971 EFI_STATUS 972 InitFtwDevice ( 973 OUT EFI_FTW_DEVICE **FtwData 974 ) 975 { 976 EFI_FTW_DEVICE *FtwDevice; 977 978 // 979 // Allocate private data of this driver, 980 // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE]. 981 // 982 FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize)); 983 if (FtwDevice == NULL) { 984 return EFI_OUT_OF_RESOURCES; 985 } 986 987 // 988 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE. 989 // 990 FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize); 991 FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize); 992 if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) { 993 DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n")); 994 FreePool (FtwDevice); 995 return EFI_INVALID_PARAMETER; 996 } 997 998 FtwDevice->Signature = FTW_DEVICE_SIGNATURE; 999 FtwDevice->FtwFvBlock = NULL; 1000 FtwDevice->FtwBackupFvb = NULL; 1001 FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1); 1002 FtwDevice->FtwSpareLba = (EFI_LBA) (-1); 1003 1004 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64); 1005 if (FtwDevice->WorkSpaceAddress == 0) { 1006 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase); 1007 } 1008 1009 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64); 1010 if (FtwDevice->SpareAreaAddress == 0) { 1011 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase); 1012 } 1013 1014 *FtwData = FtwDevice; 1015 return EFI_SUCCESS; 1016 } 1017 1018 1019 /** 1020 Find the proper Firmware Volume Block protocol for FTW operation. 1021 1022 @param[in, out] FtwDevice Pointer to the FTW device structure 1023 1024 @retval EFI_SUCCESS Find the FVB protocol successfully. 1025 @retval EFI_NOT_FOUND No proper FVB protocol was found. 1026 @retval EFI_ABORTED Some data can not be got or be invalid. 1027 1028 **/ 1029 EFI_STATUS 1030 FindFvbForFtw ( 1031 IN OUT EFI_FTW_DEVICE *FtwDevice 1032 ) 1033 { 1034 EFI_STATUS Status; 1035 EFI_HANDLE *HandleBuffer; 1036 UINTN HandleCount; 1037 UINTN Index; 1038 EFI_PHYSICAL_ADDRESS FvbBaseAddress; 1039 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; 1040 EFI_FVB_ATTRIBUTES_2 Attributes; 1041 UINT32 LbaIndex; 1042 UINTN BlockSize; 1043 UINTN NumberOfBlocks; 1044 1045 HandleBuffer = NULL; 1046 1047 // 1048 // Get all FVB handle. 1049 // 1050 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); 1051 if (EFI_ERROR (Status)) { 1052 return EFI_NOT_FOUND; 1053 } 1054 1055 // 1056 // Get the FVB to access variable store 1057 // 1058 Fvb = NULL; 1059 for (Index = 0; Index < HandleCount; Index += 1) { 1060 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb); 1061 if (EFI_ERROR (Status)) { 1062 Status = EFI_NOT_FOUND; 1063 break; 1064 } 1065 1066 // 1067 // Ensure this FVB protocol support Write operation. 1068 // 1069 Status = Fvb->GetAttributes (Fvb, &Attributes); 1070 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { 1071 continue; 1072 } 1073 // 1074 // Compare the address and select the right one 1075 // 1076 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); 1077 if (EFI_ERROR (Status)) { 1078 continue; 1079 } 1080 1081 // 1082 // Now, one FVB has one type of BlockSize. 1083 // 1084 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks); 1085 if (EFI_ERROR (Status)) { 1086 continue; 1087 } 1088 1089 if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) && 1090 ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + BlockSize * NumberOfBlocks))) { 1091 FtwDevice->FtwFvBlock = Fvb; 1092 // 1093 // To get the LBA of work space 1094 // 1095 for (LbaIndex = 1; LbaIndex <= NumberOfBlocks; LbaIndex += 1) { 1096 if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + BlockSize * (LbaIndex - 1))) 1097 && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + BlockSize * LbaIndex))) { 1098 FtwDevice->FtwWorkSpaceLba = LbaIndex - 1; 1099 // 1100 // Get the Work space size and Base(Offset) 1101 // 1102 FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength; 1103 FtwDevice->WorkBlockSize = BlockSize; 1104 FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FtwDevice->WorkBlockSize * (LbaIndex - 1))); 1105 FtwDevice->NumberOfWorkSpaceBlock = FTW_BLOCKS (FtwDevice->FtwWorkSpaceBase + FtwDevice->FtwWorkSpaceSize, FtwDevice->WorkBlockSize); 1106 if (FtwDevice->FtwWorkSpaceSize >= FtwDevice->WorkBlockSize) { 1107 // 1108 // Check the alignment of work space address and length, they should be block size aligned when work space size is larger than one block size. 1109 // 1110 if (((FtwDevice->WorkSpaceAddress & (FtwDevice->WorkBlockSize - 1)) != 0) || 1111 ((FtwDevice->WorkSpaceLength & (FtwDevice->WorkBlockSize - 1)) != 0)) { 1112 DEBUG ((EFI_D_ERROR, "Ftw: Work space address or length is not block size aligned when work space size is larger than one block size\n")); 1113 FreePool (HandleBuffer); 1114 ASSERT (FALSE); 1115 return EFI_ABORTED; 1116 } 1117 } else if ((FtwDevice->FtwWorkSpaceBase + FtwDevice->FtwWorkSpaceSize) > FtwDevice->WorkBlockSize) { 1118 DEBUG ((EFI_D_ERROR, "Ftw: The work space range should not span blocks when work space size is less than one block size\n")); 1119 FreePool (HandleBuffer); 1120 ASSERT (FALSE); 1121 return EFI_ABORTED; 1122 } 1123 break; 1124 } 1125 } 1126 } 1127 1128 if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) && 1129 ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + BlockSize * NumberOfBlocks))) { 1130 FtwDevice->FtwBackupFvb = Fvb; 1131 // 1132 // To get the LBA of spare 1133 // 1134 for (LbaIndex = 1; LbaIndex <= NumberOfBlocks; LbaIndex += 1) { 1135 if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + BlockSize * (LbaIndex - 1))) 1136 && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + BlockSize * LbaIndex))) { 1137 // 1138 // Get the NumberOfSpareBlock and BlockSize 1139 // 1140 FtwDevice->FtwSpareLba = LbaIndex - 1; 1141 FtwDevice->SpareBlockSize = BlockSize; 1142 FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->SpareBlockSize; 1143 // 1144 // Check the range of spare area to make sure that it's in FV range 1145 // 1146 if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > NumberOfBlocks) { 1147 DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n")); 1148 FreePool (HandleBuffer); 1149 ASSERT (FALSE); 1150 return EFI_ABORTED; 1151 } 1152 // 1153 // Check the alignment of spare area address and length, they should be block size aligned 1154 // 1155 if (((FtwDevice->SpareAreaAddress & (FtwDevice->SpareBlockSize - 1)) != 0) || 1156 ((FtwDevice->SpareAreaLength & (FtwDevice->SpareBlockSize - 1)) != 0)) { 1157 DEBUG ((EFI_D_ERROR, "Ftw: Spare area address or length is not block size aligned\n")); 1158 FreePool (HandleBuffer); 1159 // 1160 // Report Status Code EFI_SW_EC_ABORTED. 1161 // 1162 REPORT_STATUS_CODE ((EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ABORTED)); 1163 ASSERT (FALSE); 1164 CpuDeadLoop (); 1165 } 1166 break; 1167 } 1168 } 1169 } 1170 } 1171 FreePool (HandleBuffer); 1172 1173 if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) || 1174 (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) { 1175 return EFI_ABORTED; 1176 } 1177 DEBUG ((EFI_D_INFO, "Ftw: FtwWorkSpaceLba - 0x%lx, WorkBlockSize - 0x%x, FtwWorkSpaceBase - 0x%x\n", FtwDevice->FtwWorkSpaceLba, FtwDevice->WorkBlockSize, FtwDevice->FtwWorkSpaceBase)); 1178 DEBUG ((EFI_D_INFO, "Ftw: FtwSpareLba - 0x%lx, SpareBlockSize - 0x%x\n", FtwDevice->FtwSpareLba, FtwDevice->SpareBlockSize)); 1179 1180 return EFI_SUCCESS; 1181 } 1182 1183 1184 /** 1185 Initialization for Fault Tolerant Write protocol. 1186 1187 @param[in, out] FtwDevice Pointer to the FTW device structure 1188 1189 @retval EFI_SUCCESS Initialize the FTW protocol successfully. 1190 @retval EFI_NOT_FOUND No proper FVB protocol was found. 1191 1192 **/ 1193 EFI_STATUS 1194 InitFtwProtocol ( 1195 IN OUT EFI_FTW_DEVICE *FtwDevice 1196 ) 1197 { 1198 EFI_STATUS Status; 1199 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; 1200 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader; 1201 UINTN Offset; 1202 EFI_HANDLE FvbHandle; 1203 EFI_LBA WorkSpaceLbaOffset; 1204 1205 // 1206 // Find the right SMM Fvb protocol instance for FTW. 1207 // 1208 Status = FindFvbForFtw (FtwDevice); 1209 if (EFI_ERROR (Status)) { 1210 return EFI_NOT_FOUND; 1211 } 1212 1213 // 1214 // Calculate the start LBA of working block. 1215 // 1216 if (FtwDevice->FtwWorkSpaceSize >= FtwDevice->WorkBlockSize) { 1217 // 1218 // Working block is a standalone area which only contains working space. 1219 // 1220 FtwDevice->NumberOfWorkBlock = FtwDevice->NumberOfWorkSpaceBlock; 1221 } else { 1222 // 1223 // Working block is an area which 1224 // contains working space in its last block and has the same size as spare 1225 // block, unless there are not enough blocks before the block that contains 1226 // working space. 1227 // 1228 FtwDevice->NumberOfWorkBlock = (UINTN) (FtwDevice->FtwWorkSpaceLba + FtwDevice->NumberOfWorkSpaceBlock); 1229 while (FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize > FtwDevice->SpareAreaLength) { 1230 FtwDevice->NumberOfWorkBlock--; 1231 } 1232 } 1233 FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba + FtwDevice->NumberOfWorkSpaceBlock - FtwDevice->NumberOfWorkBlock; 1234 DEBUG ((EFI_D_INFO, "Ftw: NumberOfWorkBlock - 0x%x, FtwWorkBlockLba - 0x%lx\n", FtwDevice->NumberOfWorkBlock, FtwDevice->FtwWorkBlockLba)); 1235 1236 // 1237 // Calcualte the LBA and base of work space in spare block. 1238 // Note: Do not assume Spare Block and Work Block have same block size. 1239 // 1240 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba; 1241 FtwDevice->FtwWorkSpaceLbaInSpare = (EFI_LBA) (((UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize + FtwDevice->FtwWorkSpaceBase) / FtwDevice->SpareBlockSize); 1242 FtwDevice->FtwWorkSpaceBaseInSpare = ((UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize + FtwDevice->FtwWorkSpaceBase) % FtwDevice->SpareBlockSize; 1243 DEBUG ((EFI_D_INFO, "Ftw: WorkSpaceLbaInSpare - 0x%lx, WorkSpaceBaseInSpare - 0x%x\n", FtwDevice->FtwWorkSpaceLbaInSpare, FtwDevice->FtwWorkSpaceBaseInSpare)); 1244 1245 // 1246 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE. 1247 // 1248 FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1); 1249 FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace; 1250 1251 FtwDevice->FtwLastWriteHeader = NULL; 1252 FtwDevice->FtwLastWriteRecord = NULL; 1253 1254 InitializeLocalWorkSpaceHeader (); 1255 1256 // 1257 // Refresh the working space data from working block 1258 // 1259 Status = WorkSpaceRefresh (FtwDevice); 1260 ASSERT_EFI_ERROR (Status); 1261 // 1262 // If the working block workspace is not valid, try the spare block 1263 // 1264 if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) { 1265 // 1266 // Read from spare block 1267 // 1268 Status = ReadWorkSpaceData ( 1269 FtwDevice->FtwBackupFvb, 1270 FtwDevice->SpareBlockSize, 1271 FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare, 1272 FtwDevice->FtwWorkSpaceBaseInSpare, 1273 FtwDevice->FtwWorkSpaceSize, 1274 FtwDevice->FtwWorkSpace 1275 ); 1276 ASSERT_EFI_ERROR (Status); 1277 1278 // 1279 // If spare block is valid, then replace working block content. 1280 // 1281 if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) { 1282 Status = FlushSpareBlockToWorkingBlock (FtwDevice); 1283 DEBUG ((EFI_D_INFO, "Ftw: Restart working block update in %a() - %r\n", 1284 __FUNCTION__, Status)); 1285 FtwAbort (&FtwDevice->FtwInstance); 1286 // 1287 // Refresh work space. 1288 // 1289 Status = WorkSpaceRefresh (FtwDevice); 1290 ASSERT_EFI_ERROR (Status); 1291 } else { 1292 DEBUG ((EFI_D_INFO, 1293 "Ftw: Both working and spare blocks are invalid, init workspace\n")); 1294 // 1295 // If both are invalid, then initialize work space. 1296 // 1297 SetMem ( 1298 FtwDevice->FtwWorkSpace, 1299 FtwDevice->FtwWorkSpaceSize, 1300 FTW_ERASED_BYTE 1301 ); 1302 InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader); 1303 // 1304 // Initialize the work space 1305 // 1306 Status = FtwReclaimWorkSpace (FtwDevice, FALSE); 1307 ASSERT_EFI_ERROR (Status); 1308 } 1309 } 1310 // 1311 // If the FtwDevice->FtwLastWriteRecord is 1st record of write header && 1312 // (! SpareComplete) THEN call Abort(). 1313 // 1314 if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) && 1315 (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) && 1316 IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord) 1317 ) { 1318 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n")); 1319 FtwAbort (&FtwDevice->FtwInstance); 1320 } 1321 // 1322 // If Header is incompleted and the last record has completed, then 1323 // call Abort() to set the Header->Complete FLAG. 1324 // 1325 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) && 1326 (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) && 1327 IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord) 1328 ) { 1329 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n")); 1330 FtwAbort (&FtwDevice->FtwInstance); 1331 } 1332 // 1333 // To check the workspace buffer following last Write header/records is EMPTY or not. 1334 // If it's not EMPTY, FTW also need to call reclaim(). 1335 // 1336 FtwHeader = FtwDevice->FtwLastWriteHeader; 1337 Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace; 1338 if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) { 1339 Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); 1340 } 1341 1342 if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) { 1343 Status = FtwReclaimWorkSpace (FtwDevice, TRUE); 1344 ASSERT_EFI_ERROR (Status); 1345 } 1346 1347 // 1348 // Restart if it's boot block 1349 // 1350 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) && 1351 (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) 1352 ) { 1353 if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) { 1354 Status = FlushSpareBlockToBootBlock (FtwDevice); 1355 DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status)); 1356 ASSERT_EFI_ERROR (Status); 1357 FtwAbort (&FtwDevice->FtwInstance); 1358 } else { 1359 // 1360 // if (SpareCompleted) THEN Restart to fault tolerant write. 1361 // 1362 FvbHandle = NULL; 1363 FvbHandle = GetFvbByAddress ((EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) FtwDevice->SpareAreaAddress + FtwDevice->FtwLastWriteRecord->RelativeOffset), &Fvb); 1364 if (FvbHandle != NULL) { 1365 Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle); 1366 DEBUG ((EFI_D_ERROR, "Ftw: Restart last write - %r\n", Status)); 1367 ASSERT_EFI_ERROR (Status); 1368 } 1369 FtwAbort (&FtwDevice->FtwInstance); 1370 } 1371 } 1372 // 1373 // Hook the protocol API 1374 // 1375 FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize; 1376 FtwDevice->FtwInstance.Allocate = FtwAllocate; 1377 FtwDevice->FtwInstance.Write = FtwWrite; 1378 FtwDevice->FtwInstance.Restart = FtwRestart; 1379 FtwDevice->FtwInstance.Abort = FtwAbort; 1380 FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite; 1381 1382 return EFI_SUCCESS; 1383 } 1384 1385