3 Internal functions to operate Working Block Space.
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "FaultTolerantWrite.h"
13 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader
= {ZERO_GUID
, 0, 0, 0, 0, {0, 0, 0}, 0};
16 Initialize a local work space header.
18 Since Signature and WriteQueueSize have been known, Crc can be calculated out,
19 then the work space header will be fixed.
22 InitializeLocalWorkSpaceHeader (
27 // Check signature with gEdkiiWorkingBlockSignatureGuid.
29 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, &mWorkingBlockHeader
.Signature
)) {
31 // The local work space header has been initialized.
38 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
43 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
46 &mWorkingBlockHeader
.Signature
,
47 &gEdkiiWorkingBlockSignatureGuid
,
50 mWorkingBlockHeader
.WriteQueueSize
= PcdGet32 (PcdFlashNvStorageFtwWorkingSize
) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
);
53 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
57 // Calculate the Crc of woking block header
59 mWorkingBlockHeader
.Crc
= FtwCalculateCrc32 (&mWorkingBlockHeader
,
60 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
62 mWorkingBlockHeader
.WorkingBlockValid
= FTW_VALID_STATE
;
63 mWorkingBlockHeader
.WorkingBlockInvalid
= FTW_INVALID_STATE
;
67 Check to see if it is a valid work space.
70 @param WorkingHeader Pointer of working block header
72 @retval TRUE The work space is valid.
73 @retval FALSE The work space is invalid.
78 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
81 if (WorkingHeader
== NULL
) {
85 if (CompareMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)) == 0) {
89 DEBUG ((EFI_D_INFO
, "Ftw: Work block header check mismatch\n"));
94 Initialize a work space when there is no work space.
96 @param WorkingHeader Pointer of working block header
98 @retval EFI_SUCCESS The function completed successfully
99 @retval EFI_ABORTED The function could not complete successfully.
103 InitWorkSpaceHeader (
104 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
107 if (WorkingHeader
== NULL
) {
108 return EFI_INVALID_PARAMETER
;
111 CopyMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
117 Read work space data from work block or spare block.
119 @param FvBlock FVB Protocol interface to access the block.
120 @param BlockSize The size of the block.
121 @param Lba Lba of the block.
122 @param Offset The offset within the block.
123 @param Length The number of bytes to read from the block.
124 @param Buffer The data is read.
126 @retval EFI_SUCCESS The function completed successfully.
127 @retval EFI_ABORTED The function could not complete successfully.
132 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
145 // Calculate the real Offset and Lba to write.
147 while (Offset
>= BlockSize
) {
154 if ((Offset
+ Length
) > BlockSize
) {
155 MyLength
= BlockSize
- Offset
;
160 Status
= FvBlock
->Read (
167 if (EFI_ERROR (Status
)) {
180 Write work space data to work block.
182 @param FvBlock FVB Protocol interface to access the block.
183 @param BlockSize The size of the block.
184 @param Lba Lba of the block.
185 @param Offset The offset within the block to place the data.
186 @param Length The number of bytes to write to the block.
187 @param Buffer The data to write.
189 @retval EFI_SUCCESS The function completed successfully.
190 @retval EFI_ABORTED The function could not complete successfully.
195 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
208 // Calculate the real Offset and Lba to write.
210 while (Offset
>= BlockSize
) {
217 if ((Offset
+ Length
) > BlockSize
) {
218 MyLength
= BlockSize
- Offset
;
223 Status
= FvBlock
->Write (
230 if (EFI_ERROR (Status
)) {
242 Read from working block to refresh the work space in memory.
244 @param FtwDevice Point to private data of FTW driver
246 @retval EFI_SUCCESS The function completed successfully
247 @retval EFI_ABORTED The function could not complete successfully.
252 IN EFI_FTW_DEVICE
*FtwDevice
256 UINTN RemainingSpaceSize
;
259 // Initialize WorkSpace as FTW_ERASED_BYTE
262 FtwDevice
->FtwWorkSpace
,
263 FtwDevice
->FtwWorkSpaceSize
,
268 // Read from working block
270 Status
= ReadWorkSpaceData (
271 FtwDevice
->FtwFvBlock
,
272 FtwDevice
->WorkBlockSize
,
273 FtwDevice
->FtwWorkSpaceLba
,
274 FtwDevice
->FtwWorkSpaceBase
,
275 FtwDevice
->FtwWorkSpaceSize
,
276 FtwDevice
->FtwWorkSpace
278 if (EFI_ERROR (Status
)) {
282 // Refresh the FtwLastWriteHeader
284 Status
= FtwGetLastWriteHeader (
285 FtwDevice
->FtwWorkSpaceHeader
,
286 FtwDevice
->FtwWorkSpaceSize
,
287 &FtwDevice
->FtwLastWriteHeader
289 RemainingSpaceSize
= FtwDevice
->FtwWorkSpaceSize
- ((UINTN
) FtwDevice
->FtwLastWriteHeader
- (UINTN
) FtwDevice
->FtwWorkSpace
);
290 DEBUG ((EFI_D_INFO
, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize
));
292 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
293 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
294 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
295 // it needs to reclaim work space.
297 if (EFI_ERROR (Status
) || RemainingSpaceSize
< sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD
)) {
299 // reclaim work space in working block.
301 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
302 if (EFI_ERROR (Status
)) {
303 DEBUG ((EFI_D_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
307 // Read from working block again
309 Status
= ReadWorkSpaceData (
310 FtwDevice
->FtwFvBlock
,
311 FtwDevice
->WorkBlockSize
,
312 FtwDevice
->FtwWorkSpaceLba
,
313 FtwDevice
->FtwWorkSpaceBase
,
314 FtwDevice
->FtwWorkSpaceSize
,
315 FtwDevice
->FtwWorkSpace
317 if (EFI_ERROR (Status
)) {
321 Status
= FtwGetLastWriteHeader (
322 FtwDevice
->FtwWorkSpaceHeader
,
323 FtwDevice
->FtwWorkSpaceSize
,
324 &FtwDevice
->FtwLastWriteHeader
326 if (EFI_ERROR (Status
)) {
331 // Refresh the FtwLastWriteRecord
333 Status
= FtwGetLastWriteRecord (
334 FtwDevice
->FtwLastWriteHeader
,
335 &FtwDevice
->FtwLastWriteRecord
337 if (EFI_ERROR (Status
)) {
345 Reclaim the work space on the working block.
347 @param FtwDevice Point to private data of FTW driver
348 @param PreserveRecord Whether to preserve the working record is needed
350 @retval EFI_SUCCESS The function completed successfully
351 @retval EFI_OUT_OF_RESOURCES Allocate memory error
352 @retval EFI_ABORTED The function could not complete successfully
356 FtwReclaimWorkSpace (
357 IN EFI_FTW_DEVICE
*FtwDevice
,
358 IN BOOLEAN PreserveRecord
363 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
365 UINTN TempBufferSize
;
366 UINTN SpareBufferSize
;
368 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
371 EFI_LBA WorkSpaceLbaOffset
;
373 DEBUG ((EFI_D_INFO
, "Ftw: start to reclaim work space\n"));
375 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
378 // Read all original data from working block to a memory buffer
380 TempBufferSize
= FtwDevice
->NumberOfWorkBlock
* FtwDevice
->WorkBlockSize
;
381 TempBuffer
= AllocateZeroPool (TempBufferSize
);
382 if (TempBuffer
== NULL
) {
383 return EFI_OUT_OF_RESOURCES
;
387 for (Index
= 0; Index
< FtwDevice
->NumberOfWorkBlock
; Index
+= 1) {
388 Length
= FtwDevice
->WorkBlockSize
;
389 Status
= FtwDevice
->FtwFvBlock
->Read (
390 FtwDevice
->FtwFvBlock
,
391 FtwDevice
->FtwWorkBlockLba
+ Index
,
396 if (EFI_ERROR (Status
)) {
397 FreePool (TempBuffer
);
404 // Clean up the workspace, remove all the completed records.
407 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
408 FtwDevice
->FtwWorkSpaceBase
;
411 // Clear the content of buffer that will save the new work space data
413 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
416 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
420 FtwDevice
->FtwWorkSpaceHeader
,
421 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
423 if (PreserveRecord
) {
425 // Get the last record following the header,
427 Status
= FtwGetLastWriteHeader (
428 FtwDevice
->FtwWorkSpaceHeader
,
429 FtwDevice
->FtwWorkSpaceSize
,
430 &FtwDevice
->FtwLastWriteHeader
432 Header
= FtwDevice
->FtwLastWriteHeader
;
433 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
435 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
436 FtwDevice
->FtwLastWriteHeader
,
437 FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
443 FtwDevice
->FtwWorkSpace
,
445 FtwDevice
->FtwWorkSpaceSize
448 FtwGetLastWriteHeader (
449 FtwDevice
->FtwWorkSpaceHeader
,
450 FtwDevice
->FtwWorkSpaceSize
,
451 &FtwDevice
->FtwLastWriteHeader
454 FtwGetLastWriteRecord (
455 FtwDevice
->FtwLastWriteHeader
,
456 &FtwDevice
->FtwLastWriteRecord
460 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
462 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) (TempBuffer
+
463 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
464 FtwDevice
->FtwWorkSpaceBase
);
465 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
466 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
469 // Try to keep the content of spare block
470 // Save spare block into a spare backup memory buffer (Sparebuffer)
472 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
473 SpareBuffer
= AllocatePool (SpareBufferSize
);
474 if (SpareBuffer
== NULL
) {
475 FreePool (TempBuffer
);
476 return EFI_OUT_OF_RESOURCES
;
480 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
481 Length
= FtwDevice
->SpareBlockSize
;
482 Status
= FtwDevice
->FtwBackupFvb
->Read (
483 FtwDevice
->FtwBackupFvb
,
484 FtwDevice
->FtwSpareLba
+ Index
,
489 if (EFI_ERROR (Status
)) {
490 FreePool (TempBuffer
);
491 FreePool (SpareBuffer
);
498 // Write the memory buffer to spare block
500 Status
= FtwEraseSpareBlock (FtwDevice
);
501 if (EFI_ERROR (Status
)) {
502 FreePool (TempBuffer
);
503 FreePool (SpareBuffer
);
507 for (Index
= 0; TempBufferSize
> 0; Index
+= 1) {
508 if (TempBufferSize
> FtwDevice
->SpareBlockSize
) {
509 Length
= FtwDevice
->SpareBlockSize
;
511 Length
= TempBufferSize
;
513 Status
= FtwDevice
->FtwBackupFvb
->Write (
514 FtwDevice
->FtwBackupFvb
,
515 FtwDevice
->FtwSpareLba
+ Index
,
520 if (EFI_ERROR (Status
)) {
521 FreePool (TempBuffer
);
522 FreePool (SpareBuffer
);
527 TempBufferSize
-= Length
;
532 FreePool (TempBuffer
);
535 // Set the WorkingBlockValid in spare block
537 Status
= FtwUpdateFvState (
538 FtwDevice
->FtwBackupFvb
,
539 FtwDevice
->SpareBlockSize
,
540 FtwDevice
->FtwSpareLba
+ FtwDevice
->FtwWorkSpaceLbaInSpare
,
541 FtwDevice
->FtwWorkSpaceBaseInSpare
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
544 if (EFI_ERROR (Status
)) {
545 FreePool (SpareBuffer
);
549 // Before erase the working block, set WorkingBlockInvalid in working block.
551 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
552 // WorkingBlockInvalid);
554 Status
= FtwUpdateFvState (
555 FtwDevice
->FtwFvBlock
,
556 FtwDevice
->WorkBlockSize
,
557 FtwDevice
->FtwWorkSpaceLba
,
558 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
559 WORKING_BLOCK_INVALID
561 if (EFI_ERROR (Status
)) {
562 FreePool (SpareBuffer
);
566 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
569 // Write the spare block to working block
571 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
572 if (EFI_ERROR (Status
)) {
573 FreePool (SpareBuffer
);
577 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
579 Status
= FtwEraseSpareBlock (FtwDevice
);
580 if (EFI_ERROR (Status
)) {
581 FreePool (SpareBuffer
);
585 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
586 Length
= FtwDevice
->SpareBlockSize
;
587 Status
= FtwDevice
->FtwBackupFvb
->Write (
588 FtwDevice
->FtwBackupFvb
,
589 FtwDevice
->FtwSpareLba
+ Index
,
594 if (EFI_ERROR (Status
)) {
595 FreePool (SpareBuffer
);
602 FreePool (SpareBuffer
);
604 DEBUG ((EFI_D_INFO
, "Ftw: reclaim work space successfully\n"));