]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
Update Variable driver to depend on full version FaultTolerantWrite protocol, and...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Reclaim.c
1 /** @file
2
3 Handles non-volatile variable store garbage collection, using FTW
4 (Fault Tolerant Write) protocol.
5
6 Copyright (c) 2006 - 2008, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17
18 #include "Variable.h"
19
20 /**
21 Gets firmware volume block handle by given address.
22
23 This function gets firmware volume block handle whose
24 address range contains the parameter Address.
25
26 @param Address Address which should be contained
27 by returned FVB handle
28 @param FvbHandle Pointer to FVB handle for output
29
30 @retval EFI_SUCCESS FVB handle successfully returned
31 @retval EFI_NOT_FOUND Fail to find FVB handle by address
32
33 **/
34 EFI_STATUS
35 GetFvbHandleByAddress (
36 IN EFI_PHYSICAL_ADDRESS Address,
37 OUT EFI_HANDLE *FvbHandle
38 )
39 {
40 EFI_STATUS Status;
41 EFI_HANDLE *HandleBuffer;
42 UINTN HandleCount;
43 UINTN Index;
44 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
45 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
46 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
47
48 *FvbHandle = NULL;
49 //
50 // Locate all handles of Fvb protocol
51 //
52 Status = gBS->LocateHandleBuffer (
53 ByProtocol,
54 &gEfiFirmwareVolumeBlockProtocolGuid,
55 NULL,
56 &HandleCount,
57 &HandleBuffer
58 );
59 if (EFI_ERROR (Status)) {
60 return EFI_NOT_FOUND;
61 }
62 //
63 // Get the FVB to access variable store
64 //
65 for (Index = 0; Index < HandleCount; Index += 1) {
66 Status = gBS->HandleProtocol (
67 HandleBuffer[Index],
68 &gEfiFirmwareVolumeBlockProtocolGuid,
69 (VOID **) &Fvb
70 );
71 if (EFI_ERROR (Status)) {
72 Status = EFI_NOT_FOUND;
73 break;
74 }
75 //
76 // Compare the address and select the right one
77 //
78 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
79 if (EFI_ERROR (Status)) {
80 continue;
81 }
82
83 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
84 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
85 *FvbHandle = HandleBuffer[Index];
86 Status = EFI_SUCCESS;
87 break;
88 }
89 }
90
91 FreePool (HandleBuffer);
92 return Status;
93 }
94
95 /**
96 Gets LBA of block and offset by given address.
97
98 This function gets the Logical Block Address (LBA) of firmware
99 volume block containing the given address, and the offset of
100 address on the block.
101
102 @param Address Address which should be contained
103 by returned FVB handle
104 @param Lba Pointer to LBA for output
105 @param Offset Pointer to offset for output
106
107 @retval EFI_SUCCESS LBA and offset successfully returned
108 @retval EFI_NOT_FOUND Fail to find FVB handle by address
109 @retval EFI_ABORTED Fail to find valid LBA and offset
110
111 **/
112 EFI_STATUS
113 GetLbaAndOffsetByAddress (
114 IN EFI_PHYSICAL_ADDRESS Address,
115 OUT EFI_LBA *Lba,
116 OUT UINTN *Offset
117 )
118 {
119 EFI_STATUS Status;
120 EFI_HANDLE FvbHandle;
121 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
122 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
123 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
124 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
125 UINT32 LbaIndex;
126
127 *Lba = (EFI_LBA) (-1);
128 *Offset = 0;
129
130 //
131 // Get the proper FVB
132 //
133 Status = GetFvbHandleByAddress (Address, &FvbHandle);
134 if (EFI_ERROR (Status)) {
135 return Status;
136 }
137
138 Status = gBS->HandleProtocol (
139 FvbHandle,
140 &gEfiFirmwareVolumeBlockProtocolGuid,
141 (VOID **) &Fvb
142 );
143 if (EFI_ERROR (Status)) {
144 return Status;
145 }
146 //
147 // Get the Base Address of FV
148 //
149 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
150 if (EFI_ERROR (Status)) {
151 return Status;
152 }
153
154 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
155
156 //
157 // Get the (LBA, Offset) of Address
158 //
159 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
160 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
161 //
162 // BUGBUG: Assume one FV has one type of BlockLength
163 //
164 FvbMapEntry = &FwVolHeader->BlockMap[0];
165 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
166 if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
167 //
168 // Found the (Lba, Offset)
169 //
170 *Lba = LbaIndex - 1;
171 *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
172 return EFI_SUCCESS;
173 }
174 }
175 }
176 }
177
178 return EFI_ABORTED;
179 }
180
181 /**
182 Writes a buffer to variable storage space, in the working block.
183
184 This function writes a buffer to variable storage space into firmware
185 volume block device. The destination is specified by parameter
186 VariableBase. Fault Tolerant Write protocol is used for writing.
187
188 @param VariableBase Base address of variable to write
189 @param Buffer Point to the data buffer
190 @param BufferSize The number of bytes of the data Buffer
191
192 @retval EFI_SUCCESS The function completed successfully
193 @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol
194 @retval EFI_ABORTED The function could not complete successfully
195
196 **/
197 EFI_STATUS
198 FtwVariableSpace (
199 IN EFI_PHYSICAL_ADDRESS VariableBase,
200 IN UINT8 *Buffer,
201 IN UINTN BufferSize
202 )
203 {
204 EFI_STATUS Status;
205 EFI_HANDLE FvbHandle;
206 EFI_LBA VarLba;
207 UINTN VarOffset;
208 UINT8 *FtwBuffer;
209 UINTN FtwBufferSize;
210 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
211
212 //
213 // Locate fault tolerant write protocol
214 //
215 Status = gBS->LocateProtocol (
216 &gEfiFaultTolerantWriteProtocolGuid,
217 NULL,
218 (VOID **) &FtwProtocol
219 );
220 if (EFI_ERROR (Status)) {
221 return EFI_NOT_FOUND;
222 }
223 //
224 // Locate Fvb handle by address
225 //
226 Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);
227 if (EFI_ERROR (Status)) {
228 return Status;
229 }
230 //
231 // Get LBA and Offset by address
232 //
233 Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
234 if (EFI_ERROR (Status)) {
235 return EFI_ABORTED;
236 }
237 //
238 // Prepare for the variable data
239 //
240 FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
241 FtwBuffer = AllocateRuntimePool (FtwBufferSize);
242 if (FtwBuffer == NULL) {
243 return EFI_OUT_OF_RESOURCES;
244 }
245
246 SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);
247 CopyMem (FtwBuffer, Buffer, BufferSize);
248
249 //
250 // FTW write record
251 //
252 Status = FtwProtocol->Write (
253 FtwProtocol,
254 VarLba, // LBA
255 VarOffset, // Offset
256 FtwBufferSize, // NumBytes
257 NULL, // PrivateData NULL
258 FvbHandle, // Fvb Handle
259 FtwBuffer // write buffer
260 );
261
262 FreePool (FtwBuffer);
263 return Status;
264 }