]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
Update the copyright notice format
[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. All rights reserved.<BR>
7 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 EFI_FVB_ATTRIBUTES_2 Attributes;
48
49 *FvbHandle = NULL;
50 //
51 // Locate all handles of Fvb protocol
52 //
53 Status = gBS->LocateHandleBuffer (
54 ByProtocol,
55 &gEfiFirmwareVolumeBlockProtocolGuid,
56 NULL,
57 &HandleCount,
58 &HandleBuffer
59 );
60 if (EFI_ERROR (Status)) {
61 return EFI_NOT_FOUND;
62 }
63 //
64 // Get the FVB to access variable store
65 //
66 for (Index = 0; Index < HandleCount; Index += 1) {
67 Status = gBS->HandleProtocol (
68 HandleBuffer[Index],
69 &gEfiFirmwareVolumeBlockProtocolGuid,
70 (VOID **) &Fvb
71 );
72 if (EFI_ERROR (Status)) {
73 Status = EFI_NOT_FOUND;
74 break;
75 }
76
77 Status = Fvb->GetAttributes (Fvb, &Attributes);
78 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
79 continue;
80 }
81 //
82 // Compare the address and select the right one
83 //
84 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
85 if (EFI_ERROR (Status)) {
86 continue;
87 }
88
89 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
90 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
91 *FvbHandle = HandleBuffer[Index];
92 Status = EFI_SUCCESS;
93 break;
94 }
95 }
96
97 FreePool (HandleBuffer);
98 return Status;
99 }
100
101 /**
102 Gets LBA of block and offset by given address.
103
104 This function gets the Logical Block Address (LBA) of firmware
105 volume block containing the given address, and the offset of
106 address on the block.
107
108 @param Address Address which should be contained
109 by returned FVB handle
110 @param Lba Pointer to LBA for output
111 @param Offset Pointer to offset for output
112
113 @retval EFI_SUCCESS LBA and offset successfully returned
114 @retval EFI_NOT_FOUND Fail to find FVB handle by address
115 @retval EFI_ABORTED Fail to find valid LBA and offset
116
117 **/
118 EFI_STATUS
119 GetLbaAndOffsetByAddress (
120 IN EFI_PHYSICAL_ADDRESS Address,
121 OUT EFI_LBA *Lba,
122 OUT UINTN *Offset
123 )
124 {
125 EFI_STATUS Status;
126 EFI_HANDLE FvbHandle;
127 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
128 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
129 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
130 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
131 UINT32 LbaIndex;
132
133 *Lba = (EFI_LBA) (-1);
134 *Offset = 0;
135
136 //
137 // Get the proper FVB
138 //
139 Status = GetFvbHandleByAddress (Address, &FvbHandle);
140 if (EFI_ERROR (Status)) {
141 return Status;
142 }
143
144 Status = gBS->HandleProtocol (
145 FvbHandle,
146 &gEfiFirmwareVolumeBlockProtocolGuid,
147 (VOID **) &Fvb
148 );
149 if (EFI_ERROR (Status)) {
150 return Status;
151 }
152 //
153 // Get the Base Address of FV
154 //
155 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
156 if (EFI_ERROR (Status)) {
157 return Status;
158 }
159
160 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
161
162 //
163 // Get the (LBA, Offset) of Address
164 //
165 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
166 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
167 //
168 // BUGBUG: Assume one FV has one type of BlockLength
169 //
170 FvbMapEntry = &FwVolHeader->BlockMap[0];
171 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
172 if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
173 //
174 // Found the (Lba, Offset)
175 //
176 *Lba = LbaIndex - 1;
177 *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
178 return EFI_SUCCESS;
179 }
180 }
181 }
182 }
183
184 return EFI_ABORTED;
185 }
186
187 /**
188 Writes a buffer to variable storage space, in the working block.
189
190 This function writes a buffer to variable storage space into firmware
191 volume block device. The destination is specified by parameter
192 VariableBase. Fault Tolerant Write protocol is used for writing.
193
194 @param VariableBase Base address of variable to write
195 @param Buffer Point to the data buffer
196 @param BufferSize The number of bytes of the data Buffer
197
198 @retval EFI_SUCCESS The function completed successfully
199 @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol
200 @retval EFI_ABORTED The function could not complete successfully
201
202 **/
203 EFI_STATUS
204 FtwVariableSpace (
205 IN EFI_PHYSICAL_ADDRESS VariableBase,
206 IN UINT8 *Buffer,
207 IN UINTN BufferSize
208 )
209 {
210 EFI_STATUS Status;
211 EFI_HANDLE FvbHandle;
212 EFI_LBA VarLba;
213 UINTN VarOffset;
214 UINT8 *FtwBuffer;
215 UINTN FtwBufferSize;
216 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
217
218 //
219 // Locate fault tolerant write protocol
220 //
221 Status = gBS->LocateProtocol (
222 &gEfiFaultTolerantWriteProtocolGuid,
223 NULL,
224 (VOID **) &FtwProtocol
225 );
226 if (EFI_ERROR (Status)) {
227 return EFI_NOT_FOUND;
228 }
229 //
230 // Locate Fvb handle by address
231 //
232 Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);
233 if (EFI_ERROR (Status)) {
234 return Status;
235 }
236 //
237 // Get LBA and Offset by address
238 //
239 Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
240 if (EFI_ERROR (Status)) {
241 return EFI_ABORTED;
242 }
243 //
244 // Prepare for the variable data
245 //
246 FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
247 FtwBuffer = AllocateRuntimePool (FtwBufferSize);
248 if (FtwBuffer == NULL) {
249 return EFI_OUT_OF_RESOURCES;
250 }
251
252 SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);
253 CopyMem (FtwBuffer, Buffer, BufferSize);
254
255 //
256 // FTW write record
257 //
258 Status = FtwProtocol->Write (
259 FtwProtocol,
260 VarLba, // LBA
261 VarOffset, // Offset
262 FtwBufferSize, // NumBytes
263 NULL, // PrivateData NULL
264 FvbHandle, // Fvb Handle
265 FtwBuffer // write buffer
266 );
267
268 FreePool (FtwBuffer);
269 return Status;
270 }