3 Internal functions to operate Working Block Space.
5 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "FaultTolerantWrite.h"
19 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader
= {ZERO_GUID
, 0, 0, 0, 0, {0, 0, 0}, 0};
22 Initialize a local work space header.
24 Since Signature and WriteQueueSize have been known, Crc can be calculated out,
25 then the work space header will be fixed.
28 InitializeLocalWorkSpaceHeader (
35 // Check signature with gEdkiiWorkingBlockSignatureGuid.
37 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, &mWorkingBlockHeader
.Signature
)) {
39 // The local work space header has been initialized.
46 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
51 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
54 &mWorkingBlockHeader
.Signature
,
55 &gEdkiiWorkingBlockSignatureGuid
,
58 mWorkingBlockHeader
.WriteQueueSize
= (UINT64
) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize
) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
61 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
65 // Calculate the Crc of woking block header
67 Status
= gBS
->CalculateCrc32 (
69 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
70 &mWorkingBlockHeader
.Crc
72 ASSERT_EFI_ERROR (Status
);
74 mWorkingBlockHeader
.WorkingBlockValid
= FTW_VALID_STATE
;
75 mWorkingBlockHeader
.WorkingBlockInvalid
= FTW_INVALID_STATE
;
79 Check to see if it is a valid work space.
82 @param WorkingHeader Pointer of working block header
84 @retval TRUE The work space is valid.
85 @retval FALSE The work space is invalid.
90 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
93 if (WorkingHeader
== NULL
) {
97 if (CompareMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)) == 0) {
101 DEBUG ((EFI_D_ERROR
, "Ftw: Work block header check error\n"));
106 Initialize a work space when there is no work space.
108 @param WorkingHeader Pointer of working block header
110 @retval EFI_SUCCESS The function completed successfully
111 @retval EFI_ABORTED The function could not complete successfully.
115 InitWorkSpaceHeader (
116 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
119 if (WorkingHeader
== NULL
) {
120 return EFI_INVALID_PARAMETER
;
123 CopyMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
129 Read work space data from work block or spare block.
131 @param FtwDevice The private data of FTW driver.
132 @param FvBlock FVB Protocol interface to access the block.
133 @param BlockSize The size of the block.
134 @param Lba Lba of the block.
135 @param Offset The offset within the block.
136 @param Length The number of bytes to read from the block.
137 @param Buffer The data is read.
139 @retval EFI_SUCCESS The function completed successfully.
140 @retval EFI_ABORTED The function could not complete successfully.
145 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
158 // Calculate the real Offset and Lba to write.
160 while (Offset
>= BlockSize
) {
167 if ((Offset
+ Length
) > BlockSize
) {
168 MyLength
= BlockSize
- Offset
;
173 Status
= FvBlock
->Read (
180 if (EFI_ERROR (Status
)) {
193 Write work space data to work block.
195 @param FvBlock FVB Protocol interface to access the block.
196 @param BlockSize The size of the block.
197 @param Lba Lba of the block.
198 @param Offset The offset within the block to place the data.
199 @param Length The number of bytes to write to the block.
200 @param Buffer The data to write.
202 @retval EFI_SUCCESS The function completed successfully.
203 @retval EFI_ABORTED The function could not complete successfully.
208 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
221 // Calculate the real Offset and Lba to write.
223 while (Offset
>= BlockSize
) {
230 if ((Offset
+ Length
) > BlockSize
) {
231 MyLength
= BlockSize
- Offset
;
236 Status
= FvBlock
->Write (
243 if (EFI_ERROR (Status
)) {
255 Read from working block to refresh the work space in memory.
257 @param FtwDevice Point to private data of FTW driver
259 @retval EFI_SUCCESS The function completed successfully
260 @retval EFI_ABORTED The function could not complete successfully.
265 IN EFI_FTW_DEVICE
*FtwDevice
269 UINTN RemainingSpaceSize
;
272 // Initialize WorkSpace as FTW_ERASED_BYTE
275 FtwDevice
->FtwWorkSpace
,
276 FtwDevice
->FtwWorkSpaceSize
,
281 // Read from working block
283 Status
= ReadWorkSpaceData (
284 FtwDevice
->FtwFvBlock
,
285 FtwDevice
->WorkBlockSize
,
286 FtwDevice
->FtwWorkSpaceLba
,
287 FtwDevice
->FtwWorkSpaceBase
,
288 FtwDevice
->FtwWorkSpaceSize
,
289 FtwDevice
->FtwWorkSpace
291 if (EFI_ERROR (Status
)) {
295 // Refresh the FtwLastWriteHeader
297 Status
= FtwGetLastWriteHeader (
298 FtwDevice
->FtwWorkSpaceHeader
,
299 FtwDevice
->FtwWorkSpaceSize
,
300 &FtwDevice
->FtwLastWriteHeader
302 RemainingSpaceSize
= FtwDevice
->FtwWorkSpaceSize
- ((UINTN
) FtwDevice
->FtwLastWriteHeader
- (UINTN
) FtwDevice
->FtwWorkSpace
);
303 DEBUG ((EFI_D_INFO
, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize
));
305 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
306 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
307 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
308 // it needs to reclaim work space.
310 if (EFI_ERROR (Status
) || RemainingSpaceSize
< sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD
)) {
312 // reclaim work space in working block.
314 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
315 if (EFI_ERROR (Status
)) {
316 DEBUG ((EFI_D_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
320 // Read from working block again
322 Status
= ReadWorkSpaceData (
323 FtwDevice
->FtwFvBlock
,
324 FtwDevice
->WorkBlockSize
,
325 FtwDevice
->FtwWorkSpaceLba
,
326 FtwDevice
->FtwWorkSpaceBase
,
327 FtwDevice
->FtwWorkSpaceSize
,
328 FtwDevice
->FtwWorkSpace
330 if (EFI_ERROR (Status
)) {
334 Status
= FtwGetLastWriteHeader (
335 FtwDevice
->FtwWorkSpaceHeader
,
336 FtwDevice
->FtwWorkSpaceSize
,
337 &FtwDevice
->FtwLastWriteHeader
339 if (EFI_ERROR (Status
)) {
344 // Refresh the FtwLastWriteRecord
346 Status
= FtwGetLastWriteRecord (
347 FtwDevice
->FtwLastWriteHeader
,
348 &FtwDevice
->FtwLastWriteRecord
350 if (EFI_ERROR (Status
)) {
358 Reclaim the work space on the working block.
360 @param FtwDevice Point to private data of FTW driver
361 @param PreserveRecord Whether to preserve the working record is needed
363 @retval EFI_SUCCESS The function completed successfully
364 @retval EFI_OUT_OF_RESOURCES Allocate memory error
365 @retval EFI_ABORTED The function could not complete successfully
369 FtwReclaimWorkSpace (
370 IN EFI_FTW_DEVICE
*FtwDevice
,
371 IN BOOLEAN PreserveRecord
376 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
378 UINTN TempBufferSize
;
379 UINTN SpareBufferSize
;
381 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
384 EFI_LBA WorkSpaceLbaOffset
;
386 DEBUG ((EFI_D_INFO
, "Ftw: start to reclaim work space\n"));
388 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
391 // Read all original data from working block to a memory buffer
393 TempBufferSize
= FtwDevice
->NumberOfWorkBlock
* FtwDevice
->WorkBlockSize
;
394 TempBuffer
= AllocateZeroPool (TempBufferSize
);
395 if (TempBuffer
== NULL
) {
396 return EFI_OUT_OF_RESOURCES
;
400 for (Index
= 0; Index
< FtwDevice
->NumberOfWorkBlock
; Index
+= 1) {
401 Length
= FtwDevice
->WorkBlockSize
;
402 Status
= FtwDevice
->FtwFvBlock
->Read (
403 FtwDevice
->FtwFvBlock
,
404 FtwDevice
->FtwWorkBlockLba
+ Index
,
409 if (EFI_ERROR (Status
)) {
410 FreePool (TempBuffer
);
417 // Clean up the workspace, remove all the completed records.
420 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
421 FtwDevice
->FtwWorkSpaceBase
;
424 // Clear the content of buffer that will save the new work space data
426 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
429 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
433 FtwDevice
->FtwWorkSpaceHeader
,
434 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
436 if (PreserveRecord
) {
438 // Get the last record following the header,
440 Status
= FtwGetLastWriteHeader (
441 FtwDevice
->FtwWorkSpaceHeader
,
442 FtwDevice
->FtwWorkSpaceSize
,
443 &FtwDevice
->FtwLastWriteHeader
445 Header
= FtwDevice
->FtwLastWriteHeader
;
446 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
448 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
449 FtwDevice
->FtwLastWriteHeader
,
450 FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
456 FtwDevice
->FtwWorkSpace
,
458 FtwDevice
->FtwWorkSpaceSize
461 FtwGetLastWriteHeader (
462 FtwDevice
->FtwWorkSpaceHeader
,
463 FtwDevice
->FtwWorkSpaceSize
,
464 &FtwDevice
->FtwLastWriteHeader
467 FtwGetLastWriteRecord (
468 FtwDevice
->FtwLastWriteHeader
,
469 &FtwDevice
->FtwLastWriteRecord
473 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
475 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) (TempBuffer
+
476 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->WorkBlockSize
+
477 FtwDevice
->FtwWorkSpaceBase
);
478 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
479 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
482 // Try to keep the content of spare block
483 // Save spare block into a spare backup memory buffer (Sparebuffer)
485 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
486 SpareBuffer
= AllocatePool (SpareBufferSize
);
487 if (SpareBuffer
== NULL
) {
488 FreePool (TempBuffer
);
489 return EFI_OUT_OF_RESOURCES
;
493 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
494 Length
= FtwDevice
->SpareBlockSize
;
495 Status
= FtwDevice
->FtwBackupFvb
->Read (
496 FtwDevice
->FtwBackupFvb
,
497 FtwDevice
->FtwSpareLba
+ Index
,
502 if (EFI_ERROR (Status
)) {
503 FreePool (TempBuffer
);
504 FreePool (SpareBuffer
);
511 // Write the memory buffer to spare block
513 Status
= FtwEraseSpareBlock (FtwDevice
);
515 for (Index
= 0; TempBufferSize
> 0; Index
+= 1) {
516 if (TempBufferSize
> FtwDevice
->SpareBlockSize
) {
517 Length
= FtwDevice
->SpareBlockSize
;
519 Length
= TempBufferSize
;
521 Status
= FtwDevice
->FtwBackupFvb
->Write (
522 FtwDevice
->FtwBackupFvb
,
523 FtwDevice
->FtwSpareLba
+ Index
,
528 if (EFI_ERROR (Status
)) {
529 FreePool (TempBuffer
);
530 FreePool (SpareBuffer
);
535 TempBufferSize
-= Length
;
540 FreePool (TempBuffer
);
543 // Set the WorkingBlockValid in spare block
545 Status
= FtwUpdateFvState (
546 FtwDevice
->FtwBackupFvb
,
547 FtwDevice
->SpareBlockSize
,
548 FtwDevice
->FtwSpareLba
+ FtwDevice
->FtwWorkSpaceLbaInSpare
,
549 FtwDevice
->FtwWorkSpaceBaseInSpare
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
552 if (EFI_ERROR (Status
)) {
553 FreePool (SpareBuffer
);
557 // Before erase the working block, set WorkingBlockInvalid in working block.
559 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
560 // WorkingBlockInvalid);
562 Status
= FtwUpdateFvState (
563 FtwDevice
->FtwFvBlock
,
564 FtwDevice
->WorkBlockSize
,
565 FtwDevice
->FtwWorkSpaceLba
,
566 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
567 WORKING_BLOCK_INVALID
569 if (EFI_ERROR (Status
)) {
570 FreePool (SpareBuffer
);
574 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
577 // Write the spare block to working block
579 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
580 if (EFI_ERROR (Status
)) {
581 FreePool (SpareBuffer
);
585 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
587 Status
= FtwEraseSpareBlock (FtwDevice
);
589 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
590 Length
= FtwDevice
->SpareBlockSize
;
591 Status
= FtwDevice
->FtwBackupFvb
->Write (
592 FtwDevice
->FtwBackupFvb
,
593 FtwDevice
->FtwSpareLba
+ Index
,
598 if (EFI_ERROR (Status
)) {
599 FreePool (SpareBuffer
);
606 FreePool (SpareBuffer
);
608 DEBUG ((EFI_D_INFO
, "Ftw: reclaim work space successfully\n"));