]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
MdeModulePkg/FaultTolerantWrite: Consume Variable Flash Info
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / UpdateWorkingBlock.c
CommitLineData
85e923a5
LG
1/** @file\r
2\r
3 Internal functions to operate Working Block Space.\r
4\r
d1102dba 5Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
85e923a5
LG
7\r
8**/\r
9\r
85e923a5
LG
10#include "FaultTolerantWrite.h"\r
11\r
1436aea4 12EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = { ZERO_GUID, 0, 0, 0, 0, { 0, 0, 0 }, 0 };\r
85e923a5 13\r
05cfd5f2
SZ
14/**\r
15 Initialize a local work space header.\r
85e923a5 16\r
05cfd5f2
SZ
17 Since Signature and WriteQueueSize have been known, Crc can be calculated out,\r
18 then the work space header will be fixed.\r
8db39c60
MK
19\r
20 @param[in] WorkSpaceLength Length in bytes of the FTW workspace area.\r
21\r
85e923a5 22**/\r
05cfd5f2
SZ
23VOID\r
24InitializeLocalWorkSpaceHeader (\r
8db39c60 25 IN UINTN WorkSpaceLength\r
85e923a5
LG
26 )\r
27{\r
85e923a5 28 //\r
3e02ebb2 29 // Check signature with gEdkiiWorkingBlockSignatureGuid.\r
85e923a5 30 //\r
3e02ebb2 31 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {\r
05cfd5f2
SZ
32 //\r
33 // The local work space header has been initialized.\r
34 //\r
35 return;\r
85e923a5 36 }\r
05cfd5f2
SZ
37\r
38 SetMem (\r
39 &mWorkingBlockHeader,\r
40 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
41 FTW_ERASED_BYTE\r
42 );\r
43\r
85e923a5 44 //\r
3e02ebb2 45 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.\r
85e923a5
LG
46 //\r
47 CopyMem (\r
05cfd5f2 48 &mWorkingBlockHeader.Signature,\r
3e02ebb2 49 &gEdkiiWorkingBlockSignatureGuid,\r
05cfd5f2 50 sizeof (EFI_GUID)\r
85e923a5 51 );\r
8db39c60 52 mWorkingBlockHeader.WriteQueueSize = WorkSpaceLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
85e923a5
LG
53\r
54 //\r
05cfd5f2 55 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.\r
85e923a5 56 //\r
85e923a5
LG
57\r
58 //\r
59 // Calculate the Crc of woking block header\r
60 //\r
1436aea4
MK
61 mWorkingBlockHeader.Crc = FtwCalculateCrc32 (\r
62 &mWorkingBlockHeader,\r
63 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
64 );\r
05cfd5f2 65\r
1436aea4
MK
66 mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;\r
67 mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;\r
05cfd5f2
SZ
68}\r
69\r
70/**\r
71 Check to see if it is a valid work space.\r
72\r
73\r
74 @param WorkingHeader Pointer of working block header\r
75\r
76 @retval TRUE The work space is valid.\r
77 @retval FALSE The work space is invalid.\r
78\r
79**/\r
80BOOLEAN\r
81IsValidWorkSpace (\r
1436aea4 82 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
05cfd5f2
SZ
83 )\r
84{\r
85 if (WorkingHeader == NULL) {\r
85e923a5
LG
86 return FALSE;\r
87 }\r
88\r
05cfd5f2
SZ
89 if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {\r
90 return TRUE;\r
85e923a5
LG
91 }\r
92\r
87000d77 93 DEBUG ((DEBUG_INFO, "Ftw: Work block header check mismatch\n"));\r
05cfd5f2 94 return FALSE;\r
85e923a5
LG
95}\r
96\r
97/**\r
98 Initialize a work space when there is no work space.\r
99\r
100 @param WorkingHeader Pointer of working block header\r
101\r
102 @retval EFI_SUCCESS The function completed successfully\r
103 @retval EFI_ABORTED The function could not complete successfully.\r
104\r
105**/\r
106EFI_STATUS\r
107InitWorkSpaceHeader (\r
1436aea4 108 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
85e923a5
LG
109 )\r
110{\r
85e923a5
LG
111 if (WorkingHeader == NULL) {\r
112 return EFI_INVALID_PARAMETER;\r
113 }\r
85e923a5 114\r
05cfd5f2 115 CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
85e923a5
LG
116\r
117 return EFI_SUCCESS;\r
118}\r
119\r
0d3edd9d
SZ
120/**\r
121 Read work space data from work block or spare block.\r
122\r
0d3edd9d
SZ
123 @param FvBlock FVB Protocol interface to access the block.\r
124 @param BlockSize The size of the block.\r
125 @param Lba Lba of the block.\r
126 @param Offset The offset within the block.\r
127 @param Length The number of bytes to read from the block.\r
128 @param Buffer The data is read.\r
129\r
130 @retval EFI_SUCCESS The function completed successfully.\r
131 @retval EFI_ABORTED The function could not complete successfully.\r
132\r
133**/\r
134EFI_STATUS\r
135ReadWorkSpaceData (\r
1436aea4
MK
136 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
137 IN UINTN BlockSize,\r
138 IN EFI_LBA Lba,\r
139 IN UINTN Offset,\r
140 IN UINTN Length,\r
141 OUT UINT8 *Buffer\r
0d3edd9d
SZ
142 )\r
143{\r
1436aea4
MK
144 EFI_STATUS Status;\r
145 UINT8 *Ptr;\r
146 UINTN MyLength;\r
0d3edd9d
SZ
147\r
148 //\r
149 // Calculate the real Offset and Lba to write.\r
150 //\r
151 while (Offset >= BlockSize) {\r
152 Offset -= BlockSize;\r
153 Lba++;\r
154 }\r
155\r
156 Ptr = Buffer;\r
157 while (Length > 0) {\r
158 if ((Offset + Length) > BlockSize) {\r
159 MyLength = BlockSize - Offset;\r
160 } else {\r
161 MyLength = Length;\r
162 }\r
163\r
164 Status = FvBlock->Read (\r
165 FvBlock,\r
166 Lba,\r
167 Offset,\r
168 &MyLength,\r
169 Ptr\r
170 );\r
171 if (EFI_ERROR (Status)) {\r
172 return EFI_ABORTED;\r
173 }\r
1436aea4
MK
174\r
175 Offset = 0;\r
0d3edd9d 176 Length -= MyLength;\r
1436aea4 177 Ptr += MyLength;\r
0d3edd9d
SZ
178 Lba++;\r
179 }\r
180\r
181 return EFI_SUCCESS;\r
182}\r
183\r
184/**\r
185 Write work space data to work block.\r
186\r
187 @param FvBlock FVB Protocol interface to access the block.\r
188 @param BlockSize The size of the block.\r
189 @param Lba Lba of the block.\r
190 @param Offset The offset within the block to place the data.\r
191 @param Length The number of bytes to write to the block.\r
192 @param Buffer The data to write.\r
193\r
194 @retval EFI_SUCCESS The function completed successfully.\r
195 @retval EFI_ABORTED The function could not complete successfully.\r
196\r
197**/\r
198EFI_STATUS\r
199WriteWorkSpaceData (\r
1436aea4
MK
200 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
201 IN UINTN BlockSize,\r
202 IN EFI_LBA Lba,\r
203 IN UINTN Offset,\r
204 IN UINTN Length,\r
205 IN UINT8 *Buffer\r
0d3edd9d
SZ
206 )\r
207{\r
1436aea4
MK
208 EFI_STATUS Status;\r
209 UINT8 *Ptr;\r
210 UINTN MyLength;\r
0d3edd9d
SZ
211\r
212 //\r
213 // Calculate the real Offset and Lba to write.\r
214 //\r
215 while (Offset >= BlockSize) {\r
216 Offset -= BlockSize;\r
217 Lba++;\r
218 }\r
219\r
220 Ptr = Buffer;\r
221 while (Length > 0) {\r
222 if ((Offset + Length) > BlockSize) {\r
223 MyLength = BlockSize - Offset;\r
224 } else {\r
225 MyLength = Length;\r
226 }\r
227\r
228 Status = FvBlock->Write (\r
229 FvBlock,\r
230 Lba,\r
231 Offset,\r
232 &MyLength,\r
233 Ptr\r
234 );\r
235 if (EFI_ERROR (Status)) {\r
236 return EFI_ABORTED;\r
237 }\r
1436aea4
MK
238\r
239 Offset = 0;\r
0d3edd9d 240 Length -= MyLength;\r
1436aea4 241 Ptr += MyLength;\r
0d3edd9d
SZ
242 Lba++;\r
243 }\r
1436aea4 244\r
0d3edd9d
SZ
245 return EFI_SUCCESS;\r
246}\r
247\r
85e923a5
LG
248/**\r
249 Read from working block to refresh the work space in memory.\r
250\r
251 @param FtwDevice Point to private data of FTW driver\r
252\r
253 @retval EFI_SUCCESS The function completed successfully\r
254 @retval EFI_ABORTED The function could not complete successfully.\r
255\r
256**/\r
257EFI_STATUS\r
258WorkSpaceRefresh (\r
259 IN EFI_FTW_DEVICE *FtwDevice\r
260 )\r
261{\r
1436aea4
MK
262 EFI_STATUS Status;\r
263 UINTN RemainingSpaceSize;\r
85e923a5
LG
264\r
265 //\r
266 // Initialize WorkSpace as FTW_ERASED_BYTE\r
267 //\r
268 SetMem (\r
269 FtwDevice->FtwWorkSpace,\r
270 FtwDevice->FtwWorkSpaceSize,\r
271 FTW_ERASED_BYTE\r
272 );\r
273\r
274 //\r
275 // Read from working block\r
276 //\r
0d3edd9d
SZ
277 Status = ReadWorkSpaceData (\r
278 FtwDevice->FtwFvBlock,\r
279 FtwDevice->WorkBlockSize,\r
280 FtwDevice->FtwWorkSpaceLba,\r
281 FtwDevice->FtwWorkSpaceBase,\r
282 FtwDevice->FtwWorkSpaceSize,\r
283 FtwDevice->FtwWorkSpace\r
284 );\r
85e923a5
LG
285 if (EFI_ERROR (Status)) {\r
286 return EFI_ABORTED;\r
287 }\r
1436aea4 288\r
85e923a5
LG
289 //\r
290 // Refresh the FtwLastWriteHeader\r
291 //\r
292 Status = FtwGetLastWriteHeader (\r
1436aea4
MK
293 FtwDevice->FtwWorkSpaceHeader,\r
294 FtwDevice->FtwWorkSpaceSize,\r
295 &FtwDevice->FtwLastWriteHeader\r
296 );\r
297 RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN)FtwDevice->FtwLastWriteHeader - (UINTN)FtwDevice->FtwWorkSpace);\r
87000d77 298 DEBUG ((DEBUG_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));\r
d379cbc7
SZ
299 //\r
300 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain\r
301 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header\r
302 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),\r
303 // it needs to reclaim work space.\r
304 //\r
1436aea4 305 if (EFI_ERROR (Status) || (RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD))) {\r
85e923a5
LG
306 //\r
307 // reclaim work space in working block.\r
308 //\r
309 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
310 if (EFI_ERROR (Status)) {\r
87000d77 311 DEBUG ((DEBUG_ERROR, "Ftw: Reclaim workspace - %r\n", Status));\r
85e923a5
LG
312 return EFI_ABORTED;\r
313 }\r
1436aea4 314\r
85e923a5
LG
315 //\r
316 // Read from working block again\r
317 //\r
0d3edd9d
SZ
318 Status = ReadWorkSpaceData (\r
319 FtwDevice->FtwFvBlock,\r
320 FtwDevice->WorkBlockSize,\r
321 FtwDevice->FtwWorkSpaceLba,\r
322 FtwDevice->FtwWorkSpaceBase,\r
323 FtwDevice->FtwWorkSpaceSize,\r
324 FtwDevice->FtwWorkSpace\r
325 );\r
85e923a5
LG
326 if (EFI_ERROR (Status)) {\r
327 return EFI_ABORTED;\r
328 }\r
329\r
330 Status = FtwGetLastWriteHeader (\r
1436aea4
MK
331 FtwDevice->FtwWorkSpaceHeader,\r
332 FtwDevice->FtwWorkSpaceSize,\r
333 &FtwDevice->FtwLastWriteHeader\r
334 );\r
d26c7e82
SZ
335 if (EFI_ERROR (Status)) {\r
336 return EFI_ABORTED;\r
337 }\r
85e923a5 338 }\r
1436aea4 339\r
85e923a5
LG
340 //\r
341 // Refresh the FtwLastWriteRecord\r
342 //\r
343 Status = FtwGetLastWriteRecord (\r
1436aea4
MK
344 FtwDevice->FtwLastWriteHeader,\r
345 &FtwDevice->FtwLastWriteRecord\r
346 );\r
85e923a5
LG
347 if (EFI_ERROR (Status)) {\r
348 return EFI_ABORTED;\r
349 }\r
350\r
351 return EFI_SUCCESS;\r
352}\r
353\r
354/**\r
355 Reclaim the work space on the working block.\r
356\r
357 @param FtwDevice Point to private data of FTW driver\r
358 @param PreserveRecord Whether to preserve the working record is needed\r
359\r
360 @retval EFI_SUCCESS The function completed successfully\r
361 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
362 @retval EFI_ABORTED The function could not complete successfully\r
363\r
364**/\r
365EFI_STATUS\r
366FtwReclaimWorkSpace (\r
367 IN EFI_FTW_DEVICE *FtwDevice,\r
368 IN BOOLEAN PreserveRecord\r
369 )\r
370{\r
1436aea4
MK
371 EFI_STATUS Status;\r
372 UINTN Length;\r
373 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
374 UINT8 *TempBuffer;\r
375 UINTN TempBufferSize;\r
376 UINTN SpareBufferSize;\r
377 UINT8 *SpareBuffer;\r
378 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
379 UINTN Index;\r
380 UINT8 *Ptr;\r
381 EFI_LBA WorkSpaceLbaOffset;\r
85e923a5 382\r
87000d77 383 DEBUG ((DEBUG_INFO, "Ftw: start to reclaim work space\n"));\r
85e923a5 384\r
d26c7e82
SZ
385 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
386\r
85e923a5
LG
387 //\r
388 // Read all original data from working block to a memory buffer\r
389 //\r
0d3edd9d 390 TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;\r
85e923a5
LG
391 TempBuffer = AllocateZeroPool (TempBufferSize);\r
392 if (TempBuffer == NULL) {\r
393 return EFI_OUT_OF_RESOURCES;\r
394 }\r
395\r
396 Ptr = TempBuffer;\r
0d3edd9d
SZ
397 for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {\r
398 Length = FtwDevice->WorkBlockSize;\r
85e923a5 399 Status = FtwDevice->FtwFvBlock->Read (\r
1436aea4
MK
400 FtwDevice->FtwFvBlock,\r
401 FtwDevice->FtwWorkBlockLba + Index,\r
402 0,\r
403 &Length,\r
404 Ptr\r
405 );\r
85e923a5
LG
406 if (EFI_ERROR (Status)) {\r
407 FreePool (TempBuffer);\r
408 return EFI_ABORTED;\r
409 }\r
410\r
411 Ptr += Length;\r
412 }\r
1436aea4 413\r
85e923a5
LG
414 //\r
415 // Clean up the workspace, remove all the completed records.\r
416 //\r
417 Ptr = TempBuffer +\r
1436aea4 418 (UINTN)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +\r
85e923a5
LG
419 FtwDevice->FtwWorkSpaceBase;\r
420\r
421 //\r
422 // Clear the content of buffer that will save the new work space data\r
423 //\r
424 SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);\r
425\r
426 //\r
427 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
428 //\r
429 CopyMem (\r
430 Ptr,\r
431 FtwDevice->FtwWorkSpaceHeader,\r
432 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
433 );\r
434 if (PreserveRecord) {\r
435 //\r
436 // Get the last record following the header,\r
437 //\r
438 Status = FtwGetLastWriteHeader (\r
439 FtwDevice->FtwWorkSpaceHeader,\r
440 FtwDevice->FtwWorkSpaceSize,\r
441 &FtwDevice->FtwLastWriteHeader\r
442 );\r
443 Header = FtwDevice->FtwLastWriteHeader;\r
8dc8879a 444 if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {\r
85e923a5
LG
445 CopyMem (\r
446 Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
447 FtwDevice->FtwLastWriteHeader,\r
3e02ebb2 448 FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
85e923a5
LG
449 );\r
450 }\r
451 }\r
452\r
453 CopyMem (\r
454 FtwDevice->FtwWorkSpace,\r
455 Ptr,\r
456 FtwDevice->FtwWorkSpaceSize\r
457 );\r
458\r
459 FtwGetLastWriteHeader (\r
460 FtwDevice->FtwWorkSpaceHeader,\r
461 FtwDevice->FtwWorkSpaceSize,\r
462 &FtwDevice->FtwLastWriteHeader\r
463 );\r
464\r
d26c7e82
SZ
465 FtwGetLastWriteRecord (\r
466 FtwDevice->FtwLastWriteHeader,\r
467 &FtwDevice->FtwLastWriteRecord\r
468 );\r
469\r
85e923a5
LG
470 //\r
471 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
472 //\r
1436aea4
MK
473 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(TempBuffer +\r
474 (UINTN)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +\r
475 FtwDevice->FtwWorkSpaceBase);\r
85e923a5
LG
476 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
477 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
478\r
479 //\r
480 // Try to keep the content of spare block\r
481 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
482 //\r
483 SpareBufferSize = FtwDevice->SpareAreaLength;\r
484 SpareBuffer = AllocatePool (SpareBufferSize);\r
485 if (SpareBuffer == NULL) {\r
486 FreePool (TempBuffer);\r
487 return EFI_OUT_OF_RESOURCES;\r
488 }\r
489\r
490 Ptr = SpareBuffer;\r
491 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
0d3edd9d 492 Length = FtwDevice->SpareBlockSize;\r
85e923a5
LG
493 Status = FtwDevice->FtwBackupFvb->Read (\r
494 FtwDevice->FtwBackupFvb,\r
495 FtwDevice->FtwSpareLba + Index,\r
496 0,\r
497 &Length,\r
498 Ptr\r
499 );\r
500 if (EFI_ERROR (Status)) {\r
501 FreePool (TempBuffer);\r
502 FreePool (SpareBuffer);\r
503 return EFI_ABORTED;\r
504 }\r
505\r
506 Ptr += Length;\r
507 }\r
1436aea4 508\r
85e923a5
LG
509 //\r
510 // Write the memory buffer to spare block\r
511 //\r
1436aea4 512 Status = FtwEraseSpareBlock (FtwDevice);\r
de2d7497
SZ
513 if (EFI_ERROR (Status)) {\r
514 FreePool (TempBuffer);\r
515 FreePool (SpareBuffer);\r
516 return EFI_ABORTED;\r
517 }\r
1436aea4
MK
518\r
519 Ptr = TempBuffer;\r
0d3edd9d
SZ
520 for (Index = 0; TempBufferSize > 0; Index += 1) {\r
521 if (TempBufferSize > FtwDevice->SpareBlockSize) {\r
522 Length = FtwDevice->SpareBlockSize;\r
523 } else {\r
524 Length = TempBufferSize;\r
525 }\r
1436aea4 526\r
85e923a5 527 Status = FtwDevice->FtwBackupFvb->Write (\r
1436aea4
MK
528 FtwDevice->FtwBackupFvb,\r
529 FtwDevice->FtwSpareLba + Index,\r
530 0,\r
531 &Length,\r
532 Ptr\r
533 );\r
85e923a5
LG
534 if (EFI_ERROR (Status)) {\r
535 FreePool (TempBuffer);\r
536 FreePool (SpareBuffer);\r
537 return EFI_ABORTED;\r
538 }\r
539\r
1436aea4 540 Ptr += Length;\r
0d3edd9d 541 TempBufferSize -= Length;\r
85e923a5 542 }\r
1436aea4 543\r
85e923a5
LG
544 //\r
545 // Free TempBuffer\r
546 //\r
547 FreePool (TempBuffer);\r
548\r
549 //\r
550 // Set the WorkingBlockValid in spare block\r
551 //\r
552 Status = FtwUpdateFvState (\r
1436aea4
MK
553 FtwDevice->FtwBackupFvb,\r
554 FtwDevice->SpareBlockSize,\r
555 FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,\r
556 FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),\r
557 WORKING_BLOCK_VALID\r
558 );\r
85e923a5
LG
559 if (EFI_ERROR (Status)) {\r
560 FreePool (SpareBuffer);\r
561 return EFI_ABORTED;\r
562 }\r
1436aea4 563\r
85e923a5
LG
564 //\r
565 // Before erase the working block, set WorkingBlockInvalid in working block.\r
566 //\r
567 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
568 // WorkingBlockInvalid);\r
569 //\r
570 Status = FtwUpdateFvState (\r
1436aea4
MK
571 FtwDevice->FtwFvBlock,\r
572 FtwDevice->WorkBlockSize,\r
573 FtwDevice->FtwWorkSpaceLba,\r
574 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
575 WORKING_BLOCK_INVALID\r
576 );\r
85e923a5
LG
577 if (EFI_ERROR (Status)) {\r
578 FreePool (SpareBuffer);\r
579 return EFI_ABORTED;\r
580 }\r
581\r
582 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;\r
583\r
584 //\r
585 // Write the spare block to working block\r
586 //\r
587 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
588 if (EFI_ERROR (Status)) {\r
589 FreePool (SpareBuffer);\r
590 return Status;\r
591 }\r
1436aea4 592\r
85e923a5
LG
593 //\r
594 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
595 //\r
1436aea4 596 Status = FtwEraseSpareBlock (FtwDevice);\r
de2d7497
SZ
597 if (EFI_ERROR (Status)) {\r
598 FreePool (SpareBuffer);\r
599 return EFI_ABORTED;\r
600 }\r
1436aea4
MK
601\r
602 Ptr = SpareBuffer;\r
85e923a5 603 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
0d3edd9d 604 Length = FtwDevice->SpareBlockSize;\r
85e923a5
LG
605 Status = FtwDevice->FtwBackupFvb->Write (\r
606 FtwDevice->FtwBackupFvb,\r
607 FtwDevice->FtwSpareLba + Index,\r
608 0,\r
609 &Length,\r
610 Ptr\r
611 );\r
612 if (EFI_ERROR (Status)) {\r
613 FreePool (SpareBuffer);\r
614 return EFI_ABORTED;\r
615 }\r
616\r
617 Ptr += Length;\r
618 }\r
619\r
620 FreePool (SpareBuffer);\r
621\r
87000d77 622 DEBUG ((DEBUG_INFO, "Ftw: reclaim work space successfully\n"));\r
85e923a5
LG
623\r
624 return EFI_SUCCESS;\r
625}\r