1 /** @file 2 Handles non-volatile variable store garbage collection, using FTW 3 (Fault Tolerant Write) protocol. 4 5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "Variable.h" 17 18 /** 19 Gets LBA of block and offset by given address. 20 21 This function gets the Logical Block Address (LBA) of a firmware 22 volume block containing the given address, and the offset of the 23 address on the block. 24 25 @param Address Address which should be contained 26 by returned FVB handle. 27 @param Lba Pointer to LBA for output. 28 @param Offset Pointer to offset for output. 29 30 @retval EFI_SUCCESS LBA and offset successfully returned. 31 @retval EFI_NOT_FOUND Fail to find FVB handle by address. 32 @retval EFI_ABORTED Fail to find valid LBA and offset. 33 34 **/ 35 EFI_STATUS 36 GetLbaAndOffsetByAddress ( 37 IN EFI_PHYSICAL_ADDRESS Address, 38 OUT EFI_LBA *Lba, 39 OUT UINTN *Offset 40 ) 41 { 42 EFI_STATUS Status; 43 EFI_PHYSICAL_ADDRESS FvbBaseAddress; 44 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; 45 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 46 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; 47 UINT32 LbaIndex; 48 49 Fvb = NULL; 50 *Lba = (EFI_LBA) (-1); 51 *Offset = 0; 52 53 // 54 // Get the proper FVB protocol. 55 // 56 Status = GetFvbInfoByAddress (Address, NULL, &Fvb); 57 if (EFI_ERROR (Status)) { 58 return Status; 59 } 60 61 // 62 // Get the Base Address of FV. 63 // 64 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); 65 if (EFI_ERROR (Status)) { 66 return Status; 67 } 68 69 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); 70 71 // 72 // Get the (LBA, Offset) of Address. 73 // 74 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { 75 // 76 // BUGBUG: Assume one FV has one type of BlockLength. 77 // 78 FvbMapEntry = &FwVolHeader->BlockMap[0]; 79 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { 80 if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { 81 // 82 // Found the (Lba, Offset). 83 // 84 *Lba = LbaIndex - 1; 85 *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); 86 return EFI_SUCCESS; 87 } 88 } 89 } 90 91 return EFI_ABORTED; 92 } 93 94 /** 95 Writes a buffer to variable storage space, in the working block. 96 97 This function writes a buffer to variable storage space into a firmware 98 volume block device. The destination is specified by parameter 99 VariableBase. Fault Tolerant Write protocol is used for writing. 100 101 @param VariableBase Base address of variable to write 102 @param VariableBuffer Point to the variable data buffer. 103 104 @retval EFI_SUCCESS The function completed successfully. 105 @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. 106 @retval EFI_ABORTED The function could not complete successfully. 107 108 **/ 109 EFI_STATUS 110 FtwVariableSpace ( 111 IN EFI_PHYSICAL_ADDRESS VariableBase, 112 IN VARIABLE_STORE_HEADER *VariableBuffer 113 ) 114 { 115 EFI_STATUS Status; 116 EFI_HANDLE FvbHandle; 117 EFI_LBA VarLba; 118 UINTN VarOffset; 119 UINTN FtwBufferSize; 120 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; 121 122 // 123 // Locate fault tolerant write protocol. 124 // 125 Status = GetFtwProtocol((VOID **) &FtwProtocol); 126 if (EFI_ERROR (Status)) { 127 return EFI_NOT_FOUND; 128 } 129 // 130 // Locate Fvb handle by address. 131 // 132 Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL); 133 if (EFI_ERROR (Status)) { 134 return Status; 135 } 136 // 137 // Get LBA and Offset by address. 138 // 139 Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset); 140 if (EFI_ERROR (Status)) { 141 return EFI_ABORTED; 142 } 143 144 FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size; 145 ASSERT (FtwBufferSize == VariableBuffer->Size); 146 147 // 148 // FTW write record. 149 // 150 Status = FtwProtocol->Write ( 151 FtwProtocol, 152 VarLba, // LBA 153 VarOffset, // Offset 154 FtwBufferSize, // NumBytes 155 NULL, // PrivateData NULL 156 FvbHandle, // Fvb Handle 157 (VOID *) VariableBuffer // write buffer 158 ); 159 160 return Status; 161 } 162