185e923a52851b242f8fc9f937c1fad7ce51246eelgao/** @file
285e923a52851b242f8fc9f937c1fad7ce51246eelgao
38a2d49964e371b1715beb3225fde47edfcaa51cagdong  These are the common Fault Tolerant Write (FTW) functions that are shared
48a2d49964e371b1715beb3225fde47edfcaa51cagdong  by DXE FTW driver and SMM FTW driver.
585e923a52851b242f8fc9f937c1fad7ce51246eelgao
6de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar ZengCopyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
7e5eed7d3641d71d7ea539e5379ea9c6a5cd97004hhtianThis program and the accompanying materials
885e923a52851b242f8fc9f937c1fad7ce51246eelgaoare licensed and made available under the terms and conditions of the BSD License
985e923a52851b242f8fc9f937c1fad7ce51246eelgaowhich accompanies this distribution.  The full text of the license may be found at
1085e923a52851b242f8fc9f937c1fad7ce51246eelgaohttp://opensource.org/licenses/bsd-license.php
1185e923a52851b242f8fc9f937c1fad7ce51246eelgao
1285e923a52851b242f8fc9f937c1fad7ce51246eelgaoTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
1385e923a52851b242f8fc9f937c1fad7ce51246eelgaoWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
1485e923a52851b242f8fc9f937c1fad7ce51246eelgao
1585e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
1685e923a52851b242f8fc9f937c1fad7ce51246eelgao
1785e923a52851b242f8fc9f937c1fad7ce51246eelgao#include "FaultTolerantWrite.h"
1885e923a52851b242f8fc9f937c1fad7ce51246eelgao
1985e923a52851b242f8fc9f937c1fad7ce51246eelgao//
2085e923a52851b242f8fc9f937c1fad7ce51246eelgao// Fault Tolerant Write Protocol API
2185e923a52851b242f8fc9f937c1fad7ce51246eelgao//
2285e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
2385e923a52851b242f8fc9f937c1fad7ce51246eelgao  Query the largest block that may be updated in a fault tolerant manner.
2485e923a52851b242f8fc9f937c1fad7ce51246eelgao
2585e923a52851b242f8fc9f937c1fad7ce51246eelgao
2685e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This            The pointer to this protocol instance.
2785e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param BlockSize       A pointer to a caller allocated UINTN that is updated to
2885e923a52851b242f8fc9f937c1fad7ce51246eelgao                         indicate the size of the largest block that can be updated.
2985e923a52851b242f8fc9f937c1fad7ce51246eelgao
3085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @return EFI_SUCCESS   The function completed successfully
3185e923a52851b242f8fc9f937c1fad7ce51246eelgao
3285e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
3385e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
3485e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFIAPI
3585e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwGetMaxBlockSize (
3685e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL    *This,
3785e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT UINTN                               *BlockSize
3885e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
3985e923a52851b242f8fc9f937c1fad7ce51246eelgao{
4085e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE  *FtwDevice;
4185e923a52851b242f8fc9f937c1fad7ce51246eelgao
4285e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
4385e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_UNSUPPORTED;
4485e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
4585e923a52851b242f8fc9f937c1fad7ce51246eelgao
4685e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice   = FTW_CONTEXT_FROM_THIS (This);
4785e923a52851b242f8fc9f937c1fad7ce51246eelgao
4885e923a52851b242f8fc9f937c1fad7ce51246eelgao  *BlockSize  = FtwDevice->SpareAreaLength;
4985e923a52851b242f8fc9f937c1fad7ce51246eelgao
5085e923a52851b242f8fc9f937c1fad7ce51246eelgao  return EFI_SUCCESS;
5185e923a52851b242f8fc9f937c1fad7ce51246eelgao}
5285e923a52851b242f8fc9f937c1fad7ce51246eelgao
5385e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
5485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Allocates space for the protocol to maintain information about writes.
5585e923a52851b242f8fc9f937c1fad7ce51246eelgao  Since writes must be completed in a fault tolerant manner and multiple
5685e923a52851b242f8fc9f937c1fad7ce51246eelgao  updates will require more resources to be successful, this function
5785e923a52851b242f8fc9f937c1fad7ce51246eelgao  enables the protocol to ensure that enough space exists to track
5885e923a52851b242f8fc9f937c1fad7ce51246eelgao  information about the upcoming writes.
5985e923a52851b242f8fc9f937c1fad7ce51246eelgao
6085e923a52851b242f8fc9f937c1fad7ce51246eelgao  All writes must be completed or aborted before another fault tolerant write can occur.
6185e923a52851b242f8fc9f937c1fad7ce51246eelgao
6285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This            The pointer to this protocol instance.
6385e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param CallerId        The GUID identifying the write.
6485e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param PrivateDataSize The size of the caller's private data
6585e923a52851b242f8fc9f937c1fad7ce51246eelgao                         that must be recorded for each write.
6685e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param NumberOfWrites  The number of fault tolerant block writes
6785e923a52851b242f8fc9f937c1fad7ce51246eelgao                         that will need to occur.
6885e923a52851b242f8fc9f937c1fad7ce51246eelgao
6985e923a52851b242f8fc9f937c1fad7ce51246eelgao  @return EFI_SUCCESS        The function completed successfully
7085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_ABORTED        The function could not complete successfully.
7185e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_ACCESS_DENIED  All allocated writes have not been completed.
7285e923a52851b242f8fc9f937c1fad7ce51246eelgao
7385e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
7485e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
7585e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFIAPI
7685e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwAllocate (
7785e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL    *This,
7885e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_GUID                             *CallerId,
7985e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN UINTN                                PrivateDataSize,
8085e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN UINTN                                NumberOfWrites
8185e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
8285e923a52851b242f8fc9f937c1fad7ce51246eelgao{
8385e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_STATUS                      Status;
8485e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                           Offset;
8585e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE                  *FtwDevice;
8685e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
8785e923a52851b242f8fc9f937c1fad7ce51246eelgao
8885e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice = FTW_CONTEXT_FROM_THIS (This);
8985e923a52851b242f8fc9f937c1fad7ce51246eelgao
9085e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status    = WorkSpaceRefresh (FtwDevice);
9185e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
9285e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
9385e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
9485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
9585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Check if there is enough space for the coming allocation
9685e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
973e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
9885e923a52851b242f8fc9f937c1fad7ce51246eelgao    DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
9985e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_BUFFER_TOO_SMALL;
10085e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
10185e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
10285e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Find the last write header and record.
10385e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If the FtwHeader is complete, skip the completed last write header/records
10485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
10585e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwHeader = FtwDevice->FtwLastWriteHeader;
10685e923a52851b242f8fc9f937c1fad7ce51246eelgao
10785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
10885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Previous write has not completed, access denied.
10985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
11085e923a52851b242f8fc9f937c1fad7ce51246eelgao  if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
11185e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ACCESS_DENIED;
11285e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
11385e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
11485e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If workspace is not enough, then reclaim workspace
11585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
11685e923a52851b242f8fc9f937c1fad7ce51246eelgao  Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
1173e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
11885e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
11985e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
12085e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
12185e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
12285e923a52851b242f8fc9f937c1fad7ce51246eelgao
12385e923a52851b242f8fc9f937c1fad7ce51246eelgao    FtwHeader = FtwDevice->FtwLastWriteHeader;
12485e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
12585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
12685e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Prepare FTW write header,
12785e923a52851b242f8fc9f937c1fad7ce51246eelgao  // overwrite the buffer and write to workspace.
12885e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
12985e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwHeader->WritesAllocated  = FTW_INVALID_STATE;
13085e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwHeader->Complete         = FTW_INVALID_STATE;
13185e923a52851b242f8fc9f937c1fad7ce51246eelgao  CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
13285e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwHeader->NumberOfWrites   = NumberOfWrites;
13385e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwHeader->PrivateDataSize  = PrivateDataSize;
13485e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwHeader->HeaderAllocated  = FTW_VALID_STATE;
13585e923a52851b242f8fc9f937c1fad7ce51246eelgao
1360d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Status = WriteWorkSpaceData (
1370d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->FtwFvBlock,
1380d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->WorkBlockSize,
1390d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->FtwWorkSpaceLba,
1400d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->FtwWorkSpaceBase + Offset,
1410d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER),
1420d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             (UINT8 *) FtwHeader
1430d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             );
14485e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
14585e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
14685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
14785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
14885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Update Header->WriteAllocated as VALID
14985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
15085e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = FtwUpdateFvState (
15185e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwFvBlock,
1520d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng            FtwDevice->WorkBlockSize,
15385e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceLba,
15485e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceBase + Offset,
15585e923a52851b242f8fc9f937c1fad7ce51246eelgao            WRITES_ALLOCATED
15685e923a52851b242f8fc9f937c1fad7ce51246eelgao            );
15785e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
15885e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
15985e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
16085e923a52851b242f8fc9f937c1fad7ce51246eelgao
16185e923a52851b242f8fc9f937c1fad7ce51246eelgao  DEBUG (
1629a95972e6a2fa19ff46c36098818fa5e76971a62Samer El-Haj-Mahmoud    (EFI_D_INFO,
16385e923a52851b242f8fc9f937c1fad7ce51246eelgao    "Ftw: Allocate() success, Caller:%g, # %d\n",
16485e923a52851b242f8fc9f937c1fad7ce51246eelgao    CallerId,
16585e923a52851b242f8fc9f937c1fad7ce51246eelgao    NumberOfWrites)
16685e923a52851b242f8fc9f937c1fad7ce51246eelgao    );
16785e923a52851b242f8fc9f937c1fad7ce51246eelgao
16885e923a52851b242f8fc9f937c1fad7ce51246eelgao  return EFI_SUCCESS;
16985e923a52851b242f8fc9f937c1fad7ce51246eelgao}
17085e923a52851b242f8fc9f937c1fad7ce51246eelgao
17185e923a52851b242f8fc9f937c1fad7ce51246eelgao
17285e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
1730d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Write a record with fault tolerant manner.
17485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Since the content has already backuped in spare block, the write is
17585e923a52851b242f8fc9f937c1fad7ce51246eelgao  guaranteed to be completed with fault tolerant manner.
17685e923a52851b242f8fc9f937c1fad7ce51246eelgao
17785e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This            The pointer to this protocol instance.
17885e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Fvb             The FVB protocol that provides services for
17985e923a52851b242f8fc9f937c1fad7ce51246eelgao                         reading, writing, and erasing the target block.
1800d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  @param BlockSize       The size of the block.
18185e923a52851b242f8fc9f937c1fad7ce51246eelgao
18285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval  EFI_SUCCESS          The function completed successfully
18385e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval  EFI_ABORTED          The function could not complete successfully
18485e923a52851b242f8fc9f937c1fad7ce51246eelgao
18585e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
18685e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
18785e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwWriteRecord (
18885e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
1890d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb,
1900d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  IN UINTN                                 BlockSize
19185e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
19285e923a52851b242f8fc9f937c1fad7ce51246eelgao{
19385e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_STATUS                      Status;
19485e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE                  *FtwDevice;
19585e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
19685e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
19785e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                           Offset;
1980d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                           NumberOfWriteBlocks;
19985e923a52851b242f8fc9f937c1fad7ce51246eelgao
20085e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice = FTW_CONTEXT_FROM_THIS (This);
20185e923a52851b242f8fc9f937c1fad7ce51246eelgao
20285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
20385e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Spare Complete but Destination not complete,
2048a2d49964e371b1715beb3225fde47edfcaa51cagdong  // Recover the target block with the spare block.
20585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
20685e923a52851b242f8fc9f937c1fad7ce51246eelgao  Header  = FtwDevice->FtwLastWriteHeader;
20785e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record  = FtwDevice->FtwLastWriteRecord;
20885e923a52851b242f8fc9f937c1fad7ce51246eelgao
20985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
21085e923a52851b242f8fc9f937c1fad7ce51246eelgao  // IF target block is working block, THEN Flush Spare Block To Working Block;
21185e923a52851b242f8fc9f937c1fad7ce51246eelgao  // ELSE flush spare block to target block, which may be boot block after all.
21285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
21385e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
21485e923a52851b242f8fc9f937c1fad7ce51246eelgao    //
21585e923a52851b242f8fc9f937c1fad7ce51246eelgao    // If target block is working block,
21685e923a52851b242f8fc9f937c1fad7ce51246eelgao    // it also need to set SPARE_COMPLETED to spare block.
21785e923a52851b242f8fc9f937c1fad7ce51246eelgao    //
21885e923a52851b242f8fc9f937c1fad7ce51246eelgao    Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
21985e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FtwUpdateFvState (
22085e923a52851b242f8fc9f937c1fad7ce51246eelgao              FtwDevice->FtwBackupFvb,
2210d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng              FtwDevice->SpareBlockSize,
2220d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng              FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
2230d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng              FtwDevice->FtwWorkSpaceBaseInSpare + Offset,
22485e923a52851b242f8fc9f937c1fad7ce51246eelgao              SPARE_COMPLETED
22585e923a52851b242f8fc9f937c1fad7ce51246eelgao              );
22685e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
22785e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
22885e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
22985e923a52851b242f8fc9f937c1fad7ce51246eelgao
23085e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FlushSpareBlockToWorkingBlock (FtwDevice);
2310d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  } else if (IsBootBlock (FtwDevice, Fvb)) {
23285e923a52851b242f8fc9f937c1fad7ce51246eelgao    //
23385e923a52851b242f8fc9f937c1fad7ce51246eelgao    // Update boot block
23485e923a52851b242f8fc9f937c1fad7ce51246eelgao    //
23585e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FlushSpareBlockToBootBlock (FtwDevice);
23685e923a52851b242f8fc9f937c1fad7ce51246eelgao  } else {
23785e923a52851b242f8fc9f937c1fad7ce51246eelgao    //
23885e923a52851b242f8fc9f937c1fad7ce51246eelgao    // Update blocks other than working block or boot block
23985e923a52851b242f8fc9f937c1fad7ce51246eelgao    //
2400d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    NumberOfWriteBlocks = FTW_BLOCKS ((UINTN) (Record->Offset + Record->Length), BlockSize);
2410d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba, BlockSize, NumberOfWriteBlocks);
24285e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
24385e923a52851b242f8fc9f937c1fad7ce51246eelgao
24485e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
24585e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
24685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
24785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
24885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Record the DestionationComplete in record
24985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
25085e923a52851b242f8fc9f937c1fad7ce51246eelgao  Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
25185e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = FtwUpdateFvState (
25285e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwFvBlock,
2530d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng            FtwDevice->WorkBlockSize,
25485e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceLba,
25585e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceBase + Offset,
25685e923a52851b242f8fc9f937c1fad7ce51246eelgao            DEST_COMPLETED
25785e923a52851b242f8fc9f937c1fad7ce51246eelgao            );
25885e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
25985e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
26085e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
26185e923a52851b242f8fc9f937c1fad7ce51246eelgao
26285e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record->DestinationComplete = FTW_VALID_STATE;
26385e923a52851b242f8fc9f937c1fad7ce51246eelgao
26485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
26585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If this is the last Write in these write sequence,
26685e923a52851b242f8fc9f937c1fad7ce51246eelgao  // set the complete flag of write header.
26785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
26885e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (IsLastRecordOfWrites (Header, Record)) {
26985e923a52851b242f8fc9f937c1fad7ce51246eelgao    Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
27085e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FtwUpdateFvState (
27185e923a52851b242f8fc9f937c1fad7ce51246eelgao              FtwDevice->FtwFvBlock,
2720d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng              FtwDevice->WorkBlockSize,
27385e923a52851b242f8fc9f937c1fad7ce51246eelgao              FtwDevice->FtwWorkSpaceLba,
27485e923a52851b242f8fc9f937c1fad7ce51246eelgao              FtwDevice->FtwWorkSpaceBase + Offset,
27585e923a52851b242f8fc9f937c1fad7ce51246eelgao              WRITES_COMPLETED
27685e923a52851b242f8fc9f937c1fad7ce51246eelgao              );
27785e923a52851b242f8fc9f937c1fad7ce51246eelgao    Header->Complete = FTW_VALID_STATE;
27885e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
27985e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
28085e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
28185e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
28285e923a52851b242f8fc9f937c1fad7ce51246eelgao
28385e923a52851b242f8fc9f937c1fad7ce51246eelgao  return EFI_SUCCESS;
28485e923a52851b242f8fc9f937c1fad7ce51246eelgao}
28585e923a52851b242f8fc9f937c1fad7ce51246eelgao
28685e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
28785e923a52851b242f8fc9f937c1fad7ce51246eelgao  Starts a target block update. This function will record data about write
28885e923a52851b242f8fc9f937c1fad7ce51246eelgao  in fault tolerant storage and will complete the write in a recoverable
28985e923a52851b242f8fc9f937c1fad7ce51246eelgao  manner, ensuring at all times that either the original contents or
29085e923a52851b242f8fc9f937c1fad7ce51246eelgao  the modified contents are available.
29185e923a52851b242f8fc9f937c1fad7ce51246eelgao
29285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This            The pointer to this protocol instance.
29385e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Lba             The logical block address of the target block.
29485e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Offset          The offset within the target block to place the data.
29585e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Length          The number of bytes to write to the target block.
29685e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param PrivateData     A pointer to private data that the caller requires to
29785e923a52851b242f8fc9f937c1fad7ce51246eelgao                         complete any pending writes in the event of a fault.
29885e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param FvBlockHandle   The handle of FVB protocol that provides services for
29985e923a52851b242f8fc9f937c1fad7ce51246eelgao                         reading, writing, and erasing the target block.
30085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Buffer          The data to write.
30185e923a52851b242f8fc9f937c1fad7ce51246eelgao
30285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_SUCCESS          The function completed successfully
30385e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_ABORTED          The function could not complete successfully.
30485e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_BAD_BUFFER_SIZE  The input data can't fit within the spare block.
30585e923a52851b242f8fc9f937c1fad7ce51246eelgao                               Offset + *NumBytes > SpareAreaLength.
30685e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_ACCESS_DENIED    No writes have been allocated.
30785e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
30885e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_NOT_FOUND        Cannot find FVB protocol by handle.
30985e923a52851b242f8fc9f937c1fad7ce51246eelgao
31085e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
31185e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
31285e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFIAPI
31385e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwWrite (
31485e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
31585e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_LBA                               Lba,
31685e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN UINTN                                 Offset,
31785e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN UINTN                                 Length,
31885e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN VOID                                  *PrivateData,
31985e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_HANDLE                            FvBlockHandle,
32085e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN VOID                                  *Buffer
32185e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
32285e923a52851b242f8fc9f937c1fad7ce51246eelgao{
32385e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_STATUS                          Status;
32485e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE                      *FtwDevice;
32585e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_HEADER     *Header;
32685e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_RECORD     *Record;
32785e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
32885e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                               MyLength;
32985e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                               MyOffset;
33085e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                               MyBufferSize;
33185e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINT8                               *MyBuffer;
33285e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                               SpareBufferSize;
33385e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINT8                               *SpareBuffer;
33485e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN                               Index;
33585e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINT8                               *Ptr;
33685e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_PHYSICAL_ADDRESS                FvbPhysicalAddress;
3370d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                               BlockSize;
3380d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                               NumberOfBlocks;
3390d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                               NumberOfWriteBlocks;
3400d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                               WriteLength;
34185e923a52851b242f8fc9f937c1fad7ce51246eelgao
34285e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice = FTW_CONTEXT_FROM_THIS (This);
34385e923a52851b242f8fc9f937c1fad7ce51246eelgao
34485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status    = WorkSpaceRefresh (FtwDevice);
34585e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
34685e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
34785e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
34885e923a52851b242f8fc9f937c1fad7ce51246eelgao
34985e923a52851b242f8fc9f937c1fad7ce51246eelgao  Header  = FtwDevice->FtwLastWriteHeader;
35085e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record  = FtwDevice->FtwLastWriteRecord;
35185e923a52851b242f8fc9f937c1fad7ce51246eelgao
35285e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
35385e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (PrivateData == NULL) {
35485e923a52851b242f8fc9f937c1fad7ce51246eelgao      //
35585e923a52851b242f8fc9f937c1fad7ce51246eelgao      // Ftw Write Header is not allocated.
35685e923a52851b242f8fc9f937c1fad7ce51246eelgao      // No additional private data, the private data size is zero. Number of record can be set to 1.
35785e923a52851b242f8fc9f937c1fad7ce51246eelgao      //
35885e923a52851b242f8fc9f937c1fad7ce51246eelgao      Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
35985e923a52851b242f8fc9f937c1fad7ce51246eelgao      if (EFI_ERROR (Status)) {
36085e923a52851b242f8fc9f937c1fad7ce51246eelgao        return Status;
36185e923a52851b242f8fc9f937c1fad7ce51246eelgao      }
36285e923a52851b242f8fc9f937c1fad7ce51246eelgao    } else {
36385e923a52851b242f8fc9f937c1fad7ce51246eelgao      //
36485e923a52851b242f8fc9f937c1fad7ce51246eelgao      // Ftw Write Header is not allocated
36585e923a52851b242f8fc9f937c1fad7ce51246eelgao      // Additional private data is not NULL, the private data size can't be determined.
36685e923a52851b242f8fc9f937c1fad7ce51246eelgao      //
36785e923a52851b242f8fc9f937c1fad7ce51246eelgao      DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
36885e923a52851b242f8fc9f937c1fad7ce51246eelgao      DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
36985e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_NOT_READY;
37085e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
37185e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
37285e923a52851b242f8fc9f937c1fad7ce51246eelgao
37385e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
37485e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If Record is out of the range of Header, return access denied.
37585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
3763e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
37785e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ACCESS_DENIED;
37885e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
37985e923a52851b242f8fc9f937c1fad7ce51246eelgao
38085e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
38185e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Check the COMPLETE flag of last write header
38285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
38385e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (Header->Complete == FTW_VALID_STATE) {
38485e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ACCESS_DENIED;
38585e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
38685e923a52851b242f8fc9f937c1fad7ce51246eelgao
38785e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (Record->DestinationComplete == FTW_VALID_STATE) {
38885e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ACCESS_DENIED;
38985e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
39085e923a52851b242f8fc9f937c1fad7ce51246eelgao
39185e923a52851b242f8fc9f937c1fad7ce51246eelgao  if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
39285e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_NOT_READY;
39385e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
3940d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng
39585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
39685e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Get the FVB protocol by handle
39785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
39885e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
39985e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
40085e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_NOT_FOUND;
40185e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
40285e923a52851b242f8fc9f937c1fad7ce51246eelgao
40385e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
40485e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
4050d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get FVB physical address - %r\n", Status));
4060d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    return EFI_ABORTED;
4070d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  }
4080d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng
4090d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  //
4100d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  // Now, one FVB has one type of BlockSize.
4110d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  //
4120d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
4130d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  if (EFI_ERROR (Status)) {
4140d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get block size - %r\n", Status));
41585e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
41685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
41785e923a52851b242f8fc9f937c1fad7ce51246eelgao
4180d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  NumberOfWriteBlocks = FTW_BLOCKS (Offset + Length, BlockSize);
4190d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  DEBUG ((EFI_D_INFO, "Ftw: Write(), BlockSize - 0x%x, NumberOfWriteBlock - 0x%x\n", BlockSize, NumberOfWriteBlocks));
4200d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  WriteLength = NumberOfWriteBlocks * BlockSize;
4210d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng
4220d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  //
4230d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  // Check if the input data can fit within the spare block.
4240d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  //
4250d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  if (WriteLength > FtwDevice->SpareAreaLength) {
4260d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    return EFI_BAD_BUFFER_SIZE;
4270d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  }
4280d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng
42985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
43085e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Set BootBlockUpdate FLAG if it's updating boot block.
43185e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
4320d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  if (IsBootBlock (FtwDevice, Fvb)) {
43385e923a52851b242f8fc9f937c1fad7ce51246eelgao    Record->BootBlockUpdate = FTW_VALID_STATE;
4340d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    //
4350d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    // Boot Block and Spare Block should have same block size and block numbers.
4360d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    //
4370d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    ASSERT ((BlockSize == FtwDevice->SpareBlockSize) && (NumberOfWriteBlocks == FtwDevice->NumberOfSpareBlock));
43885e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
43985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
44085e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Write the record to the work space.
44185e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
44285e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record->Lba     = Lba;
44385e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record->Offset  = Offset;
44485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record->Length  = Length;
4450d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * BlockSize) - (INT64) FtwDevice->SpareAreaAddress;
446f0480ecf804ff9e0e5c12d21ba563f73212028e8lgao  if (PrivateData != NULL) {
4473e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng    CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);
448f0480ecf804ff9e0e5c12d21ba563f73212028e8lgao  }
44985e923a52851b242f8fc9f937c1fad7ce51246eelgao
45085e923a52851b242f8fc9f937c1fad7ce51246eelgao  MyOffset  = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
4513e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  MyLength  = FTW_RECORD_SIZE (Header->PrivateDataSize);
45285e923a52851b242f8fc9f937c1fad7ce51246eelgao
4530d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Status = WriteWorkSpaceData (
4540d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->FtwFvBlock,
4550d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->WorkBlockSize,
4560d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->FtwWorkSpaceLba,
4570d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             FtwDevice->FtwWorkSpaceBase + MyOffset,
4580d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             MyLength,
4590d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             (UINT8 *) Record
4600d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng             );
46185e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
46285e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
46385e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
46485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
46585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Record has written to working block, then do the data.
46685e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
46785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
46885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Allocate a memory buffer
46985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
4700d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  MyBufferSize  = WriteLength;
47185e923a52851b242f8fc9f937c1fad7ce51246eelgao  MyBuffer      = AllocatePool (MyBufferSize);
47285e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (MyBuffer == NULL) {
47385e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_OUT_OF_RESOURCES;
47485e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
47585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
47685e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Read all original data from target block to memory buffer
47785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
47885e923a52851b242f8fc9f937c1fad7ce51246eelgao  Ptr = MyBuffer;
4790d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  for (Index = 0; Index < NumberOfWriteBlocks; Index += 1) {
4800d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    MyLength  = BlockSize;
48185e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status    = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
48285e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
48385e923a52851b242f8fc9f937c1fad7ce51246eelgao      FreePool (MyBuffer);
48485e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
48585e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
48685e923a52851b242f8fc9f937c1fad7ce51246eelgao
48785e923a52851b242f8fc9f937c1fad7ce51246eelgao    Ptr += MyLength;
48885e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
48985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
49085e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Overwrite the updating range data with
49185e923a52851b242f8fc9f937c1fad7ce51246eelgao  // the input buffer content
49285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
49385e923a52851b242f8fc9f937c1fad7ce51246eelgao  CopyMem (MyBuffer + Offset, Buffer, Length);
49485e923a52851b242f8fc9f937c1fad7ce51246eelgao
49585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
49685e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Try to keep the content of spare block
49785e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Save spare block into a spare backup memory buffer (Sparebuffer)
49885e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
49985e923a52851b242f8fc9f937c1fad7ce51246eelgao  SpareBufferSize = FtwDevice->SpareAreaLength;
50085e923a52851b242f8fc9f937c1fad7ce51246eelgao  SpareBuffer     = AllocatePool (SpareBufferSize);
50185e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (SpareBuffer == NULL) {
50285e923a52851b242f8fc9f937c1fad7ce51246eelgao    FreePool (MyBuffer);
50385e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_OUT_OF_RESOURCES;
50485e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
50585e923a52851b242f8fc9f937c1fad7ce51246eelgao
50685e923a52851b242f8fc9f937c1fad7ce51246eelgao  Ptr = SpareBuffer;
50785e923a52851b242f8fc9f937c1fad7ce51246eelgao  for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
5080d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    MyLength = FtwDevice->SpareBlockSize;
50985e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FtwDevice->FtwBackupFvb->Read (
51085e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        FtwDevice->FtwBackupFvb,
51185e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        FtwDevice->FtwSpareLba + Index,
51285e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        0,
51385e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        &MyLength,
51485e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        Ptr
51585e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        );
51685e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
51785e923a52851b242f8fc9f937c1fad7ce51246eelgao      FreePool (MyBuffer);
51885e923a52851b242f8fc9f937c1fad7ce51246eelgao      FreePool (SpareBuffer);
51985e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
52085e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
52185e923a52851b242f8fc9f937c1fad7ce51246eelgao
52285e923a52851b242f8fc9f937c1fad7ce51246eelgao    Ptr += MyLength;
52385e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
52485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
52585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Write the memory buffer to spare block
5260d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  // Do not assume Spare Block and Target Block have same block size
52785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
52885e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status  = FtwEraseSpareBlock (FtwDevice);
529de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  if (EFI_ERROR (Status)) {
530de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng    FreePool (MyBuffer);
531de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng    FreePool (SpareBuffer);
532de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng    return EFI_ABORTED;
533de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  }
53485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Ptr     = MyBuffer;
5350d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  for (Index = 0; MyBufferSize > 0; Index += 1) {
5360d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    if (MyBufferSize > FtwDevice->SpareBlockSize) {
5370d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng      MyLength = FtwDevice->SpareBlockSize;
5380d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    } else {
5390d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng      MyLength = MyBufferSize;
5400d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    }
54185e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FtwDevice->FtwBackupFvb->Write (
54285e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        FtwDevice->FtwBackupFvb,
54385e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        FtwDevice->FtwSpareLba + Index,
54485e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        0,
54585e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        &MyLength,
54685e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        Ptr
54785e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        );
54885e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
54985e923a52851b242f8fc9f937c1fad7ce51246eelgao      FreePool (MyBuffer);
55085e923a52851b242f8fc9f937c1fad7ce51246eelgao      FreePool (SpareBuffer);
55185e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
55285e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
55385e923a52851b242f8fc9f937c1fad7ce51246eelgao
55485e923a52851b242f8fc9f937c1fad7ce51246eelgao    Ptr += MyLength;
5550d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    MyBufferSize -= MyLength;
55685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
55785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
55885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Free MyBuffer
55985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
56085e923a52851b242f8fc9f937c1fad7ce51246eelgao  FreePool (MyBuffer);
56185e923a52851b242f8fc9f937c1fad7ce51246eelgao
56285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
56385e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Set the SpareComplete in the FTW record,
56485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
56585e923a52851b242f8fc9f937c1fad7ce51246eelgao  MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
56685e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = FtwUpdateFvState (
56785e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwFvBlock,
5680d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng            FtwDevice->WorkBlockSize,
56985e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceLba,
57085e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceBase + MyOffset,
57185e923a52851b242f8fc9f937c1fad7ce51246eelgao            SPARE_COMPLETED
57285e923a52851b242f8fc9f937c1fad7ce51246eelgao            );
57385e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
57485e923a52851b242f8fc9f937c1fad7ce51246eelgao    FreePool (SpareBuffer);
57585e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
57685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
57785e923a52851b242f8fc9f937c1fad7ce51246eelgao
57885e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record->SpareComplete = FTW_VALID_STATE;
57985e923a52851b242f8fc9f937c1fad7ce51246eelgao
58085e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
58185e923a52851b242f8fc9f937c1fad7ce51246eelgao  //  Since the content has already backuped in spare block, the write is
58285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //  guaranteed to be completed with fault tolerant manner.
58385e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
5840d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Status = FtwWriteRecord (This, Fvb, BlockSize);
58585e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
58685e923a52851b242f8fc9f937c1fad7ce51246eelgao    FreePool (SpareBuffer);
58785e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
58885e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
58985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
59085e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
59185e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
59285e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status  = FtwEraseSpareBlock (FtwDevice);
593de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  if (EFI_ERROR (Status)) {
594de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng    FreePool (SpareBuffer);
595de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng    return EFI_ABORTED;
596de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  }
59785e923a52851b242f8fc9f937c1fad7ce51246eelgao  Ptr     = SpareBuffer;
59885e923a52851b242f8fc9f937c1fad7ce51246eelgao  for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
5990d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    MyLength = FtwDevice->SpareBlockSize;
60085e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = FtwDevice->FtwBackupFvb->Write (
60185e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        FtwDevice->FtwBackupFvb,
60285e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        FtwDevice->FtwSpareLba + Index,
60385e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        0,
60485e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        &MyLength,
60585e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        Ptr
60685e923a52851b242f8fc9f937c1fad7ce51246eelgao                                        );
60785e923a52851b242f8fc9f937c1fad7ce51246eelgao    if (EFI_ERROR (Status)) {
60885e923a52851b242f8fc9f937c1fad7ce51246eelgao      FreePool (SpareBuffer);
60985e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_ABORTED;
61085e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
61185e923a52851b242f8fc9f937c1fad7ce51246eelgao
61285e923a52851b242f8fc9f937c1fad7ce51246eelgao    Ptr += MyLength;
61385e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
61485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
61585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // All success.
61685e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
61785e923a52851b242f8fc9f937c1fad7ce51246eelgao  FreePool (SpareBuffer);
61885e923a52851b242f8fc9f937c1fad7ce51246eelgao
61985e923a52851b242f8fc9f937c1fad7ce51246eelgao  DEBUG (
6209a95972e6a2fa19ff46c36098818fa5e76971a62Samer El-Haj-Mahmoud    (EFI_D_INFO,
62185e923a52851b242f8fc9f937c1fad7ce51246eelgao    "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
62285e923a52851b242f8fc9f937c1fad7ce51246eelgao    Lba,
62385e923a52851b242f8fc9f937c1fad7ce51246eelgao    Offset,
62485e923a52851b242f8fc9f937c1fad7ce51246eelgao    Length)
62585e923a52851b242f8fc9f937c1fad7ce51246eelgao    );
62685e923a52851b242f8fc9f937c1fad7ce51246eelgao
62785e923a52851b242f8fc9f937c1fad7ce51246eelgao  return EFI_SUCCESS;
62885e923a52851b242f8fc9f937c1fad7ce51246eelgao}
62985e923a52851b242f8fc9f937c1fad7ce51246eelgao
63085e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
63185e923a52851b242f8fc9f937c1fad7ce51246eelgao  Restarts a previously interrupted write. The caller must provide the
63285e923a52851b242f8fc9f937c1fad7ce51246eelgao  block protocol needed to complete the interrupted write.
63385e923a52851b242f8fc9f937c1fad7ce51246eelgao
63485e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This            The pointer to this protocol instance.
63585e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param FvBlockHandle   The handle of FVB protocol that provides services for
63685e923a52851b242f8fc9f937c1fad7ce51246eelgao                         reading, writing, and erasing the target block.
63785e923a52851b242f8fc9f937c1fad7ce51246eelgao
63885e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval  EFI_SUCCESS          The function completed successfully
63985e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval  EFI_ACCESS_DENIED    No pending writes exist
64085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval  EFI_NOT_FOUND        FVB protocol not found by the handle
64185e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval  EFI_ABORTED          The function could not complete successfully
64285e923a52851b242f8fc9f937c1fad7ce51246eelgao
64385e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
64485e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
64585e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFIAPI
64685e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwRestart (
64785e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
64885e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_HANDLE                            FvBlockHandle
64985e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
65085e923a52851b242f8fc9f937c1fad7ce51246eelgao{
65185e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_STATUS                          Status;
65285e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE                      *FtwDevice;
65385e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_HEADER     *Header;
65485e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_RECORD     *Record;
65585e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
6560d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                               BlockSize;
6570d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  UINTN                               NumberOfBlocks;
65885e923a52851b242f8fc9f937c1fad7ce51246eelgao
65985e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice = FTW_CONTEXT_FROM_THIS (This);
66085e923a52851b242f8fc9f937c1fad7ce51246eelgao
66185e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status    = WorkSpaceRefresh (FtwDevice);
66285e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
66385e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
66485e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
66585e923a52851b242f8fc9f937c1fad7ce51246eelgao
66685e923a52851b242f8fc9f937c1fad7ce51246eelgao  Header  = FtwDevice->FtwLastWriteHeader;
66785e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record  = FtwDevice->FtwLastWriteRecord;
66885e923a52851b242f8fc9f937c1fad7ce51246eelgao
66985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
67085e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Spare Complete but Destination not complete,
67185e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Recover the targt block with the spare block.
67285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
67385e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
67485e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
67585e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_NOT_FOUND;
67685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
67785e923a52851b242f8fc9f937c1fad7ce51246eelgao
67885e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
6790d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  // Now, one FVB has one type of BlockSize
6800d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  //
6810d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
6820d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  if (EFI_ERROR (Status)) {
6830d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    DEBUG ((EFI_D_ERROR, "Ftw: Restart(), Get block size - %r\n", Status));
6840d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng    return EFI_ABORTED;
6850d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  }
6860d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng
6870d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  //
68885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Check the COMPLETE flag of last write header
68985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
69085e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (Header->Complete == FTW_VALID_STATE) {
69185e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ACCESS_DENIED;
69285e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
69385e923a52851b242f8fc9f937c1fad7ce51246eelgao
69485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
69585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Check the flags of last write record
69685e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
69785e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (Record->DestinationComplete == FTW_VALID_STATE) {
69885e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ACCESS_DENIED;
69985e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
70085e923a52851b242f8fc9f937c1fad7ce51246eelgao
70185e923a52851b242f8fc9f937c1fad7ce51246eelgao  if ((Record->SpareComplete != FTW_VALID_STATE)) {
70285e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
70385e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
70485e923a52851b242f8fc9f937c1fad7ce51246eelgao
70585e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
70685e923a52851b242f8fc9f937c1fad7ce51246eelgao  //  Since the content has already backuped in spare block, the write is
70785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //  guaranteed to be completed with fault tolerant manner.
70885e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
7090d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng  Status = FtwWriteRecord (This, Fvb, BlockSize);
71085e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
71185e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
71285e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
71385e923a52851b242f8fc9f937c1fad7ce51246eelgao
71485e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
71585e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Erase Spare block
71685e923a52851b242f8fc9f937c1fad7ce51246eelgao  // This is restart, no need to keep spareblock content.
71785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
718de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  Status = FtwEraseSpareBlock (FtwDevice);
719de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  if (EFI_ERROR (Status)) {
720de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng    return EFI_ABORTED;
721de2d7497fd7e64f9c2647bc5f1003d5f427916dbStar Zeng  }
72285e923a52851b242f8fc9f937c1fad7ce51246eelgao
723fcdfd249ec4782b18b5a908d90f95080bbc7c6ffLaszlo Ersek  DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
72485e923a52851b242f8fc9f937c1fad7ce51246eelgao  return EFI_SUCCESS;
72585e923a52851b242f8fc9f937c1fad7ce51246eelgao}
72685e923a52851b242f8fc9f937c1fad7ce51246eelgao
72785e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
72885e923a52851b242f8fc9f937c1fad7ce51246eelgao  Aborts all previous allocated writes.
72985e923a52851b242f8fc9f937c1fad7ce51246eelgao
73085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This                  The pointer to this protocol instance.
73185e923a52851b242f8fc9f937c1fad7ce51246eelgao
73285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_SUCCESS          The function completed successfully
73385e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_ABORTED          The function could not complete successfully.
73485e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_NOT_FOUND        No allocated writes exist.
73585e923a52851b242f8fc9f937c1fad7ce51246eelgao
73685e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
73785e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
73885e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFIAPI
73985e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwAbort (
74085e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This
74185e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
74285e923a52851b242f8fc9f937c1fad7ce51246eelgao{
74385e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_STATUS      Status;
74485e923a52851b242f8fc9f937c1fad7ce51246eelgao  UINTN           Offset;
74585e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE  *FtwDevice;
74685e923a52851b242f8fc9f937c1fad7ce51246eelgao
74785e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice = FTW_CONTEXT_FROM_THIS (This);
74885e923a52851b242f8fc9f937c1fad7ce51246eelgao
74985e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status    = WorkSpaceRefresh (FtwDevice);
75085e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
75185e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
75285e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
75385e923a52851b242f8fc9f937c1fad7ce51246eelgao
7543e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
7553e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng    return EFI_NOT_FOUND;
7563e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  }
7573e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng
75885e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
75985e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_NOT_FOUND;
76085e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
76185e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
76285e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Update the complete state of the header as VALID and abort.
76385e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
76485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
76585e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status = FtwUpdateFvState (
76685e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwFvBlock,
7670d3edd9d26300256a19472fbf82e090bbab3b5b4Star Zeng            FtwDevice->WorkBlockSize,
76885e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceLba,
76985e923a52851b242f8fc9f937c1fad7ce51246eelgao            FtwDevice->FtwWorkSpaceBase + Offset,
77085e923a52851b242f8fc9f937c1fad7ce51246eelgao            WRITES_COMPLETED
77185e923a52851b242f8fc9f937c1fad7ce51246eelgao            );
77285e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
77385e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
77485e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
77585e923a52851b242f8fc9f937c1fad7ce51246eelgao
77685e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
77785e923a52851b242f8fc9f937c1fad7ce51246eelgao
778fcdfd249ec4782b18b5a908d90f95080bbc7c6ffLaszlo Ersek  DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
77985e923a52851b242f8fc9f937c1fad7ce51246eelgao  return EFI_SUCCESS;
78085e923a52851b242f8fc9f937c1fad7ce51246eelgao}
78185e923a52851b242f8fc9f937c1fad7ce51246eelgao
78285e923a52851b242f8fc9f937c1fad7ce51246eelgao/**
78385e923a52851b242f8fc9f937c1fad7ce51246eelgao  Starts a target block update. This records information about the write
78485e923a52851b242f8fc9f937c1fad7ce51246eelgao  in fault tolerant storage and will complete the write in a recoverable
78585e923a52851b242f8fc9f937c1fad7ce51246eelgao  manner, ensuring at all times that either the original contents or
78685e923a52851b242f8fc9f937c1fad7ce51246eelgao  the modified contents are available.
78785e923a52851b242f8fc9f937c1fad7ce51246eelgao
78885e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param This            The pointer to this protocol instance.
78985e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param CallerId        The GUID identifying the last write.
79085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Lba             The logical block address of the last write.
79185e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Offset          The offset within the block of the last write.
79285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Length          The length of the last write.
79385e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param PrivateDataSize bytes from the private data
79485e923a52851b242f8fc9f937c1fad7ce51246eelgao                         stored for this write.
79585e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param PrivateData     A pointer to a buffer. The function will copy
79685e923a52851b242f8fc9f937c1fad7ce51246eelgao  @param Complete        A Boolean value with TRUE indicating
79785e923a52851b242f8fc9f937c1fad7ce51246eelgao                         that the write was completed.
79885e923a52851b242f8fc9f937c1fad7ce51246eelgao
79985e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_SUCCESS           The function completed successfully
80085e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_ABORTED           The function could not complete successfully
80185e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_NOT_FOUND         No allocated writes exist
80285e923a52851b242f8fc9f937c1fad7ce51246eelgao  @retval EFI_BUFFER_TOO_SMALL  Input buffer is not larget enough
80385e923a52851b242f8fc9f937c1fad7ce51246eelgao
80485e923a52851b242f8fc9f937c1fad7ce51246eelgao**/
80585e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFI_STATUS
80685e923a52851b242f8fc9f937c1fad7ce51246eelgaoEFIAPI
80785e923a52851b242f8fc9f937c1fad7ce51246eelgaoFtwGetLastWrite (
80885e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
80985e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT EFI_GUID                             *CallerId,
81085e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT EFI_LBA                              *Lba,
81185e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT UINTN                                *Offset,
81285e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT UINTN                                *Length,
81385e923a52851b242f8fc9f937c1fad7ce51246eelgao  IN OUT UINTN                             *PrivateDataSize,
81485e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT VOID                                 *PrivateData,
81585e923a52851b242f8fc9f937c1fad7ce51246eelgao  OUT BOOLEAN                              *Complete
81685e923a52851b242f8fc9f937c1fad7ce51246eelgao  )
81785e923a52851b242f8fc9f937c1fad7ce51246eelgao{
81885e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_STATUS                      Status;
81985e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FTW_DEVICE                  *FtwDevice;
82085e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
82185e923a52851b242f8fc9f937c1fad7ce51246eelgao  EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
82285e923a52851b242f8fc9f937c1fad7ce51246eelgao
82385e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
82485e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_UNSUPPORTED;
82585e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
82685e923a52851b242f8fc9f937c1fad7ce51246eelgao
82785e923a52851b242f8fc9f937c1fad7ce51246eelgao  FtwDevice = FTW_CONTEXT_FROM_THIS (This);
82885e923a52851b242f8fc9f937c1fad7ce51246eelgao
82985e923a52851b242f8fc9f937c1fad7ce51246eelgao  Status    = WorkSpaceRefresh (FtwDevice);
83085e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (EFI_ERROR (Status)) {
83185e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_ABORTED;
83285e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
83385e923a52851b242f8fc9f937c1fad7ce51246eelgao
83485e923a52851b242f8fc9f937c1fad7ce51246eelgao  Header  = FtwDevice->FtwLastWriteHeader;
83585e923a52851b242f8fc9f937c1fad7ce51246eelgao  Record  = FtwDevice->FtwLastWriteRecord;
83685e923a52851b242f8fc9f937c1fad7ce51246eelgao
83785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
83885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If Header is incompleted and the last record has completed, then
83985e923a52851b242f8fc9f937c1fad7ce51246eelgao  // call Abort() to set the Header->Complete FLAG.
84085e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
84185e923a52851b242f8fc9f937c1fad7ce51246eelgao  if ((Header->Complete != FTW_VALID_STATE) &&
84285e923a52851b242f8fc9f937c1fad7ce51246eelgao      (Record->DestinationComplete == FTW_VALID_STATE) &&
84385e923a52851b242f8fc9f937c1fad7ce51246eelgao      IsLastRecordOfWrites (Header, Record)
84485e923a52851b242f8fc9f937c1fad7ce51246eelgao        ) {
84585e923a52851b242f8fc9f937c1fad7ce51246eelgao
84685e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status    = FtwAbort (This);
84785e923a52851b242f8fc9f937c1fad7ce51246eelgao    *Complete = TRUE;
84885e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_NOT_FOUND;
84985e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
85085e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
85185e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If there is no write header/record, return not found.
85285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
85385e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (Header->HeaderAllocated != FTW_VALID_STATE) {
85485e923a52851b242f8fc9f937c1fad7ce51246eelgao    *Complete = TRUE;
85585e923a52851b242f8fc9f937c1fad7ce51246eelgao    return EFI_NOT_FOUND;
85685e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
85785e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
85885e923a52851b242f8fc9f937c1fad7ce51246eelgao  // If this record SpareComplete has not set, then it can not restart.
85985e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
86085e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (Record->SpareComplete != FTW_VALID_STATE) {
861f0480ecf804ff9e0e5c12d21ba563f73212028e8lgao    Status = GetPreviousRecordOfWrites (Header, &Record);
862f0480ecf804ff9e0e5c12d21ba563f73212028e8lgao    if (EFI_ERROR (Status)) {
86385e923a52851b242f8fc9f937c1fad7ce51246eelgao      FtwAbort (This);
86485e923a52851b242f8fc9f937c1fad7ce51246eelgao      *Complete = TRUE;
86585e923a52851b242f8fc9f937c1fad7ce51246eelgao      return EFI_NOT_FOUND;
86685e923a52851b242f8fc9f937c1fad7ce51246eelgao    }
867d2fbaaab17945b59ca66bcd2f72e26ba3361e1d0rsun    ASSERT (Record != NULL);
86885e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
869f0480ecf804ff9e0e5c12d21ba563f73212028e8lgao
87085e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
87185e923a52851b242f8fc9f937c1fad7ce51246eelgao  // Fill all the requested values
87285e923a52851b242f8fc9f937c1fad7ce51246eelgao  //
87385e923a52851b242f8fc9f937c1fad7ce51246eelgao  CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
87485e923a52851b242f8fc9f937c1fad7ce51246eelgao  *Lba      = Record->Lba;
8753e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  *Offset   = (UINTN) Record->Offset;
8763e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng  *Length   = (UINTN) Record->Length;
87785e923a52851b242f8fc9f937c1fad7ce51246eelgao  *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
87885e923a52851b242f8fc9f937c1fad7ce51246eelgao
87985e923a52851b242f8fc9f937c1fad7ce51246eelgao  if (*PrivateDataSize < Header->PrivateDataSize) {
8803e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng    *PrivateDataSize  = (UINTN) Header->PrivateDataSize;
88185e923a52851b242f8fc9f937c1fad7ce51246eelgao    PrivateData       = NULL;
88285e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status            = EFI_BUFFER_TOO_SMALL;
88385e923a52851b242f8fc9f937c1fad7ce51246eelgao  } else {
8843e02ebb2bbe0fd4da880511b1f35951e1c4b8404Star Zeng    *PrivateDataSize = (UINTN) Header->PrivateDataSize;
88585e923a52851b242f8fc9f937c1fad7ce51246eelgao    CopyMem (PrivateData, Record + 1, *PrivateDataSize);
88685e923a52851b242f8fc9f937c1fad7ce51246eelgao    Status = EFI_SUCCESS;
88785e923a52851b242f8fc9f937c1fad7ce51246eelgao  }
88885e923a52851b242f8fc9f937c1fad7ce51246eelgao
889fcdfd249ec4782b18b5a908d90f95080bbc7c6ffLaszlo Ersek  DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
89085e923a52851b242f8fc9f937c1fad7ce51246eelgao
89185e923a52851b242f8fc9f937c1fad7ce51246eelgao  return Status;
89285e923a52851b242f8fc9f937c1fad7ce51246eelgao}
89385e923a52851b242f8fc9f937c1fad7ce51246eelgao
894