Home | History | Annotate | Download | only in FaultTolerantWriteDxe
      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