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