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