3 This is a simple fault tolerant write driver.
4 And it only supports write BufferSize <= SpareAreaLength.
6 This boot service protocol only provides fault tolerant write capability for
7 block devices. The protocol has internal non-volatile intermediate storage
8 of the data and private information. It should be able to recover
9 automatically from a critical fault, such as power failure.
11 The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
12 This work space is a memory copy of the work space on the Working Block,
13 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
15 The work space stores each write record as EFI_FTW_LITE_RECORD structure.
16 The spare block stores the write buffer before write to the target block.
18 The write record has three states to specify the different phase of write operation.
19 1) WRITE_ALLOCATED is that the record is allocated in write space.
20 The information of write operation is stored in write record structure.
21 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
22 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
24 This driver operates the data as the whole size of spare block. It also assumes that
25 working block is an area which contains working space in its last block and has the same size as spare block.
26 It first read the SpareAreaLength data from the target block into the spare memory buffer.
27 Then copy the write buffer data into the spare memory buffer.
28 Then write the spare memory buffer into the spare block.
29 Final copy the data from the spare block to the target block.
31 Copyright (c) 2006 - 2008, Intel Corporation
32 All rights reserved. This program and the accompanying materials
33 are licensed and made available under the terms and conditions of the BSD License
34 which accompanies this distribution. The full text of the license may be found at
35 http://opensource.org/licenses/bsd-license.php
37 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
38 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
45 Starts a target block update. This function will record data about write
46 in fault tolerant storage and will complete the write in a recoverable
47 manner, ensuring at all times that either the original contents or
48 the modified contents are available.
50 @param This The pointer to this protocol instance.
51 @param FvbHandle The handle of FVB protocol that provides services for
52 reading, writing, and erasing the target block.
53 @param Lba The logical block address of the target block.
54 @param Offset The offset within the target block to place the data.
55 @param NumBytes The number of bytes to write to the target block.
56 @param Buffer The data to write.
58 @retval EFI_SUCCESS The function completed successfully
59 @retval EFI_ABORTED The function could not complete successfully.
60 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
61 Offset + *NumBytes > SpareAreaLength.
62 @retval EFI_ACCESS_DENIED No writes have been allocated.
63 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
64 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
70 IN EFI_FTW_LITE_PROTOCOL
*This
,
71 IN EFI_HANDLE FvbHandle
,
74 IN OUT UINTN
*NumBytes
,
79 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
80 EFI_FTW_LITE_RECORD
*Record
;
81 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
82 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
87 UINTN SpareBufferSize
;
91 EFI_DEV_PATH_PTR DevPtr
;
94 // Refresh work space and get last record
96 FtwLiteDevice
= FTW_LITE_CONTEXT_FROM_THIS (This
);
97 Status
= WorkSpaceRefresh (FtwLiteDevice
);
98 if (EFI_ERROR (Status
)) {
102 Record
= FtwLiteDevice
->FtwLastRecord
;
105 // Check the flags of last write record
107 if ((Record
->WriteAllocated
== FTW_VALID_STATE
) || (Record
->SpareCompleted
== FTW_VALID_STATE
)) {
108 return EFI_ACCESS_DENIED
;
111 // IF former record has completed, THEN use next record
113 if (Record
->WriteCompleted
== FTW_VALID_STATE
) {
115 FtwLiteDevice
->FtwLastRecord
= Record
;
118 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
121 // Check if the input data can fit within the target block
123 if ((Offset
+*NumBytes
) > FtwLiteDevice
->SpareAreaLength
) {
124 return EFI_BAD_BUFFER_SIZE
;
127 // Check if there is enough free space for allocate a record
129 if ((MyOffset
+ FTW_LITE_RECORD_SIZE
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
130 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
131 if (EFI_ERROR (Status
)) {
132 DEBUG ((EFI_D_ERROR
, "FtwLite: Reclaim work space - %r", Status
));
137 // Get the FVB protocol by handle
139 Status
= FtwGetFvbByHandle (FvbHandle
, &Fvb
);
140 if (EFI_ERROR (Status
)) {
141 return EFI_NOT_FOUND
;
144 // Allocate a write record in workspace.
145 // Update Header->WriteAllocated as VALID
147 Status
= FtwUpdateFvState (
148 FtwLiteDevice
->FtwFvBlock
,
149 FtwLiteDevice
->FtwWorkSpaceLba
,
150 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
154 if (EFI_ERROR (Status
)) {
155 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Allocate record - %r\n", Status
));
159 Record
->WriteAllocated
= FTW_VALID_STATE
;
162 // Prepare data of write record, filling DevPath with memory mapped address.
164 DevPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
165 DevPtr
.MemMap
->Header
.Type
= HARDWARE_DEVICE_PATH
;
166 DevPtr
.MemMap
->Header
.SubType
= HW_MEMMAP_DP
;
167 SetDevicePathNodeLength (&DevPtr
.MemMap
->Header
, sizeof (MEMMAP_DEVICE_PATH
));
169 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
170 if (EFI_ERROR (Status
)) {
171 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Get FVB physical address - %r\n", Status
));
175 DevPtr
.MemMap
->MemoryType
= EfiMemoryMappedIO
;
176 DevPtr
.MemMap
->StartingAddress
= FvbPhysicalAddress
;
177 DevPtr
.MemMap
->EndingAddress
= FvbPhysicalAddress
+*NumBytes
;
182 Record
->Offset
= Offset
;
183 Record
->NumBytes
= *NumBytes
;
186 // Write the record to the work space.
188 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
189 MyLength
= FTW_LITE_RECORD_SIZE
;
191 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
192 FtwLiteDevice
->FtwFvBlock
,
193 FtwLiteDevice
->FtwWorkSpaceLba
,
194 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
198 if (EFI_ERROR (Status
)) {
202 // Record has been written to working block, then write data.
205 // Allocate a memory buffer
207 MyBufferSize
= FtwLiteDevice
->SpareAreaLength
;
208 MyBuffer
= AllocatePool (MyBufferSize
);
209 if (MyBuffer
== NULL
) {
210 return EFI_OUT_OF_RESOURCES
;
213 // Starting at Lba, if the number of the rest blocks on Fvb is less
214 // than NumberOfSpareBlock.
217 // Read all original data from target block to memory buffer
219 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Lba
)) {
221 // If target block falls into working block, we must follow the process of
222 // updating working block.
225 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
226 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
227 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
228 FtwLiteDevice
->FtwFvBlock
,
229 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
234 if (EFI_ERROR (Status
)) {
242 // Update Offset by adding the offset from the start LBA of working block to
243 // the target LBA. The target block can not span working block!
245 Offset
= (((UINTN
) (Lba
- FtwLiteDevice
->FtwWorkBlockLba
)) * FtwLiteDevice
->SizeOfSpareBlock
+ Offset
);
246 ASSERT ((Offset
+*NumBytes
) <= FtwLiteDevice
->SpareAreaLength
);
251 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
252 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
253 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
254 if (EFI_ERROR (Status
)) {
263 // Overwrite the updating range data with
264 // the input buffer content
266 CopyMem (MyBuffer
+ Offset
, Buffer
, *NumBytes
);
269 // Try to keep the content of spare block
270 // Save spare block into a spare backup memory buffer (Sparebuffer)
272 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
273 SpareBuffer
= AllocatePool (SpareBufferSize
);
274 if (SpareBuffer
== NULL
) {
276 return EFI_OUT_OF_RESOURCES
;
280 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
281 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
282 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
283 FtwLiteDevice
->FtwBackupFvb
,
284 FtwLiteDevice
->FtwSpareLba
+ Index
,
289 if (EFI_ERROR (Status
)) {
291 FreePool (SpareBuffer
);
298 // Write the memory buffer to spare block
299 // Don't forget to erase Flash first.
301 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
303 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
304 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
305 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
306 FtwLiteDevice
->FtwBackupFvb
,
307 FtwLiteDevice
->FtwSpareLba
+ Index
,
312 if (EFI_ERROR (Status
)) {
314 FreePool (SpareBuffer
);
326 // Set the SpareComplete in the FTW record,
328 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
329 Status
= FtwUpdateFvState (
330 FtwLiteDevice
->FtwFvBlock
,
331 FtwLiteDevice
->FtwWorkSpaceLba
,
332 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
335 if (EFI_ERROR (Status
)) {
336 FreePool (SpareBuffer
);
340 Record
->SpareCompleted
= FTW_VALID_STATE
;
343 // Since the content has already backuped in spare block, the write is
344 // guaranteed to be completed with fault tolerant manner.
346 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
347 if (EFI_ERROR (Status
)) {
348 FreePool (SpareBuffer
);
353 FtwLiteDevice
->FtwLastRecord
= Record
;
356 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
358 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
360 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
361 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
362 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
363 FtwLiteDevice
->FtwBackupFvb
,
364 FtwLiteDevice
->FtwSpareLba
+ Index
,
369 if (EFI_ERROR (Status
)) {
370 FreePool (SpareBuffer
);
379 FreePool (SpareBuffer
);
383 "FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
394 Write a record with fault tolerant manner.
395 Since the content has already backuped in spare block, the write is
396 guaranteed to be completed with fault tolerant manner.
399 @param FtwLiteDevice The private data of FTW_LITE driver
400 @param Fvb The FVB protocol that provides services for
401 reading, writing, and erasing the target block.
403 @retval EFI_SUCCESS The function completed successfully
404 @retval EFI_ABORTED The function could not complete successfully
409 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
410 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
414 EFI_FTW_LITE_RECORD
*Record
;
415 EFI_LBA WorkSpaceLbaOffset
;
419 // Spare Complete but Destination not complete,
420 // Recover the targt block with the spare block.
422 Record
= FtwLiteDevice
->FtwLastRecord
;
425 // IF target block is working block, THEN Flush Spare Block To Working Block;
426 // ELSE flush spare block to normal target block.ENDIF
428 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Record
->Lba
)) {
430 // If target block is working block, Attention:
431 // it's required to set SPARE_COMPLETED to spare block.
433 WorkSpaceLbaOffset
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
;
434 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
435 Status
= FtwUpdateFvState (
436 FtwLiteDevice
->FtwBackupFvb
,
437 FtwLiteDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
438 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
441 ASSERT_EFI_ERROR (Status
);
443 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
446 // Update blocks other than working block
448 Status
= FlushSpareBlockToTargetBlock (FtwLiteDevice
, Fvb
, Record
->Lba
);
451 ASSERT_EFI_ERROR (Status
);
454 // Set WriteCompleted flag in record
456 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
457 Status
= FtwUpdateFvState (
458 FtwLiteDevice
->FtwFvBlock
,
459 FtwLiteDevice
->FtwWorkSpaceLba
,
460 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
463 ASSERT_EFI_ERROR (Status
);
465 Record
->WriteCompleted
= FTW_VALID_STATE
;
471 Restarts a previously interrupted write. The caller must provide the
472 block protocol needed to complete the interrupted write.
475 @param FtwLiteDevice The private data of FTW_LITE driver
476 FvbHandle - The handle of FVB protocol that provides services for
477 reading, writing, and erasing the target block.
479 @retval EFI_SUCCESS The function completed successfully
480 @retval EFI_ACCESS_DENIED No pending writes exist
481 @retval EFI_NOT_FOUND FVB protocol not found by the handle
482 @retval EFI_ABORTED The function could not complete successfully
487 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
491 EFI_FTW_LITE_RECORD
*Record
;
492 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
493 EFI_DEV_PATH_PTR DevPathPtr
;
496 // Spare Completed but Destination not complete,
497 // Recover the targt block with the spare block.
499 Record
= FtwLiteDevice
->FtwLastRecord
;
502 // Only support memory mapped FVB device path by now.
504 DevPathPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
505 if (!((DevPathPtr
.MemMap
->Header
.Type
== HARDWARE_DEVICE_PATH
) && (DevPathPtr
.MemMap
->Header
.SubType
== HW_MEMMAP_DP
))
507 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: FVB Device Path is not memory mapped\n"));
511 Status
= GetFvbByAddress (DevPathPtr
.MemMap
->StartingAddress
, &Fvb
);
512 if (EFI_ERROR (Status
)) {
513 return EFI_NOT_FOUND
;
516 // Since the content has already backuped in spare block, the write is
517 // guaranteed to be completed with fault tolerant manner.
519 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
520 DEBUG ((EFI_D_FTW_INFO
, "FtwLite: Restart() - %r\n", Status
));
523 FtwLiteDevice
->FtwLastRecord
= Record
;
527 // This is restart, no need to keep spareblock content.
529 FtwEraseSpareBlock (FtwLiteDevice
);
536 Aborts all previous allocated writes.
539 @param FtwLiteDevice The private data of FTW_LITE driver
541 @retval EFI_SUCCESS The function completed successfully
542 @retval EFI_ABORTED The function could not complete successfully.
543 @retval EFI_NOT_FOUND No allocated writes exist.
548 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
554 if (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
== FTW_VALID_STATE
) {
555 return EFI_NOT_FOUND
;
558 // Update the complete state of the header as VALID and abort.
560 Offset
= (UINT8
*) FtwLiteDevice
->FtwLastRecord
- FtwLiteDevice
->FtwWorkSpace
;
561 Status
= FtwUpdateFvState (
562 FtwLiteDevice
->FtwFvBlock
,
563 FtwLiteDevice
->FtwWorkSpaceLba
,
564 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
567 if (EFI_ERROR (Status
)) {
571 FtwLiteDevice
->FtwLastRecord
->WriteCompleted
= FTW_VALID_STATE
;
573 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
576 // Erase the spare block
578 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
580 DEBUG ((EFI_D_FTW_INFO
, "FtwLite: Abort() success \n"));
585 This function is the entry point of the Fault Tolerant Write driver.
587 @param ImageHandle A handle for the image that is initializing this driver
588 @param SystemTable A pointer to the EFI system table
590 @retval EFI_SUCCESS FTW has finished the initialization
591 @retval EFI_ABORTED FTW initialization error
597 IN EFI_HANDLE ImageHandle
,
598 IN EFI_SYSTEM_TABLE
*SystemTable
601 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
603 EFI_HANDLE
*HandleBuffer
;
605 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
606 EFI_PHYSICAL_ADDRESS BaseAddress
;
607 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
608 EFI_FTW_LITE_RECORD
*Record
;
612 EFI_FV_BLOCK_MAP_ENTRY
*FvbMapEntry
;
616 // Allocate Private data of this driver, including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
618 Length
= FTW_WORK_SPACE_SIZE
;
619 if (Length
< PcdGet32 (PcdFlashNvStorageFtwWorkingSize
)) {
620 Length
= PcdGet32 (PcdFlashNvStorageFtwWorkingSize
);
623 FtwLiteDevice
= NULL
;
624 FtwLiteDevice
= AllocatePool (sizeof (EFI_FTW_LITE_DEVICE
) + Length
);
625 ASSERT (FtwLiteDevice
!= NULL
);
627 ZeroMem (FtwLiteDevice
, sizeof (EFI_FTW_LITE_DEVICE
));
628 FtwLiteDevice
->Signature
= FTW_LITE_DEVICE_SIGNATURE
;
631 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
633 FtwLiteDevice
->FtwWorkSpace
= (UINT8
*) (FtwLiteDevice
+ 1);
634 FtwLiteDevice
->FtwWorkSpaceSize
= FTW_WORK_SPACE_SIZE
;
635 FtwLiteDevice
->FtwWorkSpaceBase
= FTW_WORK_SPACE_BASE
;
637 FtwLiteDevice
->FtwWorkSpace
,
638 FtwLiteDevice
->FtwWorkSpaceSize
,
641 FtwLiteDevice
->FtwWorkSpaceHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) FtwLiteDevice
->FtwWorkSpace
;
643 FtwLiteDevice
->FtwLastRecord
= NULL
;
645 FtwLiteDevice
->WorkSpaceAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwWorkingBase
);
646 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwWorkingSize
);
648 FtwLiteDevice
->SpareAreaAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwSpareBase
);
649 FtwLiteDevice
->SpareAreaLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwSpareSize
);
651 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
654 // Locate FVB protocol
656 Status
= gBS
->LocateHandleBuffer (
658 &gEfiFirmwareVolumeBlockProtocolGuid
,
663 ASSERT_EFI_ERROR (Status
);
665 ASSERT (HandleCount
> 0);
667 FtwLiteDevice
->FtwFvBlock
= NULL
;
668 FtwLiteDevice
->FtwBackupFvb
= NULL
;
669 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
670 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
671 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
672 Status
= gBS
->HandleProtocol (
674 &gEfiFirmwareVolumeBlockProtocolGuid
,
677 ASSERT_EFI_ERROR (Status
);
679 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
680 if (EFI_ERROR (Status
)) {
684 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
686 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
687 (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FwVolHeader
->FvLength
))
689 FtwLiteDevice
->FtwFvBlock
= Fvb
;
691 // To get the LBA of work space
693 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
695 // FV may have multiple types of BlockLength
697 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
698 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
699 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
700 if ((FtwLiteDevice
->WorkSpaceAddress
>= (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)))
701 && (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
))) {
702 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
704 // Get the Work space size and Base(Offset)
706 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
707 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)));
714 if (LbaIndex
<= FvbMapEntry
->NumBlocks
) {
716 // Work space range is found.
728 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
729 (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FwVolHeader
->FvLength
))
731 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
733 // To get the LBA of spare
735 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
737 // FV may have multiple types of BlockLength
739 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
740 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
741 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
742 if ((FtwLiteDevice
->SpareAreaAddress
>= (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)))
743 && (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
))) {
745 // Get the NumberOfSpareBlock and SizeOfSpareBlock
747 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
748 FtwLiteDevice
->SizeOfSpareBlock
= FvbMapEntry
->Length
;
749 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->SizeOfSpareBlock
;
751 // Check the range of spare area to make sure that it's in FV range
753 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
757 if (LbaIndex
<= FvbMapEntry
->NumBlocks
) {
759 // Spare FV range is found.
772 // Calculate the start LBA of working block. Working block is an area which
773 // contains working space in its last block and has the same size as spare
774 // block, unless there are not enough blocks before the block that contains
777 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
778 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
779 FtwLiteDevice
->FtwWorkBlockLba
= 0;
782 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
783 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
784 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
785 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
787 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
788 FreePool (FtwLiteDevice
);
792 // Refresh workspace data from working block
794 Status
= WorkSpaceRefresh (FtwLiteDevice
);
795 ASSERT_EFI_ERROR (Status
);
798 // If the working block workspace is not valid, try the spare block
800 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
801 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace invalid, read from backup\n"));
803 // Read from spare block
805 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
806 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
807 FtwLiteDevice
->FtwBackupFvb
,
808 FtwLiteDevice
->FtwSpareLba
,
809 FtwLiteDevice
->FtwWorkSpaceBase
,
811 FtwLiteDevice
->FtwWorkSpace
813 ASSERT_EFI_ERROR (Status
);
816 // If spare block is valid, then replace working block content.
818 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
819 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
820 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart working block in Init() - %r\n", Status
));
821 ASSERT_EFI_ERROR (Status
);
823 FtwAbort (FtwLiteDevice
);
825 // Refresh work space.
827 Status
= WorkSpaceRefresh (FtwLiteDevice
);
828 if (EFI_ERROR (Status
)) {
829 FreePool (FtwLiteDevice
);
833 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Both are invalid, init workspace\n"));
835 // If both are invalid, then initialize work space.
838 FtwLiteDevice
->FtwWorkSpace
,
839 FtwLiteDevice
->FtwWorkSpaceSize
,
842 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
844 // Initialize the work space
846 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, FALSE
);
848 if (EFI_ERROR (Status
)) {
849 FreePool (FtwLiteDevice
);
855 // Hook the protocol API
857 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
860 // Install protocol interface
862 Status
= gBS
->InstallProtocolInterface (
863 &FtwLiteDevice
->Handle
,
864 &gEfiFaultTolerantWriteLiteProtocolGuid
,
865 EFI_NATIVE_INTERFACE
,
866 &FtwLiteDevice
->FtwLiteInstance
868 if (EFI_ERROR (Status
)) {
869 FreePool (FtwLiteDevice
);
873 // If (!SpareCompleted) THEN Abort to rollback.
875 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
876 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
878 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
879 FtwAbort (FtwLiteDevice
);
882 // if (SpareCompleted) THEN Restart to fault tolerant write.
884 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
885 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
888 Status
= FtwRestart (FtwLiteDevice
);
889 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart last write - %r\n", Status
));
890 if (EFI_ERROR (Status
)) {
895 // To check the workspace buffer behind last records is EMPTY or not.
896 // If it's not EMPTY, FTW_LITE also need to call reclaim().
898 Record
= FtwLiteDevice
->FtwLastRecord
;
899 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
900 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
901 Offset
+= FTW_LITE_RECORD_SIZE
;
904 if (!IsErasedFlashBuffer (
906 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
907 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
909 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace is dirty, call reclaim...\n"));
910 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
911 if (EFI_ERROR (Status
)) {
912 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace reclaim - %r\n", Status
));
913 FreePool (FtwLiteDevice
);