1 /** @file 2 Functions in this file will program the image into flash area. 3 4 Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions 8 of the BSD License which accompanies this distribution. The 9 full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "UpdateDriver.h" 18 19 /** 20 Write a block size data into flash. 21 22 @param FvbProtocol Pointer to FVB protocol. 23 @param Lba Logic block index to be updated. 24 @param BlockSize Block size 25 @param Buffer Buffer data to be written. 26 27 @retval EFI_SUCCESS Write data successfully. 28 @retval other errors Write data failed. 29 30 **/ 31 EFI_STATUS 32 UpdateOneBlock ( 33 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 34 IN EFI_LBA Lba, 35 IN UINTN BlockSize, 36 IN UINT8 *Buffer 37 ) 38 { 39 EFI_STATUS Status; 40 UINTN Size; 41 42 // 43 // First erase the block 44 // 45 Status = FvbProtocol->EraseBlocks ( 46 FvbProtocol, 47 Lba, // Lba 48 1, // NumOfBlocks 49 EFI_LBA_LIST_TERMINATOR 50 ); 51 if (EFI_ERROR (Status)) { 52 return Status; 53 } 54 55 // 56 // Write the block 57 // 58 Size = BlockSize; 59 Status = FvbProtocol->Write ( 60 FvbProtocol, 61 Lba, // Lba 62 0, // Offset 63 &Size, // Size 64 Buffer // Buffer 65 ); 66 if ((EFI_ERROR (Status)) || (Size != BlockSize)) { 67 return Status; 68 } 69 70 return EFI_SUCCESS; 71 } 72 73 /** 74 Write buffer data in a flash block. 75 76 @param FvbProtocol Pointer to FVB protocol. 77 @param Lba Logic block index to be updated. 78 @param Offset The offset within the block. 79 @param Length Size of buffer to be updated. 80 @param BlockSize Block size. 81 @param Buffer Buffer data to be updated. 82 83 @retval EFI_SUCCESS Write data successfully. 84 @retval other errors Write data failed. 85 86 **/ 87 EFI_STATUS 88 UpdateBufferInOneBlock ( 89 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 90 IN EFI_LBA Lba, 91 IN UINTN Offset, 92 IN UINTN Length, 93 IN UINTN BlockSize, 94 IN UINT8 *Buffer 95 ) 96 { 97 EFI_STATUS Status; 98 UINTN Size; 99 UINT8 *ReservedBuffer; 100 101 // 102 // If we are going to update a whole block 103 // 104 if ((Offset == 0) && (Length == BlockSize)) { 105 Status = UpdateOneBlock ( 106 FvbProtocol, 107 Lba, 108 BlockSize, 109 Buffer 110 ); 111 return Status; 112 } 113 114 // 115 // If it is not a full block update, we need to coalesce data in 116 // the block that is not going to be updated and new data together. 117 // 118 119 // 120 // Allocate a reserved buffer to make up the final buffer for update 121 // 122 ReservedBuffer = NULL; 123 ReservedBuffer = AllocatePool (BlockSize); 124 if (ReservedBuffer == NULL) { 125 return EFI_OUT_OF_RESOURCES; 126 } 127 // 128 // First get the original content of the block 129 // 130 Size = BlockSize; 131 Status = FvbProtocol->Read ( 132 FvbProtocol, 133 Lba, 134 0, 135 &Size, 136 ReservedBuffer 137 ); 138 if ((EFI_ERROR (Status)) || (Size != BlockSize)) { 139 FreePool (ReservedBuffer); 140 return Status; 141 } 142 143 // 144 // Overwrite the reserved buffer with new content 145 // 146 CopyMem (ReservedBuffer + Offset, Buffer, Length); 147 148 Status = UpdateOneBlock ( 149 FvbProtocol, 150 Lba, 151 BlockSize, 152 ReservedBuffer 153 ); 154 155 FreePool (ReservedBuffer); 156 157 return Status; 158 } 159 160 /** 161 Get the last write log, and check the status of last write. 162 If not complete, restart will be taken. 163 164 @param FvbHandle Handle of FVB protocol. 165 @param FtwProtocol FTW protocol instance. 166 @param ConfigData Config data on updating driver. 167 @param PrivateDataSize bytes from the private data 168 stored for this write. 169 @param PrivateData A pointer to a buffer. The function will copy. 170 @param Lba The logical block address of the last write. 171 @param Offset The offset within the block of the last write. 172 @param Length The length of the last write. 173 @param Pending A Boolean value with TRUE indicating 174 that the write was completed. 175 176 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. 177 @retval EFI_ABORTED The FTW work space is damaged. 178 @retval EFI_NOT_FOUND The last write is not done by this driver. 179 @retval EFI_SUCCESS Last write log is got. 180 181 **/ 182 EFI_STATUS 183 RetrieveLastWrite ( 184 IN EFI_HANDLE FvbHandle, 185 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol, 186 IN UPDATE_CONFIG_DATA *ConfigData, 187 IN UINTN PrivateDataSize, 188 IN OUT UPDATE_PRIVATE_DATA *PrivateData, 189 IN OUT EFI_LBA *Lba, 190 IN OUT UINTN *Offset, 191 IN OUT UINTN *Length, 192 IN OUT BOOLEAN *Pending 193 ) 194 { 195 EFI_STATUS Status; 196 EFI_GUID CallerId; 197 UINTN PrivateBufferSize; 198 BOOLEAN Complete; 199 VOID *PrivateDataBuffer; 200 201 // 202 // Get the last write 203 // 204 *Pending = FALSE; 205 PrivateBufferSize = PrivateDataSize; 206 PrivateDataBuffer = NULL; 207 Status = FtwProtocol->GetLastWrite ( 208 FtwProtocol, 209 &CallerId, 210 Lba, 211 Offset, 212 Length, 213 &PrivateBufferSize, 214 PrivateData, 215 &Complete 216 ); 217 if (EFI_ERROR (Status)) { 218 // 219 // If there is no incompleted record, return success. 220 // 221 if ((Status == EFI_NOT_FOUND) && Complete) { 222 return EFI_SUCCESS; 223 } else if (Status == EFI_BUFFER_TOO_SMALL) { 224 // 225 // If buffer too small, reallocate buffer and call getlastwrite again 226 // 227 PrivateDataBuffer = AllocatePool (PrivateBufferSize); 228 229 if (PrivateDataBuffer == NULL) { 230 return EFI_OUT_OF_RESOURCES; 231 } 232 233 Status = FtwProtocol->GetLastWrite ( 234 FtwProtocol, 235 &CallerId, 236 Lba, 237 Offset, 238 Length, 239 &PrivateBufferSize, 240 PrivateDataBuffer, 241 &Complete 242 ); 243 if (EFI_ERROR (Status)) { 244 FreePool ( PrivateDataBuffer); 245 return EFI_ABORTED; 246 } else { 247 CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize); 248 FreePool (PrivateDataBuffer); 249 PrivateDataBuffer = NULL; 250 } 251 } else { 252 return EFI_ABORTED; 253 } 254 } 255 256 *Pending = TRUE; 257 258 // 259 // If the caller is not the update driver, then return. 260 // The update driver cannot continue to perform the update 261 // 262 if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) { 263 return EFI_NOT_FOUND; 264 } 265 266 // 267 // Check the private data and see if it is the one I need. 268 // 269 if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) { 270 return EFI_NOT_FOUND; 271 } 272 273 // 274 // If the caller is the update driver and complete is not true, then restart(). 275 // 276 if (!Complete) { 277 // 278 // Re-start the update 279 // 280 Status = FtwProtocol->Restart ( 281 FtwProtocol, 282 FvbHandle 283 ); 284 // 285 // If restart() error, then abort(). 286 // 287 if (EFI_ERROR (Status)) { 288 FtwProtocol->Abort (FtwProtocol); 289 // 290 // Now set Pending as FALSE as this record has been cleared 291 // 292 *Pending = FALSE; 293 return EFI_SUCCESS; 294 } 295 296 } 297 298 return Status; 299 } 300 301 /** 302 Update the whole FV image in fault tolerant write method. 303 304 @param FvbHandle Handle of FVB protocol for the updated flash range. 305 @param FvbProtocol FVB protocol. 306 @param BlockMap Block array to specify flash area. 307 @param ConfigData Config data on updating driver. 308 @param ImageBuffer Image buffer to be updated. 309 @param ImageSize Image size. 310 311 @retval EFI_SUCCESS FV image is writed into flash. 312 @retval EFI_INVALID_PARAMETER Config data is not valid. 313 @retval EFI_NOT_FOUND FTW protocol doesn't exist. 314 @retval EFI_OUT_OF_RESOURCES No enough backup space. 315 @retval EFI_ABORTED Error happen when update FV. 316 317 **/ 318 EFI_STATUS 319 FaultTolerantUpdateOnWholeFv ( 320 IN EFI_HANDLE FvbHandle, 321 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 322 IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap, 323 IN UPDATE_CONFIG_DATA *ConfigData, 324 IN UINT8 *ImageBuffer, 325 IN UINTN ImageSize 326 ) 327 { 328 EFI_STATUS Status; 329 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; 330 UINTN MaxBlockSize; 331 UINTN FtwMaxBlockSize; 332 BOOLEAN Pending; 333 UPDATE_PRIVATE_DATA PrivateData; 334 EFI_LBA PendingLba; 335 EFI_LBA Lba; 336 UINTN PendingOffset; 337 UINTN Offset; 338 UINTN PendingLength; 339 UINTN Length; 340 EFI_FV_BLOCK_MAP_ENTRY *PtrMap; 341 UINTN NumOfBlocks; 342 UINTN Index; 343 UINT8 *UpdateBuffer; 344 345 if ((ConfigData->UpdateType != UpdateWholeFV) 346 || (!ConfigData->FaultTolerant)) { 347 return EFI_INVALID_PARAMETER; 348 } 349 350 // 351 // Get the FTW protocol 352 // 353 Status = gBS->LocateProtocol ( 354 &gEfiFaultTolerantWriteProtocolGuid, 355 NULL, 356 (VOID **) &FtwProtocol 357 ); 358 if (EFI_ERROR (Status)) { 359 return EFI_NOT_FOUND; 360 } 361 362 // 363 // Get the maximum block size of the FV, and number of blocks 364 // NumOfBlocks will be the NumOfUdpates. 365 // 366 MaxBlockSize = 0; 367 NumOfBlocks = 0; 368 PtrMap = BlockMap; 369 while (TRUE) { 370 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { 371 break; 372 } 373 if (MaxBlockSize < PtrMap->Length) { 374 MaxBlockSize = PtrMap->Length; 375 } 376 NumOfBlocks = NumOfBlocks + PtrMap->NumBlocks; 377 PtrMap++; 378 } 379 380 FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize); 381 // 382 // Not enough backup space. return directly 383 // 384 if (FtwMaxBlockSize < MaxBlockSize) { 385 return EFI_OUT_OF_RESOURCES; 386 } 387 388 PendingLba = 0; 389 PendingOffset = 0; 390 PendingLength = 0; 391 Pending = FALSE; 392 393 // 394 // Fault Tolerant Write can only support actual fault tolerance if the write 395 // is a reclaim operation, which means the data buffer (new and old) are 396 // acutally both stored in flash. But for component update write, the data 397 // are now in memory. So we cannot actually recover the data after power 398 // failure. 399 // 400 Status = RetrieveLastWrite ( 401 FvbHandle, 402 FtwProtocol, 403 ConfigData, 404 sizeof (UPDATE_PRIVATE_DATA), 405 &PrivateData, 406 &PendingLba, 407 &PendingOffset, 408 &PendingLength, 409 &Pending 410 ); 411 412 if (Pending && (Status == EFI_NOT_FOUND)) { 413 // 414 // Cannot continue with the write operation 415 // 416 return EFI_ABORTED; 417 } 418 419 if (EFI_ERROR(Status)) { 420 return EFI_ABORTED; 421 } 422 423 // 424 // Currently we start from the pending write if there is any. But as we 425 // are going to update a whole FV, we can just abort last write and start 426 // from the very begining. 427 // 428 if (!Pending) { 429 // 430 // Now allocte the update private data in FTW. If there is pending 431 // write, it has already been allocated and no need to allocate here. 432 // 433 Status = FtwProtocol->Allocate ( 434 FtwProtocol, 435 &gEfiCallerIdGuid, 436 sizeof (UPDATE_PRIVATE_DATA), 437 NumOfBlocks 438 ); 439 if (EFI_ERROR (Status)) { 440 return Status; 441 } 442 } 443 444 // 445 // Perform the update now. If there are pending writes, we need to 446 // start from the pending write instead of the very beginning. 447 // 448 PtrMap = BlockMap; 449 Lba = 0; 450 Offset = 0; 451 UpdateBuffer = ImageBuffer; 452 CopyMem ( 453 (VOID *) &PrivateData.FileGuid, 454 (VOID *) &ConfigData->FileGuid, 455 sizeof (EFI_GUID) 456 ); 457 458 while (TRUE) { 459 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { 460 break; 461 } 462 Length = (UINTN)PtrMap->Length; 463 for (Index = 0; Index < PtrMap->NumBlocks; Index++) { 464 465 // 466 // Add an extra check here to see if the pending record is correct 467 // 468 if (Pending && (Lba == PendingLba)) { 469 if ((PendingOffset != Offset) || (PendingLength != Length)) { 470 // 471 // Error. 472 // 473 Status = EFI_ABORTED; 474 break; 475 } 476 } 477 478 if ((!Pending) || (Lba >= PendingLba)) { 479 Status = FtwProtocol->Write ( 480 FtwProtocol, 481 Lba, // Lba 482 Offset, // Offset 483 Length, // Size 484 &PrivateData, // Private Data 485 FvbHandle, // FVB handle 486 UpdateBuffer // Buffer 487 ); 488 } 489 490 if (EFI_ERROR (Status)) { 491 break; 492 } 493 Lba++; 494 UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + Length); 495 } 496 497 if (EFI_ERROR (Status)) { 498 break; 499 } 500 PtrMap++; 501 } 502 503 return Status; 504 505 } 506 507 /** 508 Directly update the whole FV image without fault tolerant write method. 509 510 @param FvbHandle Handle of FVB protocol for the updated flash range. 511 @param FvbProtocol FVB protocol. 512 @param BlockMap Block array to specify flash area. 513 @param ConfigData Config data on updating driver. 514 @param ImageBuffer Image buffer to be updated. 515 @param ImageSize Image size. 516 517 @retval EFI_SUCCESS FV image is writed into flash. 518 @retval EFI_INVALID_PARAMETER Config data is not valid. 519 @retval EFI_ABORTED Error happen when update FV. 520 521 **/ 522 EFI_STATUS 523 NonFaultTolerantUpdateOnWholeFv ( 524 IN EFI_HANDLE FvbHandle, 525 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 526 IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap, 527 IN UPDATE_CONFIG_DATA *ConfigData, 528 IN UINT8 *ImageBuffer, 529 IN UINTN ImageSize 530 ) 531 { 532 EFI_STATUS Status; 533 EFI_FV_BLOCK_MAP_ENTRY *PtrMap; 534 UINTN Index; 535 EFI_LBA UpdateLba; 536 UINT8 *UpdateBuffer; 537 UINTN UpdateSize; 538 539 if ((ConfigData->UpdateType != UpdateWholeFV ) 540 || (ConfigData->FaultTolerant)) { 541 return EFI_INVALID_PARAMETER; 542 } 543 544 Status = EFI_SUCCESS; 545 PtrMap = BlockMap; 546 UpdateLba = 0; 547 UpdateBuffer = ImageBuffer; 548 549 // 550 // Perform the update now 551 // 552 while (TRUE) { 553 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { 554 break; 555 } 556 UpdateSize = (UINTN)PtrMap->Length; 557 for (Index = 0; Index < PtrMap->NumBlocks; Index++) { 558 Status = UpdateOneBlock ( 559 FvbProtocol, 560 UpdateLba, 561 UpdateSize, 562 UpdateBuffer 563 ); 564 if (EFI_ERROR (Status)) { 565 break; 566 } 567 568 UpdateLba++; 569 UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize); 570 } 571 572 if (EFI_ERROR (Status)) { 573 break; 574 } 575 PtrMap++; 576 } 577 578 return Status; 579 } 580 581 /** 582 Update the whole FV image, and reinsall FVB protocol for the updated FV image. 583 584 @param FvbHandle Handle of FVB protocol for the updated flash range. 585 @param FvbProtocol FVB protocol. 586 @param ConfigData Config data on updating driver. 587 @param ImageBuffer Image buffer to be updated. 588 @param ImageSize Image size. 589 590 @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV. 591 Or Image size is not same to the size of whole FV. 592 @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated. 593 @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled. 594 595 **/ 596 EFI_STATUS 597 PerformUpdateOnWholeFv ( 598 IN EFI_HANDLE FvbHandle, 599 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 600 IN UPDATE_CONFIG_DATA *ConfigData, 601 IN UINT8 *ImageBuffer, 602 IN UINTN ImageSize 603 ) 604 { 605 EFI_STATUS Status; 606 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 607 EFI_FV_BLOCK_MAP_ENTRY *BlockMap; 608 CHAR16 *TmpStr; 609 610 if (ConfigData->UpdateType != UpdateWholeFV) { 611 return EFI_INVALID_PARAMETER; 612 } 613 614 // 615 // Get the header of the firmware volume 616 // 617 FwVolHeader = NULL; 618 FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength); 619 if (FwVolHeader == NULL) { 620 return EFI_OUT_OF_RESOURCES; 621 } 622 CopyMem ( 623 FwVolHeader, 624 (VOID *) ((UINTN) (ConfigData->BaseAddress)), 625 ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength 626 ); 627 628 // 629 // Check if ImageSize is the same as the size of the whole FV 630 // 631 if ((UINT64)ImageSize != FwVolHeader->FvLength) { 632 FreePool (FwVolHeader); 633 return EFI_INVALID_PARAMETER; 634 } 635 636 // 637 // Print on screen 638 // 639 TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL); 640 if (TmpStr != NULL) { 641 Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)); 642 FreePool (TmpStr); 643 } 644 645 DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n", 646 ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress))); 647 648 // 649 // Get the block map of the firmware volume 650 // 651 BlockMap = &(FwVolHeader->BlockMap[0]); 652 653 // 654 // It is about the same if we are going to fault tolerantly update 655 // a certain FV in our current design. But we divide non-fault tolerant 656 // and fault tolerant udpate here for better maintenance as fault 657 // tolerance may change and may be done more wisely if we have space. 658 // 659 if (ConfigData->FaultTolerant) { 660 Status = FaultTolerantUpdateOnWholeFv ( 661 FvbHandle, 662 FvbProtocol, 663 BlockMap, 664 ConfigData, 665 ImageBuffer, 666 ImageSize 667 ); 668 } else { 669 Status = NonFaultTolerantUpdateOnWholeFv ( 670 FvbHandle, 671 FvbProtocol, 672 BlockMap, 673 ConfigData, 674 ImageBuffer, 675 ImageSize 676 ); 677 } 678 679 FreePool (FwVolHeader); 680 681 if (EFI_ERROR (Status)) { 682 return Status; 683 } 684 685 // 686 // As the whole FV has been replaced, the FV driver shall re-parse the 687 // firmware volume. So re-install FVB protocol here 688 // 689 Status = gBS->ReinstallProtocolInterface ( 690 FvbHandle, 691 &gEfiFirmwareVolumeBlockProtocolGuid, 692 FvbProtocol, 693 FvbProtocol 694 ); 695 696 return Status; 697 } 698 699 /** 700 Update certain file in the FV. 701 702 @param FvbHandle Handle of FVB protocol for the updated flash range. 703 @param FvbProtocol FVB protocol. 704 @param ConfigData Config data on updating driver. 705 @param ImageBuffer Image buffer to be updated. 706 @param ImageSize Image size. 707 @param FileType FFS file type. 708 @param FileAttributes FFS file attribute 709 710 @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile. 711 Or Image size is not same to the size of whole FV. 712 @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated. 713 @retval EFI_SUCCESS The FFS file is added into FV. 714 715 **/ 716 EFI_STATUS 717 PerformUpdateOnFvFile ( 718 IN EFI_HANDLE FvbHandle, 719 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 720 IN UPDATE_CONFIG_DATA *ConfigData, 721 IN UINT8 *ImageBuffer, 722 IN UINTN ImageSize, 723 IN EFI_FV_FILETYPE FileType, 724 IN EFI_FV_FILE_ATTRIBUTES FileAttributes 725 ) 726 { 727 EFI_STATUS Status; 728 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol; 729 EFI_FV_WRITE_FILE_DATA FileData; 730 CHAR16 *TmpStr; 731 732 if (ConfigData->UpdateType != UpdateFvFile) { 733 return EFI_INVALID_PARAMETER; 734 } 735 736 // 737 // Print on screen 738 // 739 TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL); 740 if (TmpStr != NULL) { 741 Print (TmpStr, &(ConfigData->FileGuid)); 742 FreePool (TmpStr); 743 } 744 745 DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n", 746 &(ConfigData->FileGuid))); 747 748 // 749 // Get Firmware volume protocol on this FVB protocol 750 // 751 Status = gBS->HandleProtocol ( 752 FvbHandle, 753 &gEfiFirmwareVolume2ProtocolGuid, 754 (VOID **) &FwVolProtocol 755 ); 756 if (EFI_ERROR (Status)) { 757 return Status; 758 } 759 760 // 761 // If it is a PEIM, we need first to rebase it before committing 762 // the write to target 763 // 764 if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM ) 765 || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { 766 return EFI_UNSUPPORTED; 767 } 768 769 FileData.NameGuid = &(ConfigData->FileGuid); 770 FileData.Type = FileType; 771 FileData.FileAttributes = FileAttributes; 772 FileData.Buffer = ImageBuffer; 773 FileData.BufferSize = (UINT32) ImageSize; 774 775 Status = FwVolProtocol->WriteFile ( 776 FwVolProtocol, 777 1, // NumberOfFiles 778 (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant, 779 &FileData 780 ); 781 return Status; 782 } 783 784 /** 785 Update the buffer into flash area in fault tolerant write method. 786 787 @param ImageBuffer Image buffer to be updated. 788 @param SizeLeft Size of the image buffer. 789 @param UpdatedSize Size of the updated buffer. 790 @param ConfigData Config data on updating driver. 791 @param FlashAddress Flash address to be updated as start address. 792 @param FvbProtocol FVB protocol. 793 @param FvbHandle Handle of FVB protocol for the updated flash range. 794 795 @retval EFI_SUCCESS Buffer data is updated into flash. 796 @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. 797 @retval EFI_NOT_FOUND FTW protocol doesn't exist. 798 @retval EFI_OUT_OF_RESOURCES No enough backup space. 799 @retval EFI_ABORTED Error happen when update flash area. 800 801 **/ 802 EFI_STATUS 803 FaultTolerantUpdateOnPartFv ( 804 IN UINT8 *ImageBuffer, 805 IN UINTN SizeLeft, 806 IN OUT UINTN *UpdatedSize, 807 IN UPDATE_CONFIG_DATA *ConfigData, 808 IN EFI_PHYSICAL_ADDRESS FlashAddress, 809 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 810 IN EFI_HANDLE FvbHandle 811 ) 812 { 813 EFI_STATUS Status; 814 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 815 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp; 816 EFI_PHYSICAL_ADDRESS BaseAddress; 817 EFI_PHYSICAL_ADDRESS FvBase; 818 EFI_PHYSICAL_ADDRESS NextBlock; 819 EFI_FV_BLOCK_MAP_ENTRY *BlockMap; 820 EFI_FV_BLOCK_MAP_ENTRY *PtrMap; 821 UINTN NumOfUpdates; 822 UINTN TotalSize; 823 EFI_PHYSICAL_ADDRESS StartAddress; 824 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; 825 UINTN MaxBlockSize; 826 UINTN FtwMaxBlockSize; 827 BOOLEAN Pending; 828 UPDATE_PRIVATE_DATA PrivateData; 829 EFI_LBA PendingLba; 830 EFI_LBA Lba; 831 UINTN BlockSize; 832 UINTN PendingOffset; 833 UINTN Offset; 834 UINTN PendingLength; 835 UINTN Length; 836 UINTN Index; 837 UINT8 *Image; 838 839 // 840 // Get the block map to update the block one by one 841 // 842 Status = FvbProtocol->GetPhysicalAddress ( 843 FvbProtocol, 844 &FvBase 845 ); 846 if (EFI_ERROR (Status)) { 847 return Status; 848 } 849 850 FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; 851 if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) { 852 return EFI_INVALID_PARAMETER; 853 } 854 855 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool ( 856 FwVolHeaderTmp->HeaderLength, 857 FwVolHeaderTmp 858 ); 859 if (FwVolHeader == NULL) { 860 return EFI_OUT_OF_RESOURCES; 861 } 862 863 // 864 // For fault tolerant write, we have to know how many blocks we need to 865 // update. So we will calculate number of updates and max block size first 866 // 867 NumOfUpdates = 0; 868 MaxBlockSize = 0; 869 TotalSize = SizeLeft; 870 StartAddress = FlashAddress; 871 BaseAddress = FvBase; 872 BlockMap = &(FwVolHeader->BlockMap[0]); 873 PtrMap = BlockMap; 874 875 while (TotalSize > 0) { 876 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { 877 break; 878 } 879 880 BlockSize = PtrMap->Length; 881 for (Index = 0; Index < PtrMap->NumBlocks; Index++) { 882 NextBlock = BaseAddress + BlockSize; 883 // 884 // Check if this block need to be updated 885 // 886 if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) { 887 // 888 // Get the maximum block size 889 // 890 if (MaxBlockSize < BlockSize) { 891 MaxBlockSize = BlockSize; 892 } 893 894 // 895 // This block shall be udpated. So increment number of updates 896 // 897 NumOfUpdates++; 898 Offset = (UINTN) (StartAddress - BaseAddress); 899 Length = TotalSize; 900 if ((Length + Offset ) > BlockSize) { 901 Length = BlockSize - Offset; 902 } 903 904 StartAddress = StartAddress + Length; 905 TotalSize = TotalSize - Length; 906 if (TotalSize <= 0) { 907 break; 908 } 909 } 910 BaseAddress = NextBlock; 911 } 912 PtrMap++; 913 } 914 915 // 916 // Get the FTW protocol 917 // 918 Status = gBS->LocateProtocol ( 919 &gEfiFaultTolerantWriteProtocolGuid, 920 NULL, 921 (VOID **) &FtwProtocol 922 ); 923 if (EFI_ERROR (Status)) { 924 FreePool (FwVolHeader); 925 return EFI_NOT_FOUND; 926 } 927 928 FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize); 929 930 // 931 // Not enough backup space. return directly 932 // 933 if (FtwMaxBlockSize < MaxBlockSize) { 934 FreePool (FwVolHeader); 935 return EFI_OUT_OF_RESOURCES; 936 } 937 938 PendingLba = 0; 939 PendingOffset = 0; 940 PendingLength = 0; 941 Pending = FALSE; 942 943 // 944 // Fault Tolerant Write can only support actual fault tolerance if the write 945 // is a reclaim operation, which means the data buffer (new and old) are 946 // acutally both stored in flash. But for component update write, the data 947 // are now in memory. So we cannot actually recover the data after power 948 // failure. 949 // 950 Status = RetrieveLastWrite ( 951 FvbHandle, 952 FtwProtocol, 953 ConfigData, 954 sizeof (UPDATE_PRIVATE_DATA), 955 &PrivateData, 956 &PendingLba, 957 &PendingOffset, 958 &PendingLength, 959 &Pending 960 ); 961 if (Pending && (Status == EFI_NOT_FOUND)) { 962 // 963 // I'm not the owner of the pending fault tolerant write record 964 // Cannot continue with the write operation 965 // 966 FreePool (FwVolHeader); 967 return EFI_ABORTED; 968 } 969 970 if (EFI_ERROR(Status)) { 971 FreePool (FwVolHeader); 972 return EFI_ABORTED; 973 } 974 975 // 976 // Currently we start from the pending write if there is any. But if the 977 // caller is exactly the same, and the new data is already a in memory, (it 978 // cannot be stored in flash in last write,) we can just abort last write 979 // and start from the very begining. 980 // 981 if (!Pending) { 982 // 983 // Now allocte the update private data in FTW. If there is pending 984 // write, it has already been allocated and no need to allocate here. 985 // 986 Status = FtwProtocol->Allocate ( 987 FtwProtocol, 988 &gEfiCallerIdGuid, 989 sizeof (UPDATE_PRIVATE_DATA), 990 NumOfUpdates 991 ); 992 if (EFI_ERROR (Status)) { 993 FreePool (FwVolHeader); 994 return Status; 995 } 996 } 997 998 // 999 // Perform the update now. If there are pending writes, we need to 1000 // start from the pending write instead of the very beginning. 1001 // 1002 TotalSize = SizeLeft; 1003 Lba = 0; 1004 StartAddress = FlashAddress; 1005 BaseAddress = FvBase; 1006 PtrMap = BlockMap; 1007 Image = ImageBuffer; 1008 CopyMem ( 1009 (VOID *) &PrivateData.FileGuid, 1010 (VOID *) &ConfigData->FileGuid, 1011 sizeof (EFI_GUID) 1012 ); 1013 1014 while (TotalSize > 0) { 1015 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) { 1016 break; 1017 } 1018 1019 BlockSize = (UINTN)PtrMap->Length; 1020 for (Index = 0; Index < PtrMap->NumBlocks; Index++) { 1021 NextBlock = BaseAddress + BlockSize; 1022 if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) { 1023 // 1024 // So we need to update this block 1025 // 1026 Offset = (UINTN) (StartAddress - BaseAddress); 1027 Length = TotalSize; 1028 if ((Length + Offset ) > BlockSize) { 1029 Length = BlockSize - Offset; 1030 } 1031 1032 // 1033 // Add an extra check here to see if the pending record is correct 1034 // 1035 if (Pending && (Lba == PendingLba)) { 1036 if ((PendingOffset != Offset) || (PendingLength != Length)) { 1037 // 1038 // Error. 1039 // 1040 Status = EFI_ABORTED; 1041 break; 1042 } 1043 } 1044 1045 if ((!Pending) || (Lba >= PendingLba)) { 1046 DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length)); 1047 Status = FtwProtocol->Write ( 1048 FtwProtocol, 1049 Lba, // Lba 1050 Offset, // Offset 1051 Length, // Size 1052 &PrivateData, // Private Data 1053 FvbHandle, // FVB handle 1054 Image // Buffer 1055 ); 1056 if (EFI_ERROR (Status)) { 1057 break; 1058 } 1059 } 1060 1061 // 1062 // Now increment StartAddress, ImageBuffer and decrease the 1063 // left size to prepare for the next block update. 1064 // 1065 StartAddress = StartAddress + Length; 1066 Image = Image + Length; 1067 TotalSize = TotalSize - Length; 1068 if (TotalSize <= 0) { 1069 break; 1070 } 1071 } 1072 BaseAddress = NextBlock; 1073 Lba++; 1074 } 1075 1076 if (EFI_ERROR (Status)) { 1077 break; 1078 } 1079 PtrMap++; 1080 } 1081 1082 FreePool (FwVolHeader); 1083 1084 *UpdatedSize = SizeLeft - TotalSize; 1085 1086 return EFI_SUCCESS; 1087 } 1088 1089 /** 1090 Directly update the buffer into flash area without fault tolerant write method. 1091 1092 @param ImageBuffer Image buffer to be updated. 1093 @param SizeLeft Size of the image buffer. 1094 @param UpdatedSize Size of the updated buffer. 1095 @param FlashAddress Flash address to be updated as start address. 1096 @param FvbProtocol FVB protocol. 1097 @param FvbHandle Handle of FVB protocol for the updated flash range. 1098 1099 @retval EFI_SUCCESS Buffer data is updated into flash. 1100 @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area. 1101 @retval EFI_OUT_OF_RESOURCES No enough backup space. 1102 1103 **/ 1104 EFI_STATUS 1105 NonFaultTolerantUpdateOnPartFv ( 1106 IN UINT8 *ImageBuffer, 1107 IN UINTN SizeLeft, 1108 IN OUT UINTN *UpdatedSize, 1109 IN EFI_PHYSICAL_ADDRESS FlashAddress, 1110 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol, 1111 IN EFI_HANDLE FvbHandle 1112 ) 1113 { 1114 EFI_STATUS Status; 1115 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 1116 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp; 1117 EFI_PHYSICAL_ADDRESS BaseAddress; 1118 EFI_PHYSICAL_ADDRESS NextBlock; 1119 EFI_FV_BLOCK_MAP_ENTRY *BlockMap; 1120 UINTN Index; 1121 UINTN TotalSize; 1122 UINTN BlockSize; 1123 EFI_LBA Lba; 1124 UINTN Offset; 1125 UINTN Length; 1126 UINT8 *Image; 1127 1128 // 1129 // Get the block map to update the block one by one 1130 // 1131 Status = FvbProtocol->GetPhysicalAddress ( 1132 FvbProtocol, 1133 &BaseAddress 1134 ); 1135 if (EFI_ERROR (Status)) { 1136 return Status; 1137 } 1138 1139 FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress; 1140 if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) { 1141 return EFI_INVALID_PARAMETER; 1142 } 1143 1144 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool ( 1145 FwVolHeaderTmp->HeaderLength, 1146 FwVolHeaderTmp 1147 ); 1148 if (FwVolHeader == NULL) { 1149 return EFI_OUT_OF_RESOURCES; 1150 } 1151 1152 Image = ImageBuffer; 1153 TotalSize = SizeLeft; 1154 BlockMap = &(FwVolHeader->BlockMap[0]); 1155 Lba = 0; 1156 1157 while (TotalSize > 0) { 1158 if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) { 1159 break; 1160 } 1161 1162 BlockSize = BlockMap->Length; 1163 for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) { 1164 NextBlock = BaseAddress + BlockSize; 1165 if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) { 1166 // 1167 // So we need to update this block 1168 // 1169 Offset = (UINTN) FlashAddress - (UINTN) BaseAddress; 1170 Length = TotalSize; 1171 if ((Length + Offset ) > BlockSize) { 1172 Length = BlockSize - Offset; 1173 } 1174 1175 DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length)); 1176 // 1177 // Update the block 1178 // 1179 Status = UpdateBufferInOneBlock ( 1180 FvbProtocol, 1181 Lba, 1182 Offset, 1183 Length, 1184 BlockSize, 1185 Image 1186 ); 1187 if (EFI_ERROR (Status)) { 1188 FreePool (FwVolHeader); 1189 return Status; 1190 } 1191 1192 // 1193 // Now increment FlashAddress, ImageBuffer and decrease the 1194 // left size to prepare for the next block update. 1195 // 1196 FlashAddress = FlashAddress + Length; 1197 Image = Image + Length; 1198 TotalSize = TotalSize - Length; 1199 if (TotalSize <= 0) { 1200 break; 1201 } 1202 } 1203 BaseAddress = NextBlock; 1204 Lba++; 1205 } 1206 1207 if (EFI_ERROR (Status)) { 1208 break; 1209 } 1210 BlockMap++; 1211 } 1212 1213 FreePool (FwVolHeader); 1214 1215 *UpdatedSize = SizeLeft - TotalSize; 1216 1217 return EFI_SUCCESS; 1218 } 1219