4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/** @file
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync These are the common Fault Tolerant Write (FTW) functions that are shared
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync by DXE FTW driver and SMM FTW driver.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncCopyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncThis program and the accompanying materials
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncare licensed and made available under the terms and conditions of the BSD License
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncwhich accompanies this distribution. The full text of the license may be found at
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynchttp://opensource.org/licenses/bsd-license.php
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "FaultTolerantWrite.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Fault Tolerant Write Protocol API
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Query the largest block that may be updated in a fault tolerant manner.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param BlockSize A pointer to a caller allocated UINTN that is updated to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync indicate the size of the largest block that can be updated.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @return EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwGetMaxBlockSize (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT UINTN *BlockSize
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_UNSUPPORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *BlockSize = FtwDevice->SpareAreaLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Allocates space for the protocol to maintain information about writes.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Since writes must be completed in a fault tolerant manner and multiple
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync updates will require more resources to be successful, this function
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync enables the protocol to ensure that enough space exists to track
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync information about the upcoming writes.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync All writes must be completed or aborted before another fault tolerant write can occur.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param CallerId The GUID identifying the write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param PrivateDataSize The size of the caller's private data
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync that must be recorded for each write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param NumberOfWrites The number of fault tolerant block writes
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync that will need to occur.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @return EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwAllocate (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_GUID *CallerId,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN PrivateDataSize,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN NumberOfWrites
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Check if there is enough space for the coming allocation
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_BUFFER_TOO_SMALL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Find the last write header and record.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If the FtwHeader is complete, skip the completed last write header/records
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Previous write has not completed, access denied.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If workspace is not enough, then reclaim workspace
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Offset + WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Prepare FTW write header,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // overwrite the buffer and write to workspace.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader->WritesAllocated = FTW_INVALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader->Complete = FTW_INVALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader->NumberOfWrites = NumberOfWrites;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader->PrivateDataSize = PrivateDataSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader->HeaderAllocated = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwFvBlock->Write (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Length,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (UINT8 *) FtwHeader
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Update Header->WriteAllocated as VALID
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WRITES_ALLOCATED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (EFI_D_ERROR,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Ftw: Allocate() success, Caller:%g, # %d\n",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CallerId,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync NumberOfWrites)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Write a record with fault tolerant mannaer.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Since the content has already backuped in spare block, the write is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync guaranteed to be completed with fault tolerant manner.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Fvb The FVB protocol that provides services for
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync reading, writing, and erasing the target block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwWriteRecord (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Spare Complete but Destination not complete,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Recover the target block with the spare block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Header = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record = FtwDevice->FtwLastWriteRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // IF target block is working block, THEN Flush Spare Block To Working Block;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // ELSE flush spare block to target block, which may be boot block after all.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If target block is working block,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // it also need to set SPARE_COMPLETED to spare block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SPARE_COMPLETED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FlushSpareBlockToWorkingBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else if (IsBootBlock (FtwDevice, Fvb, Record->Lba)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Update boot block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FlushSpareBlockToBootBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Update blocks other than working block or boot block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Record the DestionationComplete in record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEST_COMPLETED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->DestinationComplete = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If this is the last Write in these write sequence,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // set the complete flag of write header.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (IsLastRecordOfWrites (Header, Record)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WRITES_COMPLETED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Header->Complete = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Starts a target block update. This function will record data about write
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync in fault tolerant storage and will complete the write in a recoverable
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync manner, ensuring at all times that either the original contents or
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync the modified contents are available.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba The logical block address of the target block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Offset The offset within the target block to place the data.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Length The number of bytes to write to the target block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param PrivateData A pointer to private data that the caller requires to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync complete any pending writes in the event of a fault.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlockHandle The handle of FVB protocol that provides services for
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync reading, writing, and erasing the target block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Buffer The data to write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset + *NumBytes > SpareAreaLength.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ACCESS_DENIED No writes have been allocated.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwWrite (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_LBA Lba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN Length,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN VOID *PrivateData,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_HANDLE FvBlockHandle,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN VOID *Buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN MyLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN MyOffset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN MyBufferSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *MyBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN SpareBufferSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *SpareBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Header = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record = FtwDevice->FtwLastWriteRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (PrivateData == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Ftw Write Header is not allocated.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // No additional private data, the private data size is zero. Number of record can be set to 1.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Ftw Write Header is not allocated
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Additional private data is not NULL, the private data size can't be determined.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_READY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If Record is out of the range of Header, return access denied.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Check the COMPLETE flag of last write header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Header->Complete == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Record->DestinationComplete == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_READY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Check if the input data can fit within the target block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((Offset + Length) > FtwDevice->SpareAreaLength) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_BAD_BUFFER_SIZE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get the FVB protocol by handle
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Set BootBlockUpdate FLAG if it's updating boot block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (IsBootBlock (FtwDevice, Fvb, Lba)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->BootBlockUpdate = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Write the record to the work space.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->Lba = Lba;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->Offset = Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->Length = Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->FvBaseAddress = FvbPhysicalAddress;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (PrivateData != NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyLength = RECORD_SIZE (Header->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwFvBlock->Write (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + MyOffset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &MyLength,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (UINT8 *) Record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Record has written to working block, then do the data.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Allocate a memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyBufferSize = FtwDevice->SpareAreaLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyBuffer = AllocatePool (MyBufferSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (MyBuffer == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_OUT_OF_RESOURCES;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read all original data from target block to memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = MyBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyLength = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (MyBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += MyLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Overwrite the updating range data with
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // the input buffer content
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CopyMem (MyBuffer + Offset, Buffer, Length);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Try to keep the content of spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Save spare block into a spare backup memory buffer (Sparebuffer)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SpareBufferSize = FtwDevice->SpareAreaLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SpareBuffer = AllocatePool (SpareBufferSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (SpareBuffer == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (MyBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_OUT_OF_RESOURCES;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = SpareBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyLength = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Read (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &MyLength,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (MyBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (SpareBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += MyLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Write the memory buffer to spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwEraseSpareBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = MyBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyLength = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Write (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &MyLength,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (MyBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (SpareBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += MyLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Free MyBuffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (MyBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Set the SpareComplete in the FTW record,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + MyOffset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SPARE_COMPLETED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (SpareBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record->SpareComplete = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Since the content has already backuped in spare block, the write is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // guaranteed to be completed with fault tolerant manner.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwWriteRecord (This, Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (SpareBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwEraseSpareBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = SpareBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync MyLength = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Write (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &MyLength,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (SpareBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += MyLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // All success.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (SpareBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (EFI_D_ERROR,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Lba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Restarts a previously interrupted write. The caller must provide the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync block protocol needed to complete the interrupted write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlockHandle The handle of FVB protocol that provides services for
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync reading, writing, and erasing the target block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ACCESS_DENIED No pending writes exist
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND FVB protocol not found by the handle
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwRestart (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_HANDLE FvBlockHandle
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Header = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record = FtwDevice->FtwLastWriteRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Spare Complete but Destination not complete,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Recover the targt block with the spare block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Check the COMPLETE flag of last write header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Header->Complete == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Check the flags of last write record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Record->DestinationComplete == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((Record->SpareComplete != FTW_VALID_STATE)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Since the content has already backuped in spare block, the write is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // guaranteed to be completed with fault tolerant manner.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwWriteRecord (This, Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Erase Spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // This is restart, no need to keep spareblock content.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwEraseSpareBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Aborts all previous allocated writes.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND No allocated writes exist.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwAbort (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Update the complete state of the header as VALID and abort.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WRITES_COMPLETED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Starts a target block update. This records information about the write
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync in fault tolerant storage and will complete the write in a recoverable
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync manner, ensuring at all times that either the original contents or
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync the modified contents are available.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param This The pointer to this protocol instance.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param CallerId The GUID identifying the last write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba The logical block address of the last write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Offset The offset within the block of the last write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Length The length of the last write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param PrivateDataSize bytes from the private data
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync stored for this write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param PrivateData A pointer to a buffer. The function will copy
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Complete A Boolean value with TRUE indicating
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync that the write was completed.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The function completed successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND No allocated writes exist
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwGetLastWrite (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT EFI_GUID *CallerId,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT EFI_LBA *Lba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT UINTN *Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT UINTN *Length,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN OUT UINTN *PrivateDataSize,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT VOID *PrivateData,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT BOOLEAN *Complete
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_UNSUPPORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = FTW_CONTEXT_FROM_THIS (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Header = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Record = FtwDevice->FtwLastWriteRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If Header is incompleted and the last record has completed, then
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // call Abort() to set the Header->Complete FLAG.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((Header->Complete != FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (Record->DestinationComplete == FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IsLastRecordOfWrites (Header, Record)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwAbort (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Complete = TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If there is no write header/record, return not found.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Header->HeaderAllocated != FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Complete = TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If this record SpareComplete has not set, then it can not restart.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Record->SpareComplete != FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = GetPreviousRecordOfWrites (Header, &Record);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwAbort (This);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Complete = TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT (Record != NULL);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Fill all the requested values
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Lba = Record->Lba;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Offset = Record->Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Length = Record->Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (*PrivateDataSize < Header->PrivateDataSize) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *PrivateDataSize = Header->PrivateDataSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PrivateData = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = EFI_BUFFER_TOO_SMALL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *PrivateDataSize = Header->PrivateDataSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CopyMem (PrivateData, Record + 1, *PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync