mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	There are cases that the operands of an expression are all with rank less
than UINT64/INT64 and the result of the expression is explicitly cast to
UINT64/INT64 to fit the target size.
An example will be:
UINT32 a,b;
// a and b can be any unsigned int type with rank less than UINT64, like
// UINT8, UINT16, etc.
UINT64 c;
c = (UINT64) (a + b);
Some static code checkers may warn that the expression result might
overflow within the rank of "int" (integer promotions) and the result is
then cast to a bigger size.
The commit refines codes by the following rules:
1). When the expression is possible to overflow the range of unsigned int/
int:
c = (UINT64)a + b;
2). When the expression will not overflow within the rank of "int", remove
the explicit type casts:
c = a + b;
3). When the expression will be cast to pointer of possible greater size:
UINT32 a,b;
VOID *c;
c = (VOID *)(UINTN)(a + b); --> c = (VOID *)((UINTN)a + b);
4). When one side of a comparison expression contains only operands with
rank less than UINT32:
UINT8 a;
UINT16 b;
UINTN c;
if ((UINTN)(a + b) > c) {...} --> if (((UINT32)a + b) > c) {...}
For rule 4), if we remove the 'UINTN' type cast like:
if (a + b > c) {...}
The VS compiler will complain with warning C4018 (signed/unsigned
mismatch, level 3 warning) due to promoting 'a + b' to type 'int'.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
		
	
			
		
			
				
	
	
		
			620 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			620 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
   Internal functions to operate Working Block Space.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials                          
 | 
						|
are licensed and made available under the terms and conditions of the BSD License         
 | 
						|
which accompanies this distribution.  The full text of the license may be found at        
 | 
						|
http://opensource.org/licenses/bsd-license.php                                            
 | 
						|
                                                                                          
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
 | 
						|
#include "FaultTolerantWrite.h"
 | 
						|
 | 
						|
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = {ZERO_GUID, 0, 0, 0, 0, {0, 0, 0}, 0};
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize a local work space header.
 | 
						|
 | 
						|
  Since Signature and WriteQueueSize have been known, Crc can be calculated out,
 | 
						|
  then the work space header will be fixed.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializeLocalWorkSpaceHeader (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                              Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check signature with gEdkiiWorkingBlockSignatureGuid.
 | 
						|
  //
 | 
						|
  if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {
 | 
						|
    //
 | 
						|
    // The local work space header has been initialized.
 | 
						|
    //
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  SetMem (
 | 
						|
    &mWorkingBlockHeader,
 | 
						|
    sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
 | 
						|
    FTW_ERASED_BYTE
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
 | 
						|
  //
 | 
						|
  CopyMem (
 | 
						|
    &mWorkingBlockHeader.Signature,
 | 
						|
    &gEdkiiWorkingBlockSignatureGuid,
 | 
						|
    sizeof (EFI_GUID)
 | 
						|
    );
 | 
						|
  mWorkingBlockHeader.WriteQueueSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
 | 
						|
 | 
						|
  //
 | 
						|
  // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate the Crc of woking block header
 | 
						|
  //
 | 
						|
  Status = gBS->CalculateCrc32 (
 | 
						|
                  &mWorkingBlockHeader,
 | 
						|
                  sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
 | 
						|
                  &mWorkingBlockHeader.Crc
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  mWorkingBlockHeader.WorkingBlockValid    = FTW_VALID_STATE;
 | 
						|
  mWorkingBlockHeader.WorkingBlockInvalid  = FTW_INVALID_STATE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check to see if it is a valid work space.
 | 
						|
 | 
						|
 | 
						|
  @param WorkingHeader   Pointer of working block header
 | 
						|
 | 
						|
  @retval TRUE          The work space is valid.
 | 
						|
  @retval FALSE         The work space is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsValidWorkSpace (
 | 
						|
  IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (WorkingHeader == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Ftw: Work block header check mismatch\n"));
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize a work space when there is no work space.
 | 
						|
 | 
						|
  @param WorkingHeader   Pointer of working block header
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS    The function completed successfully
 | 
						|
  @retval  EFI_ABORTED    The function could not complete successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InitWorkSpaceHeader (
 | 
						|
  IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (WorkingHeader == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read work space data from work block or spare block.
 | 
						|
 | 
						|
  @param FvBlock        FVB Protocol interface to access the block.
 | 
						|
  @param BlockSize      The size of the block.
 | 
						|
  @param Lba            Lba of the block.
 | 
						|
  @param Offset         The offset within the block.
 | 
						|
  @param Length         The number of bytes to read from the block.
 | 
						|
  @param Buffer         The data is read.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The function completed successfully.
 | 
						|
  @retval EFI_ABORTED   The function could not complete successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadWorkSpaceData (
 | 
						|
  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
 | 
						|
  IN UINTN                              BlockSize,
 | 
						|
  IN EFI_LBA                            Lba,
 | 
						|
  IN UINTN                              Offset,
 | 
						|
  IN UINTN                              Length,
 | 
						|
  OUT UINT8                             *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINT8                 *Ptr;
 | 
						|
  UINTN                 MyLength;
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate the real Offset and Lba to write.
 | 
						|
  //
 | 
						|
  while (Offset >= BlockSize) {
 | 
						|
    Offset -= BlockSize;
 | 
						|
    Lba++;
 | 
						|
  }
 | 
						|
 | 
						|
  Ptr = Buffer;
 | 
						|
  while (Length > 0) {
 | 
						|
    if ((Offset + Length) > BlockSize) {
 | 
						|
      MyLength = BlockSize - Offset;
 | 
						|
    } else {
 | 
						|
      MyLength = Length;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FvBlock->Read (
 | 
						|
                        FvBlock,
 | 
						|
                        Lba,
 | 
						|
                        Offset,
 | 
						|
                        &MyLength,
 | 
						|
                        Ptr
 | 
						|
                        );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
    Offset = 0;
 | 
						|
    Length -= MyLength;
 | 
						|
    Ptr += MyLength;
 | 
						|
    Lba++;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Write work space data to work block.
 | 
						|
 | 
						|
  @param FvBlock        FVB Protocol interface to access the block.
 | 
						|
  @param BlockSize      The size of the block.
 | 
						|
  @param Lba            Lba of the block.
 | 
						|
  @param Offset         The offset within the block to place the data.
 | 
						|
  @param Length         The number of bytes to write to the block.
 | 
						|
  @param Buffer         The data to write.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The function completed successfully.
 | 
						|
  @retval EFI_ABORTED   The function could not complete successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
WriteWorkSpaceData (
 | 
						|
  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
 | 
						|
  IN UINTN                              BlockSize,
 | 
						|
  IN EFI_LBA                            Lba,
 | 
						|
  IN UINTN                              Offset,
 | 
						|
  IN UINTN                              Length,
 | 
						|
  IN UINT8                              *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINT8                 *Ptr;
 | 
						|
  UINTN                 MyLength;
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate the real Offset and Lba to write.
 | 
						|
  //
 | 
						|
  while (Offset >= BlockSize) {
 | 
						|
    Offset -= BlockSize;
 | 
						|
    Lba++;
 | 
						|
  }
 | 
						|
 | 
						|
  Ptr = Buffer;
 | 
						|
  while (Length > 0) {
 | 
						|
    if ((Offset + Length) > BlockSize) {
 | 
						|
      MyLength = BlockSize - Offset;
 | 
						|
    } else {
 | 
						|
      MyLength = Length;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FvBlock->Write (
 | 
						|
                        FvBlock,
 | 
						|
                        Lba,
 | 
						|
                        Offset,
 | 
						|
                        &MyLength,
 | 
						|
                        Ptr
 | 
						|
                        );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
    Offset = 0;
 | 
						|
    Length -= MyLength;
 | 
						|
    Ptr += MyLength;
 | 
						|
    Lba++;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read from working block to refresh the work space in memory.
 | 
						|
 | 
						|
  @param FtwDevice   Point to private data of FTW driver
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS    The function completed successfully
 | 
						|
  @retval  EFI_ABORTED    The function could not complete successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
WorkSpaceRefresh (
 | 
						|
  IN EFI_FTW_DEVICE  *FtwDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UINTN                           RemainingSpaceSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize WorkSpace as FTW_ERASED_BYTE
 | 
						|
  //
 | 
						|
  SetMem (
 | 
						|
    FtwDevice->FtwWorkSpace,
 | 
						|
    FtwDevice->FtwWorkSpaceSize,
 | 
						|
    FTW_ERASED_BYTE
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Read from working block
 | 
						|
  //
 | 
						|
  Status = ReadWorkSpaceData (
 | 
						|
             FtwDevice->FtwFvBlock,
 | 
						|
             FtwDevice->WorkBlockSize,
 | 
						|
             FtwDevice->FtwWorkSpaceLba,
 | 
						|
             FtwDevice->FtwWorkSpaceBase,
 | 
						|
             FtwDevice->FtwWorkSpaceSize,
 | 
						|
             FtwDevice->FtwWorkSpace
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Refresh the FtwLastWriteHeader
 | 
						|
  //
 | 
						|
  Status = FtwGetLastWriteHeader (
 | 
						|
            FtwDevice->FtwWorkSpaceHeader,
 | 
						|
            FtwDevice->FtwWorkSpaceSize,
 | 
						|
            &FtwDevice->FtwLastWriteHeader
 | 
						|
            );
 | 
						|
  RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN) FtwDevice->FtwLastWriteHeader - (UINTN) FtwDevice->FtwWorkSpace);
 | 
						|
  DEBUG ((EFI_D_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));
 | 
						|
  //
 | 
						|
  // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
 | 
						|
  // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
 | 
						|
  // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
 | 
						|
  // it needs to reclaim work space.
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (Status) || RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD)) {
 | 
						|
    //
 | 
						|
    // reclaim work space in working block.
 | 
						|
    //
 | 
						|
    Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Ftw: Reclaim workspace - %r\n", Status));
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Read from working block again
 | 
						|
    //
 | 
						|
    Status = ReadWorkSpaceData (
 | 
						|
               FtwDevice->FtwFvBlock,
 | 
						|
               FtwDevice->WorkBlockSize,
 | 
						|
               FtwDevice->FtwWorkSpaceLba,
 | 
						|
               FtwDevice->FtwWorkSpaceBase,
 | 
						|
               FtwDevice->FtwWorkSpaceSize,
 | 
						|
               FtwDevice->FtwWorkSpace
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FtwGetLastWriteHeader (
 | 
						|
              FtwDevice->FtwWorkSpaceHeader,
 | 
						|
              FtwDevice->FtwWorkSpaceSize,
 | 
						|
              &FtwDevice->FtwLastWriteHeader
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Refresh the FtwLastWriteRecord
 | 
						|
  //
 | 
						|
  Status = FtwGetLastWriteRecord (
 | 
						|
            FtwDevice->FtwLastWriteHeader,
 | 
						|
            &FtwDevice->FtwLastWriteRecord
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reclaim the work space on the working block.
 | 
						|
 | 
						|
  @param FtwDevice       Point to private data of FTW driver
 | 
						|
  @param PreserveRecord  Whether to preserve the working record is needed
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The function completed successfully
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Allocate memory error
 | 
						|
  @retval EFI_ABORTED            The function could not complete successfully
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FtwReclaimWorkSpace (
 | 
						|
  IN EFI_FTW_DEVICE  *FtwDevice,
 | 
						|
  IN BOOLEAN         PreserveRecord
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                              Status;
 | 
						|
  UINTN                                   Length;
 | 
						|
  EFI_FAULT_TOLERANT_WRITE_HEADER         *Header;
 | 
						|
  UINT8                                   *TempBuffer;
 | 
						|
  UINTN                                   TempBufferSize;
 | 
						|
  UINTN                                   SpareBufferSize;
 | 
						|
  UINT8                                   *SpareBuffer;
 | 
						|
  EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
 | 
						|
  UINTN                                   Index;
 | 
						|
  UINT8                                   *Ptr;
 | 
						|
  EFI_LBA                                 WorkSpaceLbaOffset;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Ftw: start to reclaim work space\n"));
 | 
						|
 | 
						|
  WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read all original data from working block to a memory buffer
 | 
						|
  //
 | 
						|
  TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;
 | 
						|
  TempBuffer     = AllocateZeroPool (TempBufferSize);
 | 
						|
  if (TempBuffer == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Ptr = TempBuffer;
 | 
						|
  for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {
 | 
						|
    Length = FtwDevice->WorkBlockSize;
 | 
						|
    Status = FtwDevice->FtwFvBlock->Read (
 | 
						|
                                          FtwDevice->FtwFvBlock,
 | 
						|
                                          FtwDevice->FtwWorkBlockLba + Index,
 | 
						|
                                          0,
 | 
						|
                                          &Length,
 | 
						|
                                          Ptr
 | 
						|
                                          );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FreePool (TempBuffer);
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Ptr += Length;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Clean up the workspace, remove all the completed records.
 | 
						|
  //
 | 
						|
  Ptr = TempBuffer +
 | 
						|
        (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
 | 
						|
        FtwDevice->FtwWorkSpaceBase;
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear the content of buffer that will save the new work space data
 | 
						|
  //
 | 
						|
  SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
 | 
						|
  //
 | 
						|
  CopyMem (
 | 
						|
    Ptr,
 | 
						|
    FtwDevice->FtwWorkSpaceHeader,
 | 
						|
    sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
 | 
						|
    );
 | 
						|
  if (PreserveRecord) {
 | 
						|
    //
 | 
						|
    // Get the last record following the header,
 | 
						|
    //
 | 
						|
    Status = FtwGetLastWriteHeader (
 | 
						|
               FtwDevice->FtwWorkSpaceHeader,
 | 
						|
               FtwDevice->FtwWorkSpaceSize,
 | 
						|
               &FtwDevice->FtwLastWriteHeader
 | 
						|
               );
 | 
						|
    Header = FtwDevice->FtwLastWriteHeader;
 | 
						|
    if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {
 | 
						|
      CopyMem (
 | 
						|
        Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
 | 
						|
        FtwDevice->FtwLastWriteHeader,
 | 
						|
        FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    FtwDevice->FtwWorkSpace,
 | 
						|
    Ptr,
 | 
						|
    FtwDevice->FtwWorkSpaceSize
 | 
						|
    );
 | 
						|
 | 
						|
  FtwGetLastWriteHeader (
 | 
						|
    FtwDevice->FtwWorkSpaceHeader,
 | 
						|
    FtwDevice->FtwWorkSpaceSize,
 | 
						|
    &FtwDevice->FtwLastWriteHeader
 | 
						|
    );
 | 
						|
 | 
						|
  FtwGetLastWriteRecord (
 | 
						|
    FtwDevice->FtwLastWriteHeader,
 | 
						|
    &FtwDevice->FtwLastWriteRecord
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
 | 
						|
  //
 | 
						|
  WorkingBlockHeader                      = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (TempBuffer +
 | 
						|
                                            (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
 | 
						|
                                            FtwDevice->FtwWorkSpaceBase);
 | 
						|
  WorkingBlockHeader->WorkingBlockValid   = FTW_INVALID_STATE;
 | 
						|
  WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to keep the content of spare block
 | 
						|
  // Save spare block into a spare backup memory buffer (Sparebuffer)
 | 
						|
  //
 | 
						|
  SpareBufferSize = FtwDevice->SpareAreaLength;
 | 
						|
  SpareBuffer     = AllocatePool (SpareBufferSize);
 | 
						|
  if (SpareBuffer == NULL) {
 | 
						|
    FreePool (TempBuffer);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Ptr = SpareBuffer;
 | 
						|
  for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
 | 
						|
    Length = FtwDevice->SpareBlockSize;
 | 
						|
    Status = FtwDevice->FtwBackupFvb->Read (
 | 
						|
                                        FtwDevice->FtwBackupFvb,
 | 
						|
                                        FtwDevice->FtwSpareLba + Index,
 | 
						|
                                        0,
 | 
						|
                                        &Length,
 | 
						|
                                        Ptr
 | 
						|
                                        );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FreePool (TempBuffer);
 | 
						|
      FreePool (SpareBuffer);
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Ptr += Length;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Write the memory buffer to spare block
 | 
						|
  //
 | 
						|
  Status  = FtwEraseSpareBlock (FtwDevice);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (TempBuffer);
 | 
						|
    FreePool (SpareBuffer);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
  Ptr     = TempBuffer;
 | 
						|
  for (Index = 0; TempBufferSize > 0; Index += 1) {
 | 
						|
    if (TempBufferSize > FtwDevice->SpareBlockSize) {
 | 
						|
      Length = FtwDevice->SpareBlockSize;
 | 
						|
    } else {
 | 
						|
      Length = TempBufferSize;
 | 
						|
    }
 | 
						|
    Status = FtwDevice->FtwBackupFvb->Write (
 | 
						|
                                            FtwDevice->FtwBackupFvb,
 | 
						|
                                            FtwDevice->FtwSpareLba + Index,
 | 
						|
                                            0,
 | 
						|
                                            &Length,
 | 
						|
                                            Ptr
 | 
						|
                                            );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FreePool (TempBuffer);
 | 
						|
      FreePool (SpareBuffer);
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Ptr += Length;
 | 
						|
    TempBufferSize -= Length;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Free TempBuffer
 | 
						|
  //
 | 
						|
  FreePool (TempBuffer);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the WorkingBlockValid in spare block
 | 
						|
  //
 | 
						|
  Status = FtwUpdateFvState (
 | 
						|
            FtwDevice->FtwBackupFvb,
 | 
						|
            FtwDevice->SpareBlockSize,
 | 
						|
            FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
 | 
						|
            FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),
 | 
						|
            WORKING_BLOCK_VALID
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (SpareBuffer);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Before erase the working block, set WorkingBlockInvalid in working block.
 | 
						|
  //
 | 
						|
  // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
 | 
						|
  //                          WorkingBlockInvalid);
 | 
						|
  //
 | 
						|
  Status = FtwUpdateFvState (
 | 
						|
            FtwDevice->FtwFvBlock,
 | 
						|
            FtwDevice->WorkBlockSize,
 | 
						|
            FtwDevice->FtwWorkSpaceLba,
 | 
						|
            FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
 | 
						|
            WORKING_BLOCK_INVALID
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (SpareBuffer);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Write the spare block to working block
 | 
						|
  //
 | 
						|
  Status = FlushSpareBlockToWorkingBlock (FtwDevice);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (SpareBuffer);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
 | 
						|
  //
 | 
						|
  Status  = FtwEraseSpareBlock (FtwDevice);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (SpareBuffer);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
  Ptr     = SpareBuffer;
 | 
						|
  for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
 | 
						|
    Length = FtwDevice->SpareBlockSize;
 | 
						|
    Status = FtwDevice->FtwBackupFvb->Write (
 | 
						|
                                        FtwDevice->FtwBackupFvb,
 | 
						|
                                        FtwDevice->FtwSpareLba + Index,
 | 
						|
                                        0,
 | 
						|
                                        &Length,
 | 
						|
                                        Ptr
 | 
						|
                                        );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FreePool (SpareBuffer);
 | 
						|
      return EFI_ABORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Ptr += Length;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (SpareBuffer);
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Ftw: reclaim work space successfully\n"));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |