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.
20 @param[in] WorkSpaceLength Length in bytes of the FTW workspace area.
24 InitializeLocalWorkSpaceHeader (
25 IN UINTN WorkSpaceLength
29 // Check signature with gEdkiiWorkingBlockSignatureGuid.
31 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, &mWorkingBlockHeader
.Signature
)) {
33 // The local work space header has been initialized.
40 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
45 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
48 &mWorkingBlockHeader
.Signature
,
49 &gEdkiiWorkingBlockSignatureGuid
,
52 mWorkingBlockHeader
.WriteQueueSize
= WorkSpaceLength
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
);
55 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
59 // Calculate the Crc of woking block header
61 mWorkingBlockHeader
.Crc
= FtwCalculateCrc32 (
63 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
66 mWorkingBlockHeader
.WorkingBlockValid
= FTW_VALID_STATE
;
67 mWorkingBlockHeader
.WorkingBlockInvalid
= FTW_INVALID_STATE
;
71 Check to see if it is a valid work space.
74 @param WorkingHeader Pointer of working block header
76 @retval TRUE The work space is valid.
77 @retval FALSE The work space is invalid.
82 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
85 if (WorkingHeader
== NULL
) {
89 if (CompareMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)) == 0) {
93 DEBUG ((DEBUG_INFO
, "Ftw: Work block header check mismatch\n"));
98 Initialize a work space when there is no work space.
100 @param WorkingHeader Pointer of working block header
102 @retval EFI_SUCCESS The function completed successfully
103 @retval EFI_ABORTED The function could not complete successfully.
107 InitWorkSpaceHeader (
108 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
111 if (WorkingHeader
== NULL
) {
112 return EFI_INVALID_PARAMETER
;
115 CopyMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
121 Read work space data from work block or spare block.
123 @param FvBlock FVB Protocol interface to access the block.
124 @param BlockSize The size of the block.
125 @param Lba Lba of the block.
126 @param Offset The offset within the block.
127 @param Length The number of bytes to read from the block.
128 @param Buffer The data is read.
130 @retval EFI_SUCCESS The function completed successfully.
131 @retval EFI_ABORTED The function could not complete successfully.
136 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
149 // Calculate the real Offset and Lba to write.
151 while (Offset
>= BlockSize
) {
158 if ((Offset
+ Length
) > BlockSize
) {
159 MyLength
= BlockSize
- Offset
;
164 Status
= FvBlock
->Read (
171 if (EFI_ERROR (Status
)) {
185 Write work space data to work block.
187 @param FvBlock FVB Protocol interface to access the block.
188 @param BlockSize The size of the block.
189 @param Lba Lba of the block.
190 @param Offset The offset within the block to place the data.
191 @param Length The number of bytes to write to the block.
192 @param Buffer The data to write.
194 @retval EFI_SUCCESS The function completed successfully.
195 @retval EFI_ABORTED The function could not complete successfully.
200 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
213 // Calculate the real Offset and Lba to write.
215 while (Offset
>= BlockSize
) {
222 if ((Offset
+ Length
) > BlockSize
) {
223 MyLength
= BlockSize
- Offset
;
228 Status
= FvBlock
->Write (
235 if (EFI_ERROR (Status
)) {
249 Read from working block to refresh the work space in memory.
251 @param FtwDevice Point to private data of FTW driver
253 @retval EFI_SUCCESS The function completed successfully
254 @retval EFI_ABORTED The function could not complete successfully.
259 IN EFI_FTW_DEVICE
*FtwDevice
263 UINTN RemainingSpaceSize
;
266 // Initialize WorkSpace as FTW_ERASED_BYTE
269 FtwDevice
->FtwWorkSpace
,
270 FtwDevice
->FtwWorkSpaceSize
,
275 // Read from working block
277 Status
= ReadWorkSpaceData (
278 FtwDevice
->FtwFvBlock
,
279 FtwDevice
->WorkBlockSize
,
280 FtwDevice
->FtwWorkSpaceLba
,
281 FtwDevice
->FtwWorkSpaceBase
,
282 FtwDevice
->FtwWorkSpaceSize
,
283 FtwDevice
->FtwWorkSpace
285 if (EFI_ERROR (Status
)) {
290 // Refresh the FtwLastWriteHeader
292 Status
= FtwGetLastWriteHeader (
293 FtwDevice
->FtwWorkSpaceHeader
,
294 FtwDevice
->FtwWorkSpaceSize
,
295 &FtwDevice
->FtwLastWriteHeader
297 RemainingSpaceSize
= FtwDevice
->FtwWorkSpaceSize
- ((UINTN
)FtwDevice
->FtwLastWriteHeader
- (UINTN
)FtwDevice
->FtwWorkSpace
);
298 DEBUG ((DEBUG_INFO
, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize
));
300 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
301 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
302 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
303 // it needs to reclaim work space.
305 if (EFI_ERROR (Status
) || (RemainingSpaceSize
< sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD
))) {
307 // reclaim work space in working block.
309 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
310 if (EFI_ERROR (Status
)) {
311 DEBUG ((DEBUG_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
316 // Read from working block again
318 Status
= ReadWorkSpaceData (
319 FtwDevice
->FtwFvBlock
,
320 FtwDevice
->WorkBlockSize
,
321 FtwDevice
->FtwWorkSpaceLba
,
322 FtwDevice
->FtwWorkSpaceBase
,
323 FtwDevice
->FtwWorkSpaceSize
,
324 FtwDevice
->FtwWorkSpace
326 if (EFI_ERROR (Status
)) {
330 Status
= FtwGetLastWriteHeader (
331 FtwDevice
->FtwWorkSpaceHeader
,
332 FtwDevice
->FtwWorkSpaceSize
,
333 &FtwDevice
->FtwLastWriteHeader
335 if (EFI_ERROR (Status
)) {
341 // Refresh the FtwLastWriteRecord
343 Status
= FtwGetLastWriteRecord (
344 FtwDevice
->FtwLastWriteHeader
,
345 &FtwDevice
->FtwLastWriteRecord
347 if (EFI_ERROR (Status
)) {
355 Reclaim the work space on the working block.
357 @param FtwDevice Point to private data of FTW driver
358 @param PreserveRecord Whether to preserve the working record is needed
360 @retval EFI_SUCCESS The function completed successfully
361 @retval EFI_OUT_OF_RESOURCES Allocate memory error
362 @retval EFI_ABORTED The function could not complete successfully
366 FtwReclaimWorkSpace (
367 IN EFI_FTW_DEVICE
*FtwDevice
,
368 IN BOOLEAN PreserveRecord
373 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
375 UINTN TempBufferSize
;
376 UINTN SpareBufferSize
;
378 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
381 EFI_LBA WorkSpaceLbaOffset
;
383 DEBUG ((DEBUG_INFO
, "Ftw: start to reclaim work space\n"));
385 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
388 // Read all original data from working block to a memory buffer
390 TempBufferSize
= FtwDevice
->NumberOfWorkBlock
* FtwDevice
->WorkBlockSize
;
391 TempBuffer
= AllocateZeroPool (TempBufferSize
);
392 if (TempBuffer
== NULL
) {
393 return EFI_OUT_OF_RESOURCES
;
397 for (Index
= 0; Index
< FtwDevice
->NumberOfWorkBlock
; Index
+= 1) {
398 Length
= FtwDevice
->WorkBlockSize
;
399 Status
= FtwDevice
->FtwFvBlock
->Read (
400 FtwDevice
->FtwFvBlock
,
401 FtwDevice
->FtwWorkBlockLba
+ Index
,
406 if (EFI_ERROR (Status
)) {
407 FreePool (TempBuffer
);
415 // Clean up the workspace, remove all the completed records.
418 (UINTN
)WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
419 FtwDevice
->FtwWorkSpaceBase
;
422 // Clear the content of buffer that will save the new work space data
424 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
427 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
431 FtwDevice
->FtwWorkSpaceHeader
,
432 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
434 if (PreserveRecord
) {
436 // Get the last record following the header,
438 Status
= FtwGetLastWriteHeader (
439 FtwDevice
->FtwWorkSpaceHeader
,
440 FtwDevice
->FtwWorkSpaceSize
,
441 &FtwDevice
->FtwLastWriteHeader
443 Header
= FtwDevice
->FtwLastWriteHeader
;
444 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
446 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
447 FtwDevice
->FtwLastWriteHeader
,
448 FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
454 FtwDevice
->FtwWorkSpace
,
456 FtwDevice
->FtwWorkSpaceSize
459 FtwGetLastWriteHeader (
460 FtwDevice
->FtwWorkSpaceHeader
,
461 FtwDevice
->FtwWorkSpaceSize
,
462 &FtwDevice
->FtwLastWriteHeader
465 FtwGetLastWriteRecord (
466 FtwDevice
->FtwLastWriteHeader
,
467 &FtwDevice
->FtwLastWriteRecord
471 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
473 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*)(TempBuffer
+
474 (UINTN
)WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
475 FtwDevice
->FtwWorkSpaceBase
);
476 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
477 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
480 // Try to keep the content of spare block
481 // Save spare block into a spare backup memory buffer (Sparebuffer)
483 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
484 SpareBuffer
= AllocatePool (SpareBufferSize
);
485 if (SpareBuffer
== NULL
) {
486 FreePool (TempBuffer
);
487 return EFI_OUT_OF_RESOURCES
;
491 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
492 Length
= FtwDevice
->SpareBlockSize
;
493 Status
= FtwDevice
->FtwBackupFvb
->Read (
494 FtwDevice
->FtwBackupFvb
,
495 FtwDevice
->FtwSpareLba
+ Index
,
500 if (EFI_ERROR (Status
)) {
501 FreePool (TempBuffer
);
502 FreePool (SpareBuffer
);
510 // Write the memory buffer to spare block
512 Status
= FtwEraseSpareBlock (FtwDevice
);
513 if (EFI_ERROR (Status
)) {
514 FreePool (TempBuffer
);
515 FreePool (SpareBuffer
);
520 for (Index
= 0; TempBufferSize
> 0; Index
+= 1) {
521 if (TempBufferSize
> FtwDevice
->SpareBlockSize
) {
522 Length
= FtwDevice
->SpareBlockSize
;
524 Length
= TempBufferSize
;
527 Status
= FtwDevice
->FtwBackupFvb
->Write (
528 FtwDevice
->FtwBackupFvb
,
529 FtwDevice
->FtwSpareLba
+ Index
,
534 if (EFI_ERROR (Status
)) {
535 FreePool (TempBuffer
);
536 FreePool (SpareBuffer
);
541 TempBufferSize
-= Length
;
547 FreePool (TempBuffer
);
550 // Set the WorkingBlockValid in spare block
552 Status
= FtwUpdateFvState (
553 FtwDevice
->FtwBackupFvb
,
554 FtwDevice
->SpareBlockSize
,
555 FtwDevice
->FtwSpareLba
+ FtwDevice
->FtwWorkSpaceLbaInSpare
,
556 FtwDevice
->FtwWorkSpaceBaseInSpare
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
559 if (EFI_ERROR (Status
)) {
560 FreePool (SpareBuffer
);
565 // Before erase the working block, set WorkingBlockInvalid in working block.
567 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
568 // WorkingBlockInvalid);
570 Status
= FtwUpdateFvState (
571 FtwDevice
->FtwFvBlock
,
572 FtwDevice
->WorkBlockSize
,
573 FtwDevice
->FtwWorkSpaceLba
,
574 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
575 WORKING_BLOCK_INVALID
577 if (EFI_ERROR (Status
)) {
578 FreePool (SpareBuffer
);
582 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
585 // Write the spare block to working block
587 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
588 if (EFI_ERROR (Status
)) {
589 FreePool (SpareBuffer
);
594 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
596 Status
= FtwEraseSpareBlock (FtwDevice
);
597 if (EFI_ERROR (Status
)) {
598 FreePool (SpareBuffer
);
603 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
604 Length
= FtwDevice
->SpareBlockSize
;
605 Status
= FtwDevice
->FtwBackupFvb
->Write (
606 FtwDevice
->FtwBackupFvb
,
607 FtwDevice
->FtwSpareLba
+ Index
,
612 if (EFI_ERROR (Status
)) {
613 FreePool (SpareBuffer
);
620 FreePool (SpareBuffer
);
622 DEBUG ((DEBUG_INFO
, "Ftw: reclaim work space successfully\n"));