]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
Clean up FaultTolerantWriteDxe to remove the duplicated definition.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / FtwWorkSpace.c
CommitLineData
6cc9ca32 1/** @file\r
d7dec593 2\r
6cc9ca32
LG
3 Internal functions to operate Working Block Space.\r
4\r
5Copyright (c) 2006 - 2008, Intel Corporation \r
d7dec593 6All rights reserved. This program and the accompanying materials \r
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
6cc9ca32 14**/\r
d7dec593 15\r
16\r
e87a334f 17#include "FtwLite.h"\r
d7dec593 18\r
6aab8214 19/**\r
20 Check to see if it is a valid work space.\r
d7dec593 21\r
d7dec593 22\r
6aab8214 23 @param WorkingHeader Pointer of working block header\r
d7dec593 24\r
6aab8214 25 @retval EFI_SUCCESS The function completed successfully\r
26 @retval EFI_ABORTED The function could not complete successfully.\r
d7dec593 27\r
6aab8214 28**/\r
29BOOLEAN\r
30IsValidWorkSpace (\r
31 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
32 )\r
d7dec593 33{\r
34 EFI_STATUS Status;\r
35 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;\r
36\r
37 ASSERT (WorkingHeader != NULL);\r
38 if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {\r
276a49b6 39 DEBUG ((EFI_D_ERROR, "FtwLite: Work block header valid bit check error\n"));\r
d7dec593 40 return FALSE;\r
41 }\r
42 //\r
43 // Check signature with gEfiSystemNvDataFvGuid\r
44 //\r
45 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
276a49b6 46 DEBUG ((EFI_D_ERROR, "FtwLite: Work block header signature check error\n"));\r
d7dec593 47 return FALSE;\r
48 }\r
49 //\r
50 // Check the CRC of header\r
51 //\r
52 CopyMem (\r
53 &WorkingBlockHeader,\r
54 WorkingHeader,\r
55 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
56 );\r
57\r
58 //\r
59 // Filter out the Crc and State fields\r
60 //\r
61 SetMem (\r
62 &WorkingBlockHeader.Crc,\r
63 sizeof (UINT32),\r
64 FTW_ERASED_BYTE\r
65 );\r
66 WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;\r
67 WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
68\r
69 //\r
70 // Calculate the Crc of woking block header\r
71 //\r
72 Status = gBS->CalculateCrc32 (\r
73 (UINT8 *) &WorkingBlockHeader,\r
74 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
75 &WorkingBlockHeader.Crc\r
76 );\r
77 ASSERT_EFI_ERROR (Status);\r
78\r
79 if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {\r
276a49b6 80 DEBUG ((EFI_D_ERROR, "FtwLite: Work block header CRC check error\n"));\r
d7dec593 81 return FALSE;\r
82 }\r
83\r
84 return TRUE;\r
85}\r
86\r
6aab8214 87/**\r
88 Initialize a work space when there is no work space.\r
d7dec593 89\r
d7dec593 90\r
6aab8214 91 @param WorkingHeader Pointer of working block header\r
d7dec593 92\r
6aab8214 93 @retval EFI_SUCCESS The function completed successfully\r
94 @retval EFI_ABORTED The function could not complete successfully.\r
d7dec593 95\r
6aab8214 96**/\r
97EFI_STATUS\r
98InitWorkSpaceHeader (\r
99 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
100 )\r
d7dec593 101{\r
102 EFI_STATUS Status;\r
103\r
104 ASSERT (WorkingHeader != NULL);\r
105\r
106 //\r
107 // Here using gEfiSystemNvDataFvGuid as the signature.\r
108 //\r
109 CopyMem (\r
110 &WorkingHeader->Signature,\r
111 &gEfiSystemNvDataFvGuid,\r
112 sizeof (EFI_GUID)\r
113 );\r
5944a83b 114 WorkingHeader->WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
d7dec593 115\r
116 //\r
117 // Crc is calculated with all the fields except Crc and STATE\r
118 //\r
119 WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
120 WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
121 SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);\r
122\r
123 //\r
124 // Calculate the CRC value\r
125 //\r
126 Status = gBS->CalculateCrc32 (\r
127 (UINT8 *) WorkingHeader,\r
128 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
129 &WorkingHeader->Crc\r
130 );\r
131 ASSERT_EFI_ERROR (Status);\r
132\r
133 //\r
134 // Restore the WorkingBlockValid flag to VALID state\r
135 //\r
136 WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;\r
137 WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
138\r
139 return EFI_SUCCESS;\r
140}\r
141\r
6aab8214 142/**\r
143 Update a bit of state on a block device. The location of the bit is\r
144 calculated by the (Lba, Offset, bit). Here bit is determined by the\r
145 the name of a certain bit.\r
146\r
147\r
148 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock\r
149 @param Lba Lba of a block\r
150 @param Offset Offset on the Lba\r
151 @param NewBit New value that will override the old value if it can be change\r
152\r
153 @retval EFI_SUCCESS A state bit has been updated successfully\r
154 @retval Others Access block device error.\r
155 Notes:\r
156 Assume all bits of State are inside the same BYTE.\r
157 @retval EFI_ABORTED Read block fail\r
158\r
159**/\r
d7dec593 160EFI_STATUS\r
161FtwUpdateFvState (\r
162 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
163 IN EFI_LBA Lba,\r
164 IN UINTN Offset,\r
165 IN UINT8 NewBit\r
166 )\r
d7dec593 167{\r
168 EFI_STATUS Status;\r
169 UINT8 State;\r
170 UINTN Length;\r
171\r
172 //\r
173 // Read state from device, assume State is only one byte.\r
174 //\r
175 Length = sizeof (UINT8);\r
176 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);\r
177 if (EFI_ERROR (Status)) {\r
178 return EFI_ABORTED;\r
179 }\r
180\r
181 State ^= FTW_POLARITY_REVERT;\r
182 State = (UINT8) (State | NewBit);\r
183 State ^= FTW_POLARITY_REVERT;\r
184\r
185 //\r
186 // Write state back to device\r
187 //\r
188 Length = sizeof (UINT8);\r
189 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);\r
190\r
191 return Status;\r
192}\r
193\r
6aab8214 194/**\r
195 Get the last Write record pointer.\r
196 The last record is the record whose 'complete' state hasn't been set.\r
197 After all, this header may be a EMPTY header entry for next Allocate.\r
198\r
199\r
200 @param FtwLiteDevice Private data of this driver\r
201 @param FtwLastRecord Pointer to retrieve the last write record\r
202\r
203 @retval EFI_SUCCESS Get the last write record successfully\r
204 @retval EFI_ABORTED The FTW work space is damaged\r
205\r
206**/\r
d7dec593 207EFI_STATUS\r
208FtwGetLastRecord (\r
209 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
210 OUT EFI_FTW_LITE_RECORD **FtwLastRecord\r
211 )\r
d7dec593 212{\r
213 EFI_FTW_LITE_RECORD *Record;\r
214\r
e11ae3a5 215 *FtwLastRecord = NULL;\r
d7dec593 216 Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);\r
217 while (Record->WriteCompleted == FTW_VALID_STATE) {\r
218 //\r
219 // If Offset exceed the FTW work space boudary, return error.\r
220 //\r
221 if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {\r
222 return EFI_ABORTED;\r
223 }\r
224\r
225 Record++;\r
226 }\r
227 //\r
228 // Last write record is found\r
229 //\r
230 *FtwLastRecord = Record;\r
231 return EFI_SUCCESS;\r
232}\r
233\r
6aab8214 234/**\r
235 Read from working block to refresh the work space in memory.\r
d7dec593 236\r
d7dec593 237\r
6aab8214 238 @param FtwLiteDevice Point to private data of FTW driver\r
d7dec593 239\r
6aab8214 240 @retval EFI_SUCCESS The function completed successfully\r
241 @retval EFI_ABORTED The function could not complete successfully.\r
d7dec593 242\r
6aab8214 243**/\r
244EFI_STATUS\r
245WorkSpaceRefresh (\r
246 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
247 )\r
d7dec593 248{\r
249 EFI_STATUS Status;\r
250 UINTN Length;\r
251 UINTN Offset;\r
252 EFI_FTW_LITE_RECORD *Record;\r
253\r
254 //\r
255 // Initialize WorkSpace as FTW_ERASED_BYTE\r
256 //\r
257 SetMem (\r
258 FtwLiteDevice->FtwWorkSpace,\r
259 FtwLiteDevice->FtwWorkSpaceSize,\r
260 FTW_ERASED_BYTE\r
261 );\r
262\r
263 //\r
264 // Read from working block\r
265 //\r
266 Length = FtwLiteDevice->FtwWorkSpaceSize;\r
267 Status = FtwLiteDevice->FtwFvBlock->Read (\r
268 FtwLiteDevice->FtwFvBlock,\r
269 FtwLiteDevice->FtwWorkSpaceLba,\r
270 FtwLiteDevice->FtwWorkSpaceBase,\r
271 &Length,\r
272 FtwLiteDevice->FtwWorkSpace\r
273 );\r
274 if (EFI_ERROR (Status)) {\r
275 return EFI_ABORTED;\r
276 }\r
277 //\r
278 // Refresh the FtwLastRecord\r
279 //\r
280 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
281\r
282 Record = FtwLiteDevice->FtwLastRecord;\r
283 Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;\r
284\r
285 //\r
da770255 286 // If work space has error or Record is out of the workspace limit, THEN\r
d7dec593 287 // call reclaim.\r
288 //\r
5944a83b 289 if (EFI_ERROR (Status) || (Offset + FTW_LITE_RECORD_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {\r
d7dec593 290 //\r
291 // reclaim work space in working block.\r
292 //\r
e11ae3a5 293 Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);\r
d7dec593 294 if (EFI_ERROR (Status)) {\r
276a49b6 295 DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim workspace - %r\n", Status));\r
d7dec593 296 return EFI_ABORTED;\r
297 }\r
298 }\r
299\r
300 return EFI_SUCCESS;\r
301}\r
302\r
6aab8214 303/**\r
304 Reclaim the work space on the working block.\r
d7dec593 305\r
d7dec593 306\r
9920ae74 307 @param FtwLiteDevice Point to private data of FTW driver\r
308 @param PreserveRecord Whether get the last record or not\r
d7dec593 309\r
9920ae74 310 @retval EFI_SUCCESS The function completed successfully\r
311 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
312 @retval EFI_ABORTED The function could not complete successfully\r
d7dec593 313\r
6aab8214 314**/\r
315EFI_STATUS\r
316FtwReclaimWorkSpace (\r
e11ae3a5
LG
317 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
318 IN BOOLEAN PreserveRecord\r
6aab8214 319 )\r
d7dec593 320{\r
321 EFI_STATUS Status;\r
322 UINT8 *TempBuffer;\r
323 UINTN TempBufferSize;\r
324 UINT8 *Ptr;\r
325 UINTN Length;\r
326 UINTN Index;\r
327 UINTN SpareBufferSize;\r
328 UINT8 *SpareBuffer;\r
329 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
e11ae3a5 330 EFI_FTW_LITE_RECORD *Record;\r
d7dec593 331\r
276a49b6 332 DEBUG ((EFI_D_ERROR, "FtwLite: start to reclaim work space\n"));\r
d7dec593 333\r
334 //\r
335 // Read all original data from working block to a memory buffer\r
336 //\r
337 TempBufferSize = FtwLiteDevice->SpareAreaLength;\r
338 TempBuffer = AllocateZeroPool (TempBufferSize);\r
e11ae3a5 339 if (TempBuffer == NULL) {\r
d7dec593 340 return EFI_OUT_OF_RESOURCES;\r
341 }\r
342\r
343 Ptr = TempBuffer;\r
344 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
276a49b6 345 Length = FtwLiteDevice->BlockSize;\r
d7dec593 346 Status = FtwLiteDevice->FtwFvBlock->Read (\r
347 FtwLiteDevice->FtwFvBlock,\r
348 FtwLiteDevice->FtwWorkBlockLba + Index,\r
349 0,\r
350 &Length,\r
351 Ptr\r
352 );\r
353 if (EFI_ERROR (Status)) {\r
354 FreePool (TempBuffer);\r
355 return EFI_ABORTED;\r
356 }\r
357\r
358 Ptr += Length;\r
359 }\r
360 //\r
361 // Clean up the workspace, remove all the completed records.\r
362 //\r
363 Ptr = TempBuffer +\r
364 ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *\r
276a49b6 365 FtwLiteDevice->BlockSize + FtwLiteDevice->FtwWorkSpaceBase;\r
d7dec593 366\r
e11ae3a5
LG
367 //\r
368 // Clear the content of buffer that will save the new work space data\r
369 //\r
370 SetMem (Ptr, FtwLiteDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);\r
371\r
372 //\r
373 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
374 //\r
375 CopyMem (\r
376 Ptr,\r
377 FtwLiteDevice->FtwWorkSpaceHeader,\r
378 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
379 );\r
380 if (PreserveRecord) {\r
381 //\r
382 // Get the last record\r
383 //\r
384 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
385 Record = FtwLiteDevice->FtwLastRecord;\r
386 if (!EFI_ERROR (Status) &&\r
387 Record != NULL &&\r
388 Record->WriteAllocated == FTW_VALID_STATE &&\r
389 Record->WriteCompleted != FTW_VALID_STATE) {\r
390 CopyMem (\r
391 (UINT8 *) Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
392 Record,\r
5944a83b 393 FTW_LITE_RECORD_SIZE\r
e11ae3a5
LG
394 );\r
395 }\r
396 }\r
d7dec593 397\r
398 CopyMem (\r
399 FtwLiteDevice->FtwWorkSpace,\r
400 Ptr,\r
401 FtwLiteDevice->FtwWorkSpaceSize\r
402 );\r
403\r
404 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
405\r
406 //\r
407 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
408 //\r
409 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;\r
410 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
411 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
412\r
413 //\r
414 // Try to keep the content of spare block\r
415 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
416 //\r
417 SpareBufferSize = FtwLiteDevice->SpareAreaLength;\r
418 SpareBuffer = AllocatePool (SpareBufferSize);\r
419 if (SpareBuffer == NULL) {\r
420 FreePool (TempBuffer);\r
421 return EFI_OUT_OF_RESOURCES;\r
422 }\r
423\r
424 Ptr = SpareBuffer;\r
425 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
276a49b6 426 Length = FtwLiteDevice->BlockSize;\r
d7dec593 427 Status = FtwLiteDevice->FtwBackupFvb->Read (\r
428 FtwLiteDevice->FtwBackupFvb,\r
429 FtwLiteDevice->FtwSpareLba + Index,\r
430 0,\r
431 &Length,\r
432 Ptr\r
433 );\r
434 if (EFI_ERROR (Status)) {\r
435 FreePool (TempBuffer);\r
436 FreePool (SpareBuffer);\r
437 return EFI_ABORTED;\r
438 }\r
439\r
440 Ptr += Length;\r
441 }\r
442 //\r
443 // Write the memory buffer to spare block\r
444 //\r
445 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
446 Ptr = TempBuffer;\r
447 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
276a49b6 448 Length = FtwLiteDevice->BlockSize;\r
d7dec593 449 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
450 FtwLiteDevice->FtwBackupFvb,\r
451 FtwLiteDevice->FtwSpareLba + Index,\r
452 0,\r
453 &Length,\r
454 Ptr\r
455 );\r
456 if (EFI_ERROR (Status)) {\r
457 FreePool (TempBuffer);\r
458 FreePool (SpareBuffer);\r
459 return EFI_ABORTED;\r
460 }\r
461\r
462 Ptr += Length;\r
463 }\r
464 //\r
465 // Free TempBuffer\r
466 //\r
467 FreePool (TempBuffer);\r
468\r
469 //\r
470 // Write the spare block to working block\r
471 //\r
472 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);\r
473 if (EFI_ERROR (Status)) {\r
474 FreePool (SpareBuffer);\r
475 return Status;\r
476 }\r
477 //\r
478 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
479 //\r
480 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
481 Ptr = SpareBuffer;\r
482 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
276a49b6 483 Length = FtwLiteDevice->BlockSize;\r
d7dec593 484 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
485 FtwLiteDevice->FtwBackupFvb,\r
486 FtwLiteDevice->FtwSpareLba + Index,\r
487 0,\r
488 &Length,\r
489 Ptr\r
490 );\r
491 if (EFI_ERROR (Status)) {\r
492 FreePool (SpareBuffer);\r
493 return EFI_ABORTED;\r
494 }\r
495\r
496 Ptr += Length;\r
497 }\r
498\r
499 FreePool (SpareBuffer);\r
500\r
276a49b6 501 DEBUG ((EFI_D_ERROR, "FtwLite: reclaim work space success\n"));\r
d7dec593 502\r
503 return EFI_SUCCESS;\r
504}\r