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