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
10 #include "FaultTolerantWrite.h"
12 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader
= { ZERO_GUID
, 0, 0, 0, 0, { 0, 0, 0 }, 0 };
15 Initialize a local work space header.
17 Since Signature and WriteQueueSize have been known, Crc can be calculated out,
18 then the work space header will be fixed.
21 InitializeLocalWorkSpaceHeader (
26 // Check signature with gEdkiiWorkingBlockSignatureGuid.
28 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, &mWorkingBlockHeader
.Signature
)) {
30 // The local work space header has been initialized.
37 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
42 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
45 &mWorkingBlockHeader
.Signature
,
46 &gEdkiiWorkingBlockSignatureGuid
,
49 mWorkingBlockHeader
.WriteQueueSize
= PcdGet32 (PcdFlashNvStorageFtwWorkingSize
) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
);
52 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
56 // Calculate the Crc of woking block header
58 mWorkingBlockHeader
.Crc
= FtwCalculateCrc32 (
60 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
63 mWorkingBlockHeader
.WorkingBlockValid
= FTW_VALID_STATE
;
64 mWorkingBlockHeader
.WorkingBlockInvalid
= FTW_INVALID_STATE
;
68 Check to see if it is a valid work space.
71 @param WorkingHeader Pointer of working block header
73 @retval TRUE The work space is valid.
74 @retval FALSE The work space is invalid.
79 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
82 if (WorkingHeader
== NULL
) {
86 if (CompareMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)) == 0) {
90 DEBUG ((DEBUG_INFO
, "Ftw: Work block header check mismatch\n"));
95 Initialize a work space when there is no work space.
97 @param WorkingHeader Pointer of working block header
99 @retval EFI_SUCCESS The function completed successfully
100 @retval EFI_ABORTED The function could not complete successfully.
104 InitWorkSpaceHeader (
105 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
108 if (WorkingHeader
== NULL
) {
109 return EFI_INVALID_PARAMETER
;
112 CopyMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
118 Read work space data from work block or spare block.
120 @param FvBlock FVB Protocol interface to access the block.
121 @param BlockSize The size of the block.
122 @param Lba Lba of the block.
123 @param Offset The offset within the block.
124 @param Length The number of bytes to read from the block.
125 @param Buffer The data is read.
127 @retval EFI_SUCCESS The function completed successfully.
128 @retval EFI_ABORTED The function could not complete successfully.
133 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
146 // Calculate the real Offset and Lba to write.
148 while (Offset
>= BlockSize
) {
155 if ((Offset
+ Length
) > BlockSize
) {
156 MyLength
= BlockSize
- Offset
;
161 Status
= FvBlock
->Read (
168 if (EFI_ERROR (Status
)) {
182 Write work space data to work block.
184 @param FvBlock FVB Protocol interface to access the block.
185 @param BlockSize The size of the block.
186 @param Lba Lba of the block.
187 @param Offset The offset within the block to place the data.
188 @param Length The number of bytes to write to the block.
189 @param Buffer The data to write.
191 @retval EFI_SUCCESS The function completed successfully.
192 @retval EFI_ABORTED The function could not complete successfully.
197 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
210 // Calculate the real Offset and Lba to write.
212 while (Offset
>= BlockSize
) {
219 if ((Offset
+ Length
) > BlockSize
) {
220 MyLength
= BlockSize
- Offset
;
225 Status
= FvBlock
->Write (
232 if (EFI_ERROR (Status
)) {
246 Read from working block to refresh the work space in memory.
248 @param FtwDevice Point to private data of FTW driver
250 @retval EFI_SUCCESS The function completed successfully
251 @retval EFI_ABORTED The function could not complete successfully.
256 IN EFI_FTW_DEVICE
*FtwDevice
260 UINTN RemainingSpaceSize
;
263 // Initialize WorkSpace as FTW_ERASED_BYTE
266 FtwDevice
->FtwWorkSpace
,
267 FtwDevice
->FtwWorkSpaceSize
,
272 // Read from working block
274 Status
= ReadWorkSpaceData (
275 FtwDevice
->FtwFvBlock
,
276 FtwDevice
->WorkBlockSize
,
277 FtwDevice
->FtwWorkSpaceLba
,
278 FtwDevice
->FtwWorkSpaceBase
,
279 FtwDevice
->FtwWorkSpaceSize
,
280 FtwDevice
->FtwWorkSpace
282 if (EFI_ERROR (Status
)) {
287 // Refresh the FtwLastWriteHeader
289 Status
= FtwGetLastWriteHeader (
290 FtwDevice
->FtwWorkSpaceHeader
,
291 FtwDevice
->FtwWorkSpaceSize
,
292 &FtwDevice
->FtwLastWriteHeader
294 RemainingSpaceSize
= FtwDevice
->FtwWorkSpaceSize
- ((UINTN
)FtwDevice
->FtwLastWriteHeader
- (UINTN
)FtwDevice
->FtwWorkSpace
);
295 DEBUG ((DEBUG_INFO
, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize
));
297 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
298 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
299 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
300 // it needs to reclaim work space.
302 if (EFI_ERROR (Status
) || (RemainingSpaceSize
< sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD
))) {
304 // reclaim work space in working block.
306 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
307 if (EFI_ERROR (Status
)) {
308 DEBUG ((DEBUG_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
313 // Read from working block again
315 Status
= ReadWorkSpaceData (
316 FtwDevice
->FtwFvBlock
,
317 FtwDevice
->WorkBlockSize
,
318 FtwDevice
->FtwWorkSpaceLba
,
319 FtwDevice
->FtwWorkSpaceBase
,
320 FtwDevice
->FtwWorkSpaceSize
,
321 FtwDevice
->FtwWorkSpace
323 if (EFI_ERROR (Status
)) {
327 Status
= FtwGetLastWriteHeader (
328 FtwDevice
->FtwWorkSpaceHeader
,
329 FtwDevice
->FtwWorkSpaceSize
,
330 &FtwDevice
->FtwLastWriteHeader
332 if (EFI_ERROR (Status
)) {
338 // Refresh the FtwLastWriteRecord
340 Status
= FtwGetLastWriteRecord (
341 FtwDevice
->FtwLastWriteHeader
,
342 &FtwDevice
->FtwLastWriteRecord
344 if (EFI_ERROR (Status
)) {
352 Reclaim the work space on the working block.
354 @param FtwDevice Point to private data of FTW driver
355 @param PreserveRecord Whether to preserve the working record is needed
357 @retval EFI_SUCCESS The function completed successfully
358 @retval EFI_OUT_OF_RESOURCES Allocate memory error
359 @retval EFI_ABORTED The function could not complete successfully
363 FtwReclaimWorkSpace (
364 IN EFI_FTW_DEVICE
*FtwDevice
,
365 IN BOOLEAN PreserveRecord
370 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
372 UINTN TempBufferSize
;
373 UINTN SpareBufferSize
;
375 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
378 EFI_LBA WorkSpaceLbaOffset
;
380 DEBUG ((DEBUG_INFO
, "Ftw: start to reclaim work space\n"));
382 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
385 // Read all original data from working block to a memory buffer
387 TempBufferSize
= FtwDevice
->NumberOfWorkBlock
* FtwDevice
->WorkBlockSize
;
388 TempBuffer
= AllocateZeroPool (TempBufferSize
);
389 if (TempBuffer
== NULL
) {
390 return EFI_OUT_OF_RESOURCES
;
394 for (Index
= 0; Index
< FtwDevice
->NumberOfWorkBlock
; Index
+= 1) {
395 Length
= FtwDevice
->WorkBlockSize
;
396 Status
= FtwDevice
->FtwFvBlock
->Read (
397 FtwDevice
->FtwFvBlock
,
398 FtwDevice
->FtwWorkBlockLba
+ Index
,
403 if (EFI_ERROR (Status
)) {
404 FreePool (TempBuffer
);
412 // Clean up the workspace, remove all the completed records.
415 (UINTN
)WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
416 FtwDevice
->FtwWorkSpaceBase
;
419 // Clear the content of buffer that will save the new work space data
421 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
424 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
428 FtwDevice
->FtwWorkSpaceHeader
,
429 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
431 if (PreserveRecord
) {
433 // Get the last record following the header,
435 Status
= FtwGetLastWriteHeader (
436 FtwDevice
->FtwWorkSpaceHeader
,
437 FtwDevice
->FtwWorkSpaceSize
,
438 &FtwDevice
->FtwLastWriteHeader
440 Header
= FtwDevice
->FtwLastWriteHeader
;
441 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
443 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
444 FtwDevice
->FtwLastWriteHeader
,
445 FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
451 FtwDevice
->FtwWorkSpace
,
453 FtwDevice
->FtwWorkSpaceSize
456 FtwGetLastWriteHeader (
457 FtwDevice
->FtwWorkSpaceHeader
,
458 FtwDevice
->FtwWorkSpaceSize
,
459 &FtwDevice
->FtwLastWriteHeader
462 FtwGetLastWriteRecord (
463 FtwDevice
->FtwLastWriteHeader
,
464 &FtwDevice
->FtwLastWriteRecord
468 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
470 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*)(TempBuffer
+
471 (UINTN
)WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
472 FtwDevice
->FtwWorkSpaceBase
);
473 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
474 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
477 // Try to keep the content of spare block
478 // Save spare block into a spare backup memory buffer (Sparebuffer)
480 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
481 SpareBuffer
= AllocatePool (SpareBufferSize
);
482 if (SpareBuffer
== NULL
) {
483 FreePool (TempBuffer
);
484 return EFI_OUT_OF_RESOURCES
;
488 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
489 Length
= FtwDevice
->SpareBlockSize
;
490 Status
= FtwDevice
->FtwBackupFvb
->Read (
491 FtwDevice
->FtwBackupFvb
,
492 FtwDevice
->FtwSpareLba
+ Index
,
497 if (EFI_ERROR (Status
)) {
498 FreePool (TempBuffer
);
499 FreePool (SpareBuffer
);
507 // Write the memory buffer to spare block
509 Status
= FtwEraseSpareBlock (FtwDevice
);
510 if (EFI_ERROR (Status
)) {
511 FreePool (TempBuffer
);
512 FreePool (SpareBuffer
);
517 for (Index
= 0; TempBufferSize
> 0; Index
+= 1) {
518 if (TempBufferSize
> FtwDevice
->SpareBlockSize
) {
519 Length
= FtwDevice
->SpareBlockSize
;
521 Length
= TempBufferSize
;
524 Status
= FtwDevice
->FtwBackupFvb
->Write (
525 FtwDevice
->FtwBackupFvb
,
526 FtwDevice
->FtwSpareLba
+ Index
,
531 if (EFI_ERROR (Status
)) {
532 FreePool (TempBuffer
);
533 FreePool (SpareBuffer
);
538 TempBufferSize
-= Length
;
544 FreePool (TempBuffer
);
547 // Set the WorkingBlockValid in spare block
549 Status
= FtwUpdateFvState (
550 FtwDevice
->FtwBackupFvb
,
551 FtwDevice
->SpareBlockSize
,
552 FtwDevice
->FtwSpareLba
+ FtwDevice
->FtwWorkSpaceLbaInSpare
,
553 FtwDevice
->FtwWorkSpaceBaseInSpare
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
556 if (EFI_ERROR (Status
)) {
557 FreePool (SpareBuffer
);
562 // Before erase the working block, set WorkingBlockInvalid in working block.
564 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
565 // WorkingBlockInvalid);
567 Status
= FtwUpdateFvState (
568 FtwDevice
->FtwFvBlock
,
569 FtwDevice
->WorkBlockSize
,
570 FtwDevice
->FtwWorkSpaceLba
,
571 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
572 WORKING_BLOCK_INVALID
574 if (EFI_ERROR (Status
)) {
575 FreePool (SpareBuffer
);
579 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
582 // Write the spare block to working block
584 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
585 if (EFI_ERROR (Status
)) {
586 FreePool (SpareBuffer
);
591 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
593 Status
= FtwEraseSpareBlock (FtwDevice
);
594 if (EFI_ERROR (Status
)) {
595 FreePool (SpareBuffer
);
600 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
601 Length
= FtwDevice
->SpareBlockSize
;
602 Status
= FtwDevice
->FtwBackupFvb
->Write (
603 FtwDevice
->FtwBackupFvb
,
604 FtwDevice
->FtwSpareLba
+ Index
,
609 if (EFI_ERROR (Status
)) {
610 FreePool (SpareBuffer
);
617 FreePool (SpareBuffer
);
619 DEBUG ((DEBUG_INFO
, "Ftw: reclaim work space successfully\n"));