| /** @file | |
| Handles non-volatile variable store garbage collection, using FTW | |
| (Fault Tolerant Write) protocol. | |
| Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #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; | |
| } |