blob: fe64d0a2b3dddb0f9e3304a13be30cb41b44d93e [file] [log] [blame]
/** @file
Handles non-volatile variable store garbage collection, using FTW
(Fault Tolerant Write) protocol.
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
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;
}