Home | History | Annotate | Download | only in FaultTolerantWriteDxe
      1 /** @file
      2 
      3   These are the common Fault Tolerant Write (FTW) functions that are shared
      4   by DXE FTW driver and SMM FTW driver.
      5 
      6 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The 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 "FaultTolerantWrite.h"
     18 
     19 //
     20 // Fault Tolerant Write Protocol API
     21 //
     22 /**
     23   Query the largest block that may be updated in a fault tolerant manner.
     24 
     25 
     26   @param This            The pointer to this protocol instance.
     27   @param BlockSize       A pointer to a caller allocated UINTN that is updated to
     28                          indicate the size of the largest block that can be updated.
     29 
     30   @return EFI_SUCCESS   The function completed successfully
     31 
     32 **/
     33 EFI_STATUS
     34 EFIAPI
     35 FtwGetMaxBlockSize (
     36   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL    *This,
     37   OUT UINTN                               *BlockSize
     38   )
     39 {
     40   EFI_FTW_DEVICE  *FtwDevice;
     41 
     42   if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
     43     return EFI_UNSUPPORTED;
     44   }
     45 
     46   FtwDevice   = FTW_CONTEXT_FROM_THIS (This);
     47 
     48   *BlockSize  = FtwDevice->SpareAreaLength;
     49 
     50   return EFI_SUCCESS;
     51 }
     52 
     53 /**
     54   Allocates space for the protocol to maintain information about writes.
     55   Since writes must be completed in a fault tolerant manner and multiple
     56   updates will require more resources to be successful, this function
     57   enables the protocol to ensure that enough space exists to track
     58   information about the upcoming writes.
     59 
     60   All writes must be completed or aborted before another fault tolerant write can occur.
     61 
     62   @param This            The pointer to this protocol instance.
     63   @param CallerId        The GUID identifying the write.
     64   @param PrivateDataSize The size of the caller's private data
     65                          that must be recorded for each write.
     66   @param NumberOfWrites  The number of fault tolerant block writes
     67                          that will need to occur.
     68 
     69   @return EFI_SUCCESS        The function completed successfully
     70   @retval EFI_ABORTED        The function could not complete successfully.
     71   @retval EFI_ACCESS_DENIED  All allocated writes have not been completed.
     72 
     73 **/
     74 EFI_STATUS
     75 EFIAPI
     76 FtwAllocate (
     77   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL    *This,
     78   IN EFI_GUID                             *CallerId,
     79   IN UINTN                                PrivateDataSize,
     80   IN UINTN                                NumberOfWrites
     81   )
     82 {
     83   EFI_STATUS                      Status;
     84   UINTN                           Offset;
     85   EFI_FTW_DEVICE                  *FtwDevice;
     86   EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
     87 
     88   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
     89 
     90   Status    = WorkSpaceRefresh (FtwDevice);
     91   if (EFI_ERROR (Status)) {
     92     return EFI_ABORTED;
     93   }
     94   //
     95   // Check if there is enough space for the coming allocation
     96   //
     97   if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
     98     DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
     99     return EFI_BUFFER_TOO_SMALL;
    100   }
    101   //
    102   // Find the last write header and record.
    103   // If the FtwHeader is complete, skip the completed last write header/records
    104   //
    105   FtwHeader = FtwDevice->FtwLastWriteHeader;
    106 
    107   //
    108   // Previous write has not completed, access denied.
    109   //
    110   if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
    111     return EFI_ACCESS_DENIED;
    112   }
    113   //
    114   // If workspace is not enough, then reclaim workspace
    115   //
    116   Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
    117   if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
    118     Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
    119     if (EFI_ERROR (Status)) {
    120       return EFI_ABORTED;
    121     }
    122 
    123     FtwHeader = FtwDevice->FtwLastWriteHeader;
    124   }
    125   //
    126   // Prepare FTW write header,
    127   // overwrite the buffer and write to workspace.
    128   //
    129   FtwHeader->WritesAllocated  = FTW_INVALID_STATE;
    130   FtwHeader->Complete         = FTW_INVALID_STATE;
    131   CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
    132   FtwHeader->NumberOfWrites   = NumberOfWrites;
    133   FtwHeader->PrivateDataSize  = PrivateDataSize;
    134   FtwHeader->HeaderAllocated  = FTW_VALID_STATE;
    135 
    136   Status = WriteWorkSpaceData (
    137              FtwDevice->FtwFvBlock,
    138              FtwDevice->WorkBlockSize,
    139              FtwDevice->FtwWorkSpaceLba,
    140              FtwDevice->FtwWorkSpaceBase + Offset,
    141              sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER),
    142              (UINT8 *) FtwHeader
    143              );
    144   if (EFI_ERROR (Status)) {
    145     return EFI_ABORTED;
    146   }
    147   //
    148   // Update Header->WriteAllocated as VALID
    149   //
    150   Status = FtwUpdateFvState (
    151             FtwDevice->FtwFvBlock,
    152             FtwDevice->WorkBlockSize,
    153             FtwDevice->FtwWorkSpaceLba,
    154             FtwDevice->FtwWorkSpaceBase + Offset,
    155             WRITES_ALLOCATED
    156             );
    157   if (EFI_ERROR (Status)) {
    158     return EFI_ABORTED;
    159   }
    160 
    161   DEBUG (
    162     (EFI_D_INFO,
    163     "Ftw: Allocate() success, Caller:%g, # %d\n",
    164     CallerId,
    165     NumberOfWrites)
    166     );
    167 
    168   return EFI_SUCCESS;
    169 }
    170 
    171 
    172 /**
    173   Write a record with fault tolerant manner.
    174   Since the content has already backuped in spare block, the write is
    175   guaranteed to be completed with fault tolerant manner.
    176 
    177   @param This            The pointer to this protocol instance.
    178   @param Fvb             The FVB protocol that provides services for
    179                          reading, writing, and erasing the target block.
    180   @param BlockSize       The size of the block.
    181 
    182   @retval  EFI_SUCCESS          The function completed successfully
    183   @retval  EFI_ABORTED          The function could not complete successfully
    184 
    185 **/
    186 EFI_STATUS
    187 FtwWriteRecord (
    188   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
    189   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb,
    190   IN UINTN                                 BlockSize
    191   )
    192 {
    193   EFI_STATUS                      Status;
    194   EFI_FTW_DEVICE                  *FtwDevice;
    195   EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
    196   EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
    197   UINTN                           Offset;
    198   UINTN                           NumberOfWriteBlocks;
    199 
    200   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
    201 
    202   //
    203   // Spare Complete but Destination not complete,
    204   // Recover the target block with the spare block.
    205   //
    206   Header  = FtwDevice->FtwLastWriteHeader;
    207   Record  = FtwDevice->FtwLastWriteRecord;
    208 
    209   //
    210   // IF target block is working block, THEN Flush Spare Block To Working Block;
    211   // ELSE flush spare block to target block, which may be boot block after all.
    212   //
    213   if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
    214     //
    215     // If target block is working block,
    216     // it also need to set SPARE_COMPLETED to spare block.
    217     //
    218     Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
    219     Status = FtwUpdateFvState (
    220               FtwDevice->FtwBackupFvb,
    221               FtwDevice->SpareBlockSize,
    222               FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
    223               FtwDevice->FtwWorkSpaceBaseInSpare + Offset,
    224               SPARE_COMPLETED
    225               );
    226     if (EFI_ERROR (Status)) {
    227       return EFI_ABORTED;
    228     }
    229 
    230     Status = FlushSpareBlockToWorkingBlock (FtwDevice);
    231   } else if (IsBootBlock (FtwDevice, Fvb)) {
    232     //
    233     // Update boot block
    234     //
    235     Status = FlushSpareBlockToBootBlock (FtwDevice);
    236   } else {
    237     //
    238     // Update blocks other than working block or boot block
    239     //
    240     NumberOfWriteBlocks = FTW_BLOCKS ((UINTN) (Record->Offset + Record->Length), BlockSize);
    241     Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba, BlockSize, NumberOfWriteBlocks);
    242   }
    243 
    244   if (EFI_ERROR (Status)) {
    245     return EFI_ABORTED;
    246   }
    247   //
    248   // Record the DestionationComplete in record
    249   //
    250   Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
    251   Status = FtwUpdateFvState (
    252             FtwDevice->FtwFvBlock,
    253             FtwDevice->WorkBlockSize,
    254             FtwDevice->FtwWorkSpaceLba,
    255             FtwDevice->FtwWorkSpaceBase + Offset,
    256             DEST_COMPLETED
    257             );
    258   if (EFI_ERROR (Status)) {
    259     return EFI_ABORTED;
    260   }
    261 
    262   Record->DestinationComplete = FTW_VALID_STATE;
    263 
    264   //
    265   // If this is the last Write in these write sequence,
    266   // set the complete flag of write header.
    267   //
    268   if (IsLastRecordOfWrites (Header, Record)) {
    269     Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
    270     Status = FtwUpdateFvState (
    271               FtwDevice->FtwFvBlock,
    272               FtwDevice->WorkBlockSize,
    273               FtwDevice->FtwWorkSpaceLba,
    274               FtwDevice->FtwWorkSpaceBase + Offset,
    275               WRITES_COMPLETED
    276               );
    277     Header->Complete = FTW_VALID_STATE;
    278     if (EFI_ERROR (Status)) {
    279       return EFI_ABORTED;
    280     }
    281   }
    282 
    283   return EFI_SUCCESS;
    284 }
    285 
    286 /**
    287   Starts a target block update. This function will record data about write
    288   in fault tolerant storage and will complete the write in a recoverable
    289   manner, ensuring at all times that either the original contents or
    290   the modified contents are available.
    291 
    292   @param This            The pointer to this protocol instance.
    293   @param Lba             The logical block address of the target block.
    294   @param Offset          The offset within the target block to place the data.
    295   @param Length          The number of bytes to write to the target block.
    296   @param PrivateData     A pointer to private data that the caller requires to
    297                          complete any pending writes in the event of a fault.
    298   @param FvBlockHandle   The handle of FVB protocol that provides services for
    299                          reading, writing, and erasing the target block.
    300   @param Buffer          The data to write.
    301 
    302   @retval EFI_SUCCESS          The function completed successfully
    303   @retval EFI_ABORTED          The function could not complete successfully.
    304   @retval EFI_BAD_BUFFER_SIZE  The input data can't fit within the spare block.
    305                                Offset + *NumBytes > SpareAreaLength.
    306   @retval EFI_ACCESS_DENIED    No writes have been allocated.
    307   @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
    308   @retval EFI_NOT_FOUND        Cannot find FVB protocol by handle.
    309 
    310 **/
    311 EFI_STATUS
    312 EFIAPI
    313 FtwWrite (
    314   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
    315   IN EFI_LBA                               Lba,
    316   IN UINTN                                 Offset,
    317   IN UINTN                                 Length,
    318   IN VOID                                  *PrivateData,
    319   IN EFI_HANDLE                            FvBlockHandle,
    320   IN VOID                                  *Buffer
    321   )
    322 {
    323   EFI_STATUS                          Status;
    324   EFI_FTW_DEVICE                      *FtwDevice;
    325   EFI_FAULT_TOLERANT_WRITE_HEADER     *Header;
    326   EFI_FAULT_TOLERANT_WRITE_RECORD     *Record;
    327   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
    328   UINTN                               MyLength;
    329   UINTN                               MyOffset;
    330   UINTN                               MyBufferSize;
    331   UINT8                               *MyBuffer;
    332   UINTN                               SpareBufferSize;
    333   UINT8                               *SpareBuffer;
    334   UINTN                               Index;
    335   UINT8                               *Ptr;
    336   EFI_PHYSICAL_ADDRESS                FvbPhysicalAddress;
    337   UINTN                               BlockSize;
    338   UINTN                               NumberOfBlocks;
    339   UINTN                               NumberOfWriteBlocks;
    340   UINTN                               WriteLength;
    341 
    342   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
    343 
    344   Status    = WorkSpaceRefresh (FtwDevice);
    345   if (EFI_ERROR (Status)) {
    346     return EFI_ABORTED;
    347   }
    348 
    349   Header  = FtwDevice->FtwLastWriteHeader;
    350   Record  = FtwDevice->FtwLastWriteRecord;
    351 
    352   if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
    353     if (PrivateData == NULL) {
    354       //
    355       // Ftw Write Header is not allocated.
    356       // No additional private data, the private data size is zero. Number of record can be set to 1.
    357       //
    358       Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
    359       if (EFI_ERROR (Status)) {
    360         return Status;
    361       }
    362     } else {
    363       //
    364       // Ftw Write Header is not allocated
    365       // Additional private data is not NULL, the private data size can't be determined.
    366       //
    367       DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
    368       DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
    369       return EFI_NOT_READY;
    370     }
    371   }
    372 
    373   //
    374   // If Record is out of the range of Header, return access denied.
    375   //
    376   if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
    377     return EFI_ACCESS_DENIED;
    378   }
    379 
    380   //
    381   // Check the COMPLETE flag of last write header
    382   //
    383   if (Header->Complete == FTW_VALID_STATE) {
    384     return EFI_ACCESS_DENIED;
    385   }
    386 
    387   if (Record->DestinationComplete == FTW_VALID_STATE) {
    388     return EFI_ACCESS_DENIED;
    389   }
    390 
    391   if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
    392     return EFI_NOT_READY;
    393   }
    394 
    395   //
    396   // Get the FVB protocol by handle
    397   //
    398   Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
    399   if (EFI_ERROR (Status)) {
    400     return EFI_NOT_FOUND;
    401   }
    402 
    403   Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
    404   if (EFI_ERROR (Status)) {
    405     DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get FVB physical address - %r\n", Status));
    406     return EFI_ABORTED;
    407   }
    408 
    409   //
    410   // Now, one FVB has one type of BlockSize.
    411   //
    412   Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
    413   if (EFI_ERROR (Status)) {
    414     DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get block size - %r\n", Status));
    415     return EFI_ABORTED;
    416   }
    417 
    418   NumberOfWriteBlocks = FTW_BLOCKS (Offset + Length, BlockSize);
    419   DEBUG ((EFI_D_INFO, "Ftw: Write(), BlockSize - 0x%x, NumberOfWriteBlock - 0x%x\n", BlockSize, NumberOfWriteBlocks));
    420   WriteLength = NumberOfWriteBlocks * BlockSize;
    421 
    422   //
    423   // Check if the input data can fit within the spare block.
    424   //
    425   if (WriteLength > FtwDevice->SpareAreaLength) {
    426     return EFI_BAD_BUFFER_SIZE;
    427   }
    428 
    429   //
    430   // Set BootBlockUpdate FLAG if it's updating boot block.
    431   //
    432   if (IsBootBlock (FtwDevice, Fvb)) {
    433     Record->BootBlockUpdate = FTW_VALID_STATE;
    434     //
    435     // Boot Block and Spare Block should have same block size and block numbers.
    436     //
    437     ASSERT ((BlockSize == FtwDevice->SpareBlockSize) && (NumberOfWriteBlocks == FtwDevice->NumberOfSpareBlock));
    438   }
    439   //
    440   // Write the record to the work space.
    441   //
    442   Record->Lba     = Lba;
    443   Record->Offset  = Offset;
    444   Record->Length  = Length;
    445   Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * BlockSize) - (INT64) FtwDevice->SpareAreaAddress;
    446   if (PrivateData != NULL) {
    447     CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);
    448   }
    449 
    450   MyOffset  = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
    451   MyLength  = FTW_RECORD_SIZE (Header->PrivateDataSize);
    452 
    453   Status = WriteWorkSpaceData (
    454              FtwDevice->FtwFvBlock,
    455              FtwDevice->WorkBlockSize,
    456              FtwDevice->FtwWorkSpaceLba,
    457              FtwDevice->FtwWorkSpaceBase + MyOffset,
    458              MyLength,
    459              (UINT8 *) Record
    460              );
    461   if (EFI_ERROR (Status)) {
    462     return EFI_ABORTED;
    463   }
    464   //
    465   // Record has written to working block, then do the data.
    466   //
    467   //
    468   // Allocate a memory buffer
    469   //
    470   MyBufferSize  = WriteLength;
    471   MyBuffer      = AllocatePool (MyBufferSize);
    472   if (MyBuffer == NULL) {
    473     return EFI_OUT_OF_RESOURCES;
    474   }
    475   //
    476   // Read all original data from target block to memory buffer
    477   //
    478   Ptr = MyBuffer;
    479   for (Index = 0; Index < NumberOfWriteBlocks; Index += 1) {
    480     MyLength  = BlockSize;
    481     Status    = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
    482     if (EFI_ERROR (Status)) {
    483       FreePool (MyBuffer);
    484       return EFI_ABORTED;
    485     }
    486 
    487     Ptr += MyLength;
    488   }
    489   //
    490   // Overwrite the updating range data with
    491   // the input buffer content
    492   //
    493   CopyMem (MyBuffer + Offset, Buffer, Length);
    494 
    495   //
    496   // Try to keep the content of spare block
    497   // Save spare block into a spare backup memory buffer (Sparebuffer)
    498   //
    499   SpareBufferSize = FtwDevice->SpareAreaLength;
    500   SpareBuffer     = AllocatePool (SpareBufferSize);
    501   if (SpareBuffer == NULL) {
    502     FreePool (MyBuffer);
    503     return EFI_OUT_OF_RESOURCES;
    504   }
    505 
    506   Ptr = SpareBuffer;
    507   for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
    508     MyLength = FtwDevice->SpareBlockSize;
    509     Status = FtwDevice->FtwBackupFvb->Read (
    510                                         FtwDevice->FtwBackupFvb,
    511                                         FtwDevice->FtwSpareLba + Index,
    512                                         0,
    513                                         &MyLength,
    514                                         Ptr
    515                                         );
    516     if (EFI_ERROR (Status)) {
    517       FreePool (MyBuffer);
    518       FreePool (SpareBuffer);
    519       return EFI_ABORTED;
    520     }
    521 
    522     Ptr += MyLength;
    523   }
    524   //
    525   // Write the memory buffer to spare block
    526   // Do not assume Spare Block and Target Block have same block size
    527   //
    528   Status  = FtwEraseSpareBlock (FtwDevice);
    529   if (EFI_ERROR (Status)) {
    530     FreePool (MyBuffer);
    531     FreePool (SpareBuffer);
    532     return EFI_ABORTED;
    533   }
    534   Ptr     = MyBuffer;
    535   for (Index = 0; MyBufferSize > 0; Index += 1) {
    536     if (MyBufferSize > FtwDevice->SpareBlockSize) {
    537       MyLength = FtwDevice->SpareBlockSize;
    538     } else {
    539       MyLength = MyBufferSize;
    540     }
    541     Status = FtwDevice->FtwBackupFvb->Write (
    542                                         FtwDevice->FtwBackupFvb,
    543                                         FtwDevice->FtwSpareLba + Index,
    544                                         0,
    545                                         &MyLength,
    546                                         Ptr
    547                                         );
    548     if (EFI_ERROR (Status)) {
    549       FreePool (MyBuffer);
    550       FreePool (SpareBuffer);
    551       return EFI_ABORTED;
    552     }
    553 
    554     Ptr += MyLength;
    555     MyBufferSize -= MyLength;
    556   }
    557   //
    558   // Free MyBuffer
    559   //
    560   FreePool (MyBuffer);
    561 
    562   //
    563   // Set the SpareComplete in the FTW record,
    564   //
    565   MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
    566   Status = FtwUpdateFvState (
    567             FtwDevice->FtwFvBlock,
    568             FtwDevice->WorkBlockSize,
    569             FtwDevice->FtwWorkSpaceLba,
    570             FtwDevice->FtwWorkSpaceBase + MyOffset,
    571             SPARE_COMPLETED
    572             );
    573   if (EFI_ERROR (Status)) {
    574     FreePool (SpareBuffer);
    575     return EFI_ABORTED;
    576   }
    577 
    578   Record->SpareComplete = FTW_VALID_STATE;
    579 
    580   //
    581   //  Since the content has already backuped in spare block, the write is
    582   //  guaranteed to be completed with fault tolerant manner.
    583   //
    584   Status = FtwWriteRecord (This, Fvb, BlockSize);
    585   if (EFI_ERROR (Status)) {
    586     FreePool (SpareBuffer);
    587     return EFI_ABORTED;
    588   }
    589   //
    590   // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
    591   //
    592   Status  = FtwEraseSpareBlock (FtwDevice);
    593   if (EFI_ERROR (Status)) {
    594     FreePool (SpareBuffer);
    595     return EFI_ABORTED;
    596   }
    597   Ptr     = SpareBuffer;
    598   for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
    599     MyLength = FtwDevice->SpareBlockSize;
    600     Status = FtwDevice->FtwBackupFvb->Write (
    601                                         FtwDevice->FtwBackupFvb,
    602                                         FtwDevice->FtwSpareLba + Index,
    603                                         0,
    604                                         &MyLength,
    605                                         Ptr
    606                                         );
    607     if (EFI_ERROR (Status)) {
    608       FreePool (SpareBuffer);
    609       return EFI_ABORTED;
    610     }
    611 
    612     Ptr += MyLength;
    613   }
    614   //
    615   // All success.
    616   //
    617   FreePool (SpareBuffer);
    618 
    619   DEBUG (
    620     (EFI_D_INFO,
    621     "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
    622     Lba,
    623     Offset,
    624     Length)
    625     );
    626 
    627   return EFI_SUCCESS;
    628 }
    629 
    630 /**
    631   Restarts a previously interrupted write. The caller must provide the
    632   block protocol needed to complete the interrupted write.
    633 
    634   @param This            The pointer to this protocol instance.
    635   @param FvBlockHandle   The handle of FVB protocol that provides services for
    636                          reading, writing, and erasing the target block.
    637 
    638   @retval  EFI_SUCCESS          The function completed successfully
    639   @retval  EFI_ACCESS_DENIED    No pending writes exist
    640   @retval  EFI_NOT_FOUND        FVB protocol not found by the handle
    641   @retval  EFI_ABORTED          The function could not complete successfully
    642 
    643 **/
    644 EFI_STATUS
    645 EFIAPI
    646 FtwRestart (
    647   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
    648   IN EFI_HANDLE                            FvBlockHandle
    649   )
    650 {
    651   EFI_STATUS                          Status;
    652   EFI_FTW_DEVICE                      *FtwDevice;
    653   EFI_FAULT_TOLERANT_WRITE_HEADER     *Header;
    654   EFI_FAULT_TOLERANT_WRITE_RECORD     *Record;
    655   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
    656   UINTN                               BlockSize;
    657   UINTN                               NumberOfBlocks;
    658 
    659   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
    660 
    661   Status    = WorkSpaceRefresh (FtwDevice);
    662   if (EFI_ERROR (Status)) {
    663     return EFI_ABORTED;
    664   }
    665 
    666   Header  = FtwDevice->FtwLastWriteHeader;
    667   Record  = FtwDevice->FtwLastWriteRecord;
    668 
    669   //
    670   // Spare Complete but Destination not complete,
    671   // Recover the targt block with the spare block.
    672   //
    673   Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
    674   if (EFI_ERROR (Status)) {
    675     return EFI_NOT_FOUND;
    676   }
    677 
    678   //
    679   // Now, one FVB has one type of BlockSize
    680   //
    681   Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
    682   if (EFI_ERROR (Status)) {
    683     DEBUG ((EFI_D_ERROR, "Ftw: Restart(), Get block size - %r\n", Status));
    684     return EFI_ABORTED;
    685   }
    686 
    687   //
    688   // Check the COMPLETE flag of last write header
    689   //
    690   if (Header->Complete == FTW_VALID_STATE) {
    691     return EFI_ACCESS_DENIED;
    692   }
    693 
    694   //
    695   // Check the flags of last write record
    696   //
    697   if (Record->DestinationComplete == FTW_VALID_STATE) {
    698     return EFI_ACCESS_DENIED;
    699   }
    700 
    701   if ((Record->SpareComplete != FTW_VALID_STATE)) {
    702     return EFI_ABORTED;
    703   }
    704 
    705   //
    706   //  Since the content has already backuped in spare block, the write is
    707   //  guaranteed to be completed with fault tolerant manner.
    708   //
    709   Status = FtwWriteRecord (This, Fvb, BlockSize);
    710   if (EFI_ERROR (Status)) {
    711     return EFI_ABORTED;
    712   }
    713 
    714   //
    715   // Erase Spare block
    716   // This is restart, no need to keep spareblock content.
    717   //
    718   Status = FtwEraseSpareBlock (FtwDevice);
    719   if (EFI_ERROR (Status)) {
    720     return EFI_ABORTED;
    721   }
    722 
    723   DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
    724   return EFI_SUCCESS;
    725 }
    726 
    727 /**
    728   Aborts all previous allocated writes.
    729 
    730   @param This                  The pointer to this protocol instance.
    731 
    732   @retval EFI_SUCCESS          The function completed successfully
    733   @retval EFI_ABORTED          The function could not complete successfully.
    734   @retval EFI_NOT_FOUND        No allocated writes exist.
    735 
    736 **/
    737 EFI_STATUS
    738 EFIAPI
    739 FtwAbort (
    740   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This
    741   )
    742 {
    743   EFI_STATUS      Status;
    744   UINTN           Offset;
    745   EFI_FTW_DEVICE  *FtwDevice;
    746 
    747   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
    748 
    749   Status    = WorkSpaceRefresh (FtwDevice);
    750   if (EFI_ERROR (Status)) {
    751     return EFI_ABORTED;
    752   }
    753 
    754   if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
    755     return EFI_NOT_FOUND;
    756   }
    757 
    758   if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
    759     return EFI_NOT_FOUND;
    760   }
    761   //
    762   // Update the complete state of the header as VALID and abort.
    763   //
    764   Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
    765   Status = FtwUpdateFvState (
    766             FtwDevice->FtwFvBlock,
    767             FtwDevice->WorkBlockSize,
    768             FtwDevice->FtwWorkSpaceLba,
    769             FtwDevice->FtwWorkSpaceBase + Offset,
    770             WRITES_COMPLETED
    771             );
    772   if (EFI_ERROR (Status)) {
    773     return EFI_ABORTED;
    774   }
    775 
    776   FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
    777 
    778   DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
    779   return EFI_SUCCESS;
    780 }
    781 
    782 /**
    783   Starts a target block update. This records information about the write
    784   in fault tolerant storage and will complete the write in a recoverable
    785   manner, ensuring at all times that either the original contents or
    786   the modified contents are available.
    787 
    788   @param This            The pointer to this protocol instance.
    789   @param CallerId        The GUID identifying the last write.
    790   @param Lba             The logical block address of the last write.
    791   @param Offset          The offset within the block of the last write.
    792   @param Length          The length of the last write.
    793   @param PrivateDataSize bytes from the private data
    794                          stored for this write.
    795   @param PrivateData     A pointer to a buffer. The function will copy
    796   @param Complete        A Boolean value with TRUE indicating
    797                          that the write was completed.
    798 
    799   @retval EFI_SUCCESS           The function completed successfully
    800   @retval EFI_ABORTED           The function could not complete successfully
    801   @retval EFI_NOT_FOUND         No allocated writes exist
    802   @retval EFI_BUFFER_TOO_SMALL  Input buffer is not larget enough
    803 
    804 **/
    805 EFI_STATUS
    806 EFIAPI
    807 FtwGetLastWrite (
    808   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
    809   OUT EFI_GUID                             *CallerId,
    810   OUT EFI_LBA                              *Lba,
    811   OUT UINTN                                *Offset,
    812   OUT UINTN                                *Length,
    813   IN OUT UINTN                             *PrivateDataSize,
    814   OUT VOID                                 *PrivateData,
    815   OUT BOOLEAN                              *Complete
    816   )
    817 {
    818   EFI_STATUS                      Status;
    819   EFI_FTW_DEVICE                  *FtwDevice;
    820   EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
    821   EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
    822 
    823   if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
    824     return EFI_UNSUPPORTED;
    825   }
    826 
    827   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
    828 
    829   Status    = WorkSpaceRefresh (FtwDevice);
    830   if (EFI_ERROR (Status)) {
    831     return EFI_ABORTED;
    832   }
    833 
    834   Header  = FtwDevice->FtwLastWriteHeader;
    835   Record  = FtwDevice->FtwLastWriteRecord;
    836 
    837   //
    838   // If Header is incompleted and the last record has completed, then
    839   // call Abort() to set the Header->Complete FLAG.
    840   //
    841   if ((Header->Complete != FTW_VALID_STATE) &&
    842       (Record->DestinationComplete == FTW_VALID_STATE) &&
    843       IsLastRecordOfWrites (Header, Record)
    844         ) {
    845 
    846     Status    = FtwAbort (This);
    847     *Complete = TRUE;
    848     return EFI_NOT_FOUND;
    849   }
    850   //
    851   // If there is no write header/record, return not found.
    852   //
    853   if (Header->HeaderAllocated != FTW_VALID_STATE) {
    854     *Complete = TRUE;
    855     return EFI_NOT_FOUND;
    856   }
    857   //
    858   // If this record SpareComplete has not set, then it can not restart.
    859   //
    860   if (Record->SpareComplete != FTW_VALID_STATE) {
    861     Status = GetPreviousRecordOfWrites (Header, &Record);
    862     if (EFI_ERROR (Status)) {
    863       FtwAbort (This);
    864       *Complete = TRUE;
    865       return EFI_NOT_FOUND;
    866     }
    867     ASSERT (Record != NULL);
    868   }
    869 
    870   //
    871   // Fill all the requested values
    872   //
    873   CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
    874   *Lba      = Record->Lba;
    875   *Offset   = (UINTN) Record->Offset;
    876   *Length   = (UINTN) Record->Length;
    877   *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
    878 
    879   if (*PrivateDataSize < Header->PrivateDataSize) {
    880     *PrivateDataSize  = (UINTN) Header->PrivateDataSize;
    881     PrivateData       = NULL;
    882     Status            = EFI_BUFFER_TOO_SMALL;
    883   } else {
    884     *PrivateDataSize = (UINTN) Header->PrivateDataSize;
    885     CopyMem (PrivateData, Record + 1, *PrivateDataSize);
    886     Status = EFI_SUCCESS;
    887   }
    888 
    889   DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
    890 
    891   return Status;
    892 }
    893 
    894