4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/** @file
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Internal generic functions to operate flash block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncCopyright (c) 2006 - 2012, 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
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Check whether a flash buffer is erased.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Buffer Buffer to check
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param BufferSize Size of the buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @return A BOOLEAN value indicating erased or not.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncBOOLEAN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncIsErasedFlashBuffer (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINT8 *Buffer,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN BufferSize
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BOOLEAN IsEmpty;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IsEmpty = TRUE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < BufferSize; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (*Ptr++ != FTW_ERASED_BYTE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IsEmpty = FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return IsEmpty;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync To erase the block with the spare block size.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlock FVB Protocol interface
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba Lba of the firmware block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Block LBA is Erased successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval Others Error occurs
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwEraseBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FTW_DEVICE *FtwDevice,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA Lba
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FvBlock->EraseBlocks (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Lba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->NumberOfSpareBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA_LIST_TERMINATOR
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Erase spare block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The erase request was successfully completed.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_DEVICE_ERROR The block device is not functioning
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync correctly and could not be written.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync The firmware device may have been
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync partially erased.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync in the variable argument list do
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync not exist in the firmware volume.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwEraseSpareBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FTW_DEVICE *FtwDevice
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FtwDevice->FtwBackupFvb->EraseBlocks (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->NumberOfSpareBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA_LIST_TERMINATOR
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Is it in working block?
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlock Fvb protocol instance
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba The block specified
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @return A BOOLEAN value indicating in working block or not.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncBOOLEAN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncIsWorkingBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA Lba
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If matching the following condition, the target block is in working block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // 1. Target block is on the FV of working block (Using the same FVB protocol instance).
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // 2. Lba falls into the range of working block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return (BOOLEAN)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (FvBlock == FtwDevice->FtwFvBlock) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (Lba >= FtwDevice->FtwWorkBlockLba) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (Lba <= FtwDevice->FtwWorkSpaceLba)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Get firmware block by address.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Address Address specified the block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlock The block caller wanted
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The protocol instance if found.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND Block not found
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_HANDLE
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncGetFvbByAddress (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_PHYSICAL_ADDRESS Address,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_HANDLE *HandleBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN HandleCount;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_PHYSICAL_ADDRESS FvbBaseAddress;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_HANDLE FvbHandle;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FvBlock = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbHandle = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Locate all handles of Fvb protocol
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get the FVB to access variable store
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < HandleCount; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Compare the address and select the right one
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FvBlock = Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbHandle = HandleBuffer[Index];
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (HandleBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FvbHandle;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Is it in boot block?
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlock Fvb protocol instance
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba The block specified
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @return A BOOLEAN value indicating in boot block or not.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncBOOLEAN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncIsBootBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA Lba
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_PHYSICAL_ADDRESS BootBlockBase;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN BootBlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_PHYSICAL_ADDRESS BackupBlockBase;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN BackupBlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BOOLEAN IsSwapped;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_HANDLE FvbHandle;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get the boot block range
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = SarProtocol->GetRangeLocation (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SarProtocol,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &BootBlockBase,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &BootBlockSize,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &BackupBlockBase,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &BackupBlockSize
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = SarProtocol->GetSwapState (SarProtocol, &IsSwapped);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get FVB by address
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!IsSwapped) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbHandle = GetFvbByAddress (BootBlockBase, &BootFvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbHandle = GetFvbByAddress (BackupBlockBase, &BootFvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FvbHandle == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return FALSE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Compare the Fvb
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return (BOOLEAN) (FvBlock == BootFvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Spare block is accessed by FTW working FVB protocol interface. LBA is 1.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Target block is accessed by FvbBlock protocol interface. LBA is Lba.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FTW will do extra work on boot block update.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync which is produced by a chipset driver.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FTW updating boot block steps may be:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 1. GetRangeLocation(), if the Range is inside the boot block, FTW know
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync that boot block will be update. It shall add a FLAG in the working block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 2. When spare block is ready,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 3. SetSwapState(EFI_SWAPPED)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 4. erasing boot block,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 5. programming boot block until the boot block is ok.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 6. SetSwapState(UNSWAPPED)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FTW shall not allow to update boot block when battery state is error.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Spare block content is copied to boot block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_INVALID_PARAMETER Input parameter error
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_OUT_OF_RESOURCES Allocate memory error
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFlushSpareBlockToBootBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BOOLEAN TopSwap;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA BootLba;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_UNSUPPORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Locate swap address range protocol
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Allocate a memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = FtwDevice->SpareAreaLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Buffer = AllocatePool (Length);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Buffer == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_OUT_OF_RESOURCES;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get TopSwap bit state
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = SarProtocol->GetSwapState (SarProtocol, &TopSwap);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Get Top Swapped status - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (TopSwap) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get FVB of current boot block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (GetFvbByAddress (FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength, &BootFvb) == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read data from current boot block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BootLba = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = BootFvb->Read (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BootFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BootLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Count,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read data from spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Read (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Count,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Set TopSwap bit
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = SarProtocol->SetSwapState (SarProtocol, TRUE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Erase current spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Because TopSwap is set, this actually erase the top block (boot block)!
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwEraseSpareBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Write memory buffer currenet spare block. Still top block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Write (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Count,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: FVB Write boot block - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Clear TopSwap bit
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = SarProtocol->SetSwapState (SarProtocol, FALSE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Spare block is accessed by FTW backup FVB protocol interface. LBA is 1.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Target block is accessed by FvbBlock protocol interface. LBA is Lba.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlock FVB Protocol interface to access target block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba Lba of the target block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Spare block content is copied to target block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_INVALID_PARAMETER Input parameter error
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_OUT_OF_RESOURCES Allocate memory error
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFlushSpareBlockToTargetBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA Lba
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice == NULL) || (FvBlock == NULL)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_INVALID_PARAMETER;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Allocate a memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = FtwDevice->SpareAreaLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Buffer = AllocatePool (Length);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Buffer == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_OUT_OF_RESOURCES;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read all content of spare block to memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Read (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Count,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Erase the target block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwEraseBlock (FtwDevice, FvBlock, Lba);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Write memory buffer to block, using the FvbBlock protocol interface
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Spare block is accessed by FTW backup FVB protocol interface. LBA is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Working block is accessed by FTW working FVB protocol interface. LBA is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkBlockLba.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Since the working block header is important when FTW initializes, the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync state of the operation should be handled carefully. The Crc value is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync calculated without STATE element.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwDevice The private data of FTW driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Spare block content is copied to target block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_OUT_OF_RESOURCES Allocate memory error
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The function could not complete successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFlushSpareBlockToWorkingBlock (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_LBA WorkSpaceLbaOffset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Allocate a memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = FtwDevice->SpareAreaLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Buffer = AllocatePool (Length);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Buffer == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_OUT_OF_RESOURCES;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // To guarantee that the WorkingBlockValid is set on spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // WorkingBlockValid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WORKING_BLOCK_VALID
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read from spare block to memory buffer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Read (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Count,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Clear the CRC and STATE, copy data from spare to working block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize + FtwDevice->FtwWorkSpaceBase);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync InitWorkSpaceHeader (WorkingBlockHeader);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // target block is working block, then
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // before erase the working block.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // WorkingBlockInvalid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // skip Signature and Crc.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WORKING_BLOCK_INVALID
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Erase the working block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwEraseBlock (FtwDevice, FtwDevice->FtwFvBlock, FtwDevice->FtwWorkBlockLba);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Write memory buffer to working block, using the FvbBlock protocol interface
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = Buffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Count = FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwFvBlock->Write (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkBlockLba + Index,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync 0,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Count,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr += Count;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Since the memory buffer will not be used, free memory Buffer.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (Buffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Update the VALID of the working block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, WorkingBlockValid);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to skip Signature and Crc.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync WORKING_BLOCK_VALID
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Update a bit of state on a block device. The location of the bit is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync calculated by the (Lba, Offset, bit). Here bit is determined by the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync the name of a certain bit.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Lba Lba of a block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param Offset Offset on the Lba
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param NewBit New value that will override the old value if it can be change
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS A state bit has been updated successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval Others Access block device error.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Notes:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Assume all bits of State are inside the same BYTE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED Read block fail
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwUpdateFvState (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_LBA Lba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN Offset,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINT8 NewBit
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 State;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read state from device, assume State is only one byte.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = sizeof (UINT8);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync State ^= FTW_POLARITY_REVERT;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync State = (UINT8) (State | NewBit);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync State ^= FTW_POLARITY_REVERT;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Write state back to device
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = sizeof (UINT8);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Get the last Write Header pointer.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync The last write header is the header whose 'complete' state hasn't been set.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync After all, this header may be a EMPTY header entry for next Allocate.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwWorkSpaceHeader Pointer of the working block header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwWorkSpaceSize Size of the work space
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwWriteHeader Pointer to retrieve the last write header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Get the last write record successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The FTW work space is damaged
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwGetLastWriteHeader (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN UINTN FtwWorkSpaceSize,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwWriteHeader = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync while (FtwHeader->Complete == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If Offset exceed the FTW work space boudary, return error.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Offset >= FtwWorkSpaceSize) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwWriteHeader = FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Last write header is found
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwWriteHeader = FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Get the last Write Record pointer. The last write Record is the Record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync whose DestinationCompleted state hasn't been set. After all, this Record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync may be a EMPTY record entry for next write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwWriteHeader Pointer to the write record header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwWriteRecord Pointer to retrieve the last write record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Get the last write record successfully
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED The FTW work space is damaged
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFtwGetLastWriteRecord (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwWriteRecord = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Try to find the last write record "that has not completed"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // The last write record is found
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwWriteRecord = FtwRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwRecord++;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwWriteHeader->PrivateDataSize != 0) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + FtwWriteHeader->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // if Index == NumberOfWrites, then
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // the last record has been written successfully,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // but the Header->Complete Flag has not been set.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // also return the last record.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (Index == FtwWriteHeader->NumberOfWrites) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync To check if FtwRecord is the first record of FtwHeader.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwHeader Pointer to the write record header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwRecord Pointer to the write record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval TRUE FtwRecord is the first Record of the FtwHeader
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval FALSE FtwRecord is not the first Record of the FtwHeader
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncBOOLEAN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncIsFirstRecordOfWrites (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Head;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Head = (UINT8 *) FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = (UINT8 *) FtwRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Head += sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return (BOOLEAN) (Head == Ptr);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync To check if FtwRecord is the last record of FtwHeader. Because the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync determined if it is the last record of FtwHeader.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwHeader Pointer to the write record header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwRecord Pointer to the write record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval TRUE FtwRecord is the last Record of the FtwHeader
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval FALSE FtwRecord is not the last Record of the FtwHeader
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncBOOLEAN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncIsLastRecordOfWrites (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Head;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Head = (UINT8 *) FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = (UINT8 *) FtwRecord;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Head += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return (BOOLEAN) (Head == Ptr);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync To check if FtwRecord is the first record of FtwHeader.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwHeader Pointer to the write record header
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param FtwRecord Pointer to retrieve the previous write record
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS The previous write record is found.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncGetPreviousRecordOfWrites (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT8 *Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (IsFirstRecordOfWrites (FtwHeader, *FtwRecord)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwRecord = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ACCESS_DENIED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr = (UINT8 *) (*FtwRecord);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Ptr -= RECORD_SIZE (FtwHeader->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Allocate private data for FTW driver and initialize it.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param[out] FtwData Pointer to the FTW device structure
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Initialize the FTW device successfully.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_OUT_OF_RESOURCES Allocate memory error
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncInitFtwDevice (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync OUT EFI_FTW_DEVICE **FtwData
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FTW_DEVICE *FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Allocate private data of this driver,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwDevice == NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_OUT_OF_RESOURCES;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_INVALID_PARAMETER;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwDevice->WorkSpaceAddress == 0) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwDevice->SpareAreaAddress == 0) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *FtwData = FtwDevice;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Find the proper Firmware Volume Block protocol for FTW operation.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param[in, out] FtwDevice Pointer to the FTW device structure
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Find the FVB protocol successfully.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND No proper FVB protocol was found.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_ABORTED Some data can not be got or be invalid.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFindFvbForFtw (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN OUT EFI_FTW_DEVICE *FtwDevice
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_HANDLE *HandleBuffer;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN HandleCount;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Index;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_PHYSICAL_ADDRESS FvbBaseAddress;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FVB_ATTRIBUTES_2 Attributes;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINT32 LbaIndex;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get all FVB handle.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get the FVB to access variable store
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Fvb = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (Index = 0; Index < HandleCount; Index += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Ensure this FVB protocol support Write operation.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = Fvb->GetAttributes (Fvb, &Attributes);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Compare the address and select the right one
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwFvBlock = Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // To get the LBA of work space
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Now, one FV has one type of BlockLength
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbMapEntry = &FwVolHeader->BlockMap[0];
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get the Work space size and Base(Offset)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb = Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // To get the LBA of spare
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Now, one FV has one type of BlockLength
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbMapEntry = &FwVolHeader->BlockMap[0];
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Get the NumberOfSpareBlock and BlockSize
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba = LbaIndex - 1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->BlockSize = FvbMapEntry->Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Check the range of spare area to make sure that it's in FV range
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (HandleBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT (FALSE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync break;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FreePool (HandleBuffer);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_ABORTED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Initialization for Fault Tolerant Write protocol.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @param[in, out] FtwDevice Pointer to the FTW device structure
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_SUCCESS Initialize the FTW protocol successfully.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync @retval EFI_NOT_FOUND No proper FVB protocol was found.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEFI_STATUS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncInitFtwProtocol (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IN OUT EFI_FTW_DEVICE *FtwDevice
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync )
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_STATUS Status;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Length;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync UINTN Offset;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync EFI_HANDLE FvbHandle;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Find the right SMM Fvb protocol instance for FTW.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FindFvbForFtw (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (EFI_ERROR (Status)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_NOT_FOUND;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Calculate the start LBA of working block. Working block is an area which
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // contains working space in its last block and has the same size as spare
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // block, unless there are not enough blocks before the block that contains
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // working space.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwLastWriteHeader = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwLastWriteRecord = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Refresh the working space data from working block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If the working block workspace is not valid, try the spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Read from spare block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Length = FtwDevice->FtwWorkSpaceSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwDevice->FtwBackupFvb->Read (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwBackupFvb,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwSpareLba,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceBase,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync &Length,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpace
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If spare block is valid, then replace working block content.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FlushSpareBlockToWorkingBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in InitFtwProtocol() - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwAbort (&FtwDevice->FtwInstance);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Refresh work space.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = WorkSpaceRefresh (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If both are invalid, then initialize work space.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SetMem (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpace,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwWorkSpaceSize,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FTW_ERASED_BYTE
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Initialize the work space
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // (! SpareComplete) THEN call Abort().
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwAbort (&FtwDevice->FtwInstance);
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 ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwAbort (&FtwDevice->FtwInstance);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // To check the workspace buffer following last Write header/records is EMPTY or not.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // If it's not EMPTY, FTW also need to call reclaim().
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwHeader = FtwDevice->FtwLastWriteHeader;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Restart if it's boot block
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FlushSpareBlockToBootBlock (FtwDevice);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwAbort (&FtwDevice->FtwInstance);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync } else {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // if (SpareCompleted) THEN Restart to fault tolerant write.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbHandle = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FvbHandle != NULL) {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ASSERT_EFI_ERROR (Status);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwAbort (&FtwDevice->FtwInstance);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Hook the protocol API
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwInstance.Allocate = FtwAllocate;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwInstance.Write = FtwWrite;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwInstance.Restart = FtwRestart;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwInstance.Abort = FtwAbort;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return EFI_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync