/** @file Handles non-volatile variable store garbage collection, using FTW (Fault Tolerant Write) protocol. Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Variable.h" /** Gets LBA of block and offset by given address. This function gets the Logical Block Address (LBA) of a firmware volume block containing the given address, and the offset of the address on the block. @param Address Address which should be contained by returned FVB handle. @param Lba Pointer to LBA for output. @param Offset Pointer to offset for output. @retval EFI_SUCCESS LBA and offset successfully returned. @retval EFI_NOT_FOUND Fail to find FVB handle by address. @retval EFI_ABORTED Fail to find valid LBA and offset. **/ EFI_STATUS GetLbaAndOffsetByAddress ( IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_LBA *Lba, OUT UINTN *Offset ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS FvbBaseAddress; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; UINT32 LbaIndex; Fvb = NULL; *Lba = (EFI_LBA)(-1); *Offset = 0; // // Get the proper FVB protocol. // Status = GetFvbInfoByAddress (Address, NULL, &Fvb); if (EFI_ERROR (Status)) { return Status; } // // Get the Base Address of FV. // Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); if (EFI_ERROR (Status)) { return Status; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbBaseAddress); // // Get the (LBA, Offset) of Address. // if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { // // BUGBUG: Assume one FV has one type of BlockLength. // FvbMapEntry = &FwVolHeader->BlockMap[0]; for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { // // Found the (Lba, Offset). // *Lba = LbaIndex - 1; *Offset = (UINTN)(Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); return EFI_SUCCESS; } } } return EFI_ABORTED; } /** Writes a buffer to variable storage space, in the working block. This function writes a buffer to variable storage space into a firmware volume block device. The destination is specified by parameter VariableBase. Fault Tolerant Write protocol is used for writing. @param VariableBase Base address of variable to write @param VariableBuffer Point to the variable data buffer. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. @retval EFI_ABORTED The function could not complete successfully. **/ EFI_STATUS FtwVariableSpace ( IN EFI_PHYSICAL_ADDRESS VariableBase, IN VARIABLE_STORE_HEADER *VariableBuffer ) { EFI_STATUS Status; EFI_HANDLE FvbHandle; EFI_LBA VarLba; UINTN VarOffset; UINTN FtwBufferSize; EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; // // Locate fault tolerant write protocol. // Status = GetFtwProtocol ((VOID **)&FtwProtocol); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Locate Fvb handle by address. // Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL); if (EFI_ERROR (Status)) { return Status; } // // Get LBA and Offset by address. // Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset); if (EFI_ERROR (Status)) { return EFI_ABORTED; } FtwBufferSize = ((VARIABLE_STORE_HEADER *)((UINTN)VariableBase))->Size; ASSERT (FtwBufferSize == VariableBuffer->Size); // // FTW write record. // Status = FtwProtocol->Write ( FtwProtocol, VarLba, // LBA VarOffset, // Offset FtwBufferSize, // NumBytes NULL, // PrivateData NULL FvbHandle, // Fvb Handle (VOID *)VariableBuffer // write buffer ); return Status; }