3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 This is a simple fault tolerant write driver, based on PlatformFd library.
20 And it only supports write BufferSize <= SpareAreaLength.
22 This boot service only protocol provides fault tolerant write capability for
23 block devices. The protocol has internal non-volatile intermediate storage
24 of the data and private information. It should be able to recover
25 automatically from a critical fault, such as power failure.
29 The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
30 This work space is a memory copy of the work space on the Woring Block,
31 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
38 // In write function, we should check the target range to prevent the user
39 // from writing Spare block and Working space directly.
42 // Fault Tolerant Write Protocol API
47 IN EFI_FTW_LITE_PROTOCOL
*This
,
48 IN EFI_HANDLE FvbHandle
,
51 IN OUT UINTN
*NumBytes
,
57 Starts a target block update. This function will record data about write
58 in fault tolerant storage and will complete the write in a recoverable
59 manner, ensuring at all times that either the original contents or
60 the modified contents are available.
63 This - Calling context
64 FvbHandle - The handle of FVB protocol that provides services for
65 reading, writing, and erasing the target block.
66 Lba - The logical block address of the target block.
67 Offset - The offset within the target block to place the data.
68 NumBytes - The number of bytes to write to the target block.
69 Buffer - The data to write.
72 EFI_SUCCESS - The function completed successfully
73 EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not
75 EFI_ACCESS_DENIED - No writes have been allocated.
76 EFI_NOT_FOUND - Cannot find FVB by handle.
77 EFI_OUT_OF_RESOURCES - Cannot allocate memory.
78 EFI_ABORTED - The function could not complete successfully.
83 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
84 EFI_FTW_LITE_RECORD
*Record
;
85 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
86 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
91 UINTN SpareBufferSize
;
95 EFI_DEV_PATH_PTR DevPtr
;
98 // Refresh work space and get last record
100 FtwLiteDevice
= FTW_LITE_CONTEXT_FROM_THIS (This
);
101 Status
= WorkSpaceRefresh (FtwLiteDevice
);
102 if (EFI_ERROR (Status
)) {
106 Record
= FtwLiteDevice
->FtwLastRecord
;
109 // Check the flags of last write record
111 if ((Record
->WriteAllocated
== FTW_VALID_STATE
) || (Record
->SpareCompleted
== FTW_VALID_STATE
)) {
112 return EFI_ACCESS_DENIED
;
115 // IF former record has completed, THEN use next record
117 if (Record
->WriteCompleted
== FTW_VALID_STATE
) {
119 FtwLiteDevice
->FtwLastRecord
= Record
;
122 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
125 // Check if the input data can fit within the target block
127 if ((Offset
+*NumBytes
) > FtwLiteDevice
->SpareAreaLength
) {
128 return EFI_BAD_BUFFER_SIZE
;
131 // Check if there is enough free space for allocate a record
133 if ((MyOffset
+ WRITE_TOTAL_SIZE
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
134 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
135 if (EFI_ERROR (Status
)) {
136 DEBUG ((EFI_D_ERROR
, "FtwLite: Reclaim work space - %r", Status
));
141 // Get the FVB protocol by handle
143 Status
= FtwGetFvbByHandle (FvbHandle
, &Fvb
);
144 if (EFI_ERROR (Status
)) {
145 return EFI_NOT_FOUND
;
148 // Allocate a write record in workspace.
149 // Update Header->WriteAllocated as VALID
151 Status
= FtwUpdateFvState (
152 FtwLiteDevice
->FtwFvBlock
,
153 FtwLiteDevice
->FtwWorkSpaceLba
,
154 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
158 if (EFI_ERROR (Status
)) {
159 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Allocate record - %r\n", Status
));
163 Record
->WriteAllocated
= FTW_VALID_STATE
;
166 // Prepare data of write record, filling DevPath with memory mapped address.
168 DevPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
169 DevPtr
.MemMap
->Header
.Type
= HARDWARE_DEVICE_PATH
;
170 DevPtr
.MemMap
->Header
.SubType
= HW_MEMMAP_DP
;
171 SetDevicePathNodeLength (&DevPtr
.MemMap
->Header
, sizeof (MEMMAP_DEVICE_PATH
));
173 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
174 if (EFI_ERROR (Status
)) {
175 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Get FVB physical address - %r\n", Status
));
179 DevPtr
.MemMap
->MemoryType
= EfiMemoryMappedIO
;
180 DevPtr
.MemMap
->StartingAddress
= FvbPhysicalAddress
;
181 DevPtr
.MemMap
->EndingAddress
= FvbPhysicalAddress
+*NumBytes
;
186 Record
->Offset
= Offset
;
187 Record
->NumBytes
= *NumBytes
;
190 // Write the record to the work space.
192 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
193 MyLength
= FTW_LITE_RECORD_SIZE
;
195 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
196 FtwLiteDevice
->FtwFvBlock
,
197 FtwLiteDevice
->FtwWorkSpaceLba
,
198 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
202 if (EFI_ERROR (Status
)) {
206 // Record has been written to working block, then write data.
209 // Allocate a memory buffer
211 MyBufferSize
= FtwLiteDevice
->SpareAreaLength
;
212 MyBuffer
= AllocatePool (MyBufferSize
);
213 if (MyBuffer
== NULL
) {
214 return EFI_OUT_OF_RESOURCES
;
217 // Starting at Lba, if the number of the rest blocks on Fvb is less
218 // than NumberOfSpareBlock.
221 // Read all original data from target block to memory buffer
223 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Lba
)) {
225 // If target block falls into working block, we must follow the process of
226 // updating working block.
229 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
230 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
231 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
232 FtwLiteDevice
->FtwFvBlock
,
233 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
238 if (EFI_ERROR (Status
)) {
246 // Update Offset by adding the offset from the start LBA of working block to
247 // the target LBA. The target block can not span working block!
249 Offset
= (((UINTN
) (Lba
- FtwLiteDevice
->FtwWorkBlockLba
)) * FtwLiteDevice
->SizeOfSpareBlock
+ Offset
);
250 ASSERT ((Offset
+*NumBytes
) <= FtwLiteDevice
->SpareAreaLength
);
255 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
256 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
257 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
258 if (EFI_ERROR (Status
)) {
267 // Overwrite the updating range data with
268 // the input buffer content
270 CopyMem (MyBuffer
+ Offset
, Buffer
, *NumBytes
);
273 // Try to keep the content of spare block
274 // Save spare block into a spare backup memory buffer (Sparebuffer)
276 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
277 SpareBuffer
= AllocatePool (SpareBufferSize
);
278 if (SpareBuffer
== NULL
) {
280 return EFI_OUT_OF_RESOURCES
;
284 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
285 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
286 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
287 FtwLiteDevice
->FtwBackupFvb
,
288 FtwLiteDevice
->FtwSpareLba
+ Index
,
293 if (EFI_ERROR (Status
)) {
295 FreePool (SpareBuffer
);
302 // Write the memory buffer to spare block
303 // Don't forget to erase Flash first.
305 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
307 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
308 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
309 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
310 FtwLiteDevice
->FtwBackupFvb
,
311 FtwLiteDevice
->FtwSpareLba
+ Index
,
316 if (EFI_ERROR (Status
)) {
318 FreePool (SpareBuffer
);
330 // Set the SpareCompleteD in the FTW record,
332 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
333 Status
= FtwUpdateFvState (
334 FtwLiteDevice
->FtwFvBlock
,
335 FtwLiteDevice
->FtwWorkSpaceLba
,
336 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
339 if (EFI_ERROR (Status
)) {
340 FreePool (SpareBuffer
);
344 Record
->SpareCompleted
= FTW_VALID_STATE
;
347 // Since the content has already backuped in spare block, the write is
348 // guaranteed to be completed with fault tolerant manner.
350 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
351 if (EFI_ERROR (Status
)) {
352 FreePool (SpareBuffer
);
357 FtwLiteDevice
->FtwLastRecord
= Record
;
360 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
362 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
364 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
365 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
366 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
367 FtwLiteDevice
->FtwBackupFvb
,
368 FtwLiteDevice
->FtwSpareLba
+ Index
,
373 if (EFI_ERROR (Status
)) {
374 FreePool (SpareBuffer
);
383 FreePool (SpareBuffer
);
387 "FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
399 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
400 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
405 Write a record with fault tolerant mannaer.
406 Since the content has already backuped in spare block, the write is
407 guaranteed to be completed with fault tolerant manner.
410 FtwLiteDevice - The private data of FTW_LITE driver
411 Fvb - The FVB protocol that provides services for
412 reading, writing, and erasing the target block.
415 EFI_SUCCESS - The function completed successfully
416 EFI_ABORTED - The function could not complete successfully
421 EFI_FTW_LITE_RECORD
*Record
;
422 EFI_LBA WorkSpaceLbaOffset
;
426 // Spare Complete but Destination not complete,
427 // Recover the targt block with the spare block.
429 Record
= FtwLiteDevice
->FtwLastRecord
;
432 // IF target block is working block, THEN Flush Spare Block To Working Block;
433 // ELSE IF target block is boot block, THEN Flush Spare Block To boot Block;
434 // ELSE flush spare block to normal target block.ENDIF
436 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Record
->Lba
)) {
438 // If target block is working block, Attention:
439 // it's required to set SPARE_COMPLETED to spare block.
441 WorkSpaceLbaOffset
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
;
442 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
443 Status
= FtwUpdateFvState (
444 FtwLiteDevice
->FtwBackupFvb
,
445 FtwLiteDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
446 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
449 ASSERT_EFI_ERROR (Status
);
451 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
452 } else if (IsBootBlock (FtwLiteDevice
, Fvb
, Record
->Lba
)) {
456 Status
= FlushSpareBlockToBootBlock (FtwLiteDevice
);
459 // Update blocks other than working block or boot block
461 Status
= FlushSpareBlockToTargetBlock (FtwLiteDevice
, Fvb
, Record
->Lba
);
464 ASSERT_EFI_ERROR (Status
);
467 // Set WriteCompleted flag in record
469 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
470 Status
= FtwUpdateFvState (
471 FtwLiteDevice
->FtwFvBlock
,
472 FtwLiteDevice
->FtwWorkSpaceLba
,
473 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
476 ASSERT_EFI_ERROR (Status
);
478 Record
->WriteCompleted
= FTW_VALID_STATE
;
485 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
490 Restarts a previously interrupted write. The caller must provide the
491 block protocol needed to complete the interrupted write.
494 FtwLiteDevice - The private data of FTW_LITE driver
495 FvbHandle - The handle of FVB protocol that provides services for
496 reading, writing, and erasing the target block.
499 EFI_SUCCESS - The function completed successfully
500 EFI_ACCESS_DENIED - No pending writes exist
501 EFI_NOT_FOUND - FVB protocol not found by the handle
502 EFI_ABORTED - The function could not complete successfully
507 EFI_FTW_LITE_RECORD
*Record
;
508 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
509 EFI_DEV_PATH_PTR DevPathPtr
;
512 // Spare Completed but Destination not complete,
513 // Recover the targt block with the spare block.
515 Record
= FtwLiteDevice
->FtwLastRecord
;
518 // Only support memory mapped FVB device path by now.
520 DevPathPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
521 if (!((DevPathPtr
.MemMap
->Header
.Type
== HARDWARE_DEVICE_PATH
) && (DevPathPtr
.MemMap
->Header
.SubType
== HW_MEMMAP_DP
))
523 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: FVB Device Path is not memory mapped\n"));
527 Status
= GetFvbByAddress (DevPathPtr
.MemMap
->StartingAddress
, &Fvb
);
528 if (EFI_ERROR (Status
)) {
529 return EFI_NOT_FOUND
;
532 // Since the content has already backuped in spare block, the write is
533 // guaranteed to be completed with fault tolerant manner.
535 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
536 DEBUG ((EFI_D_FTW_INFO
, "FtwLite: Restart() - %r\n", Status
));
539 FtwLiteDevice
->FtwLastRecord
= Record
;
543 // This is restart, no need to keep spareblock content.
545 FtwEraseSpareBlock (FtwLiteDevice
);
553 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
558 Aborts all previous allocated writes.
561 FtwLiteDevice - The private data of FTW_LITE driver
564 EFI_SUCCESS - The function completed successfully
565 EFI_ABORTED - The function could not complete successfully.
566 EFI_NOT_FOUND - No allocated writes exist.
573 if (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
== FTW_VALID_STATE
) {
574 return EFI_NOT_FOUND
;
577 // Update the complete state of the header as VALID and abort.
579 Offset
= (UINT8
*) FtwLiteDevice
->FtwLastRecord
- FtwLiteDevice
->FtwWorkSpace
;
580 Status
= FtwUpdateFvState (
581 FtwLiteDevice
->FtwFvBlock
,
582 FtwLiteDevice
->FtwWorkSpaceLba
,
583 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
586 if (EFI_ERROR (Status
)) {
590 FtwLiteDevice
->FtwLastRecord
->WriteCompleted
= FTW_VALID_STATE
;
592 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
595 // Erase the spare block
597 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
599 DEBUG ((EFI_D_FTW_INFO
, "FtwLite: Abort() success \n"));
606 IN EFI_HANDLE ImageHandle
,
607 IN EFI_SYSTEM_TABLE
*SystemTable
611 This function is the entry point of the Fault Tolerant Write driver.
614 ImageHandle - EFI_HANDLE: A handle for the image that is initializing
616 SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table
619 EFI_SUCCESS - FTW has finished the initialization
620 EFI_ABORTED - FTW initialization error
624 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
626 EFI_HANDLE
*HandleBuffer
;
628 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
629 EFI_PHYSICAL_ADDRESS BaseAddress
;
630 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
631 EFI_FTW_LITE_RECORD
*Record
;
635 EFI_FV_BLOCK_MAP_ENTRY
*FvbMapEntry
;
639 // Allocate Private data of this driver,
640 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
642 FtwLiteDevice
= NULL
;
643 FtwLiteDevice
= AllocatePool (sizeof (EFI_FTW_LITE_DEVICE
) + FTW_WORK_SPACE_SIZE
);
644 if (FtwLiteDevice
!= NULL
) {
645 Status
= EFI_SUCCESS
;
647 Status
= EFI_OUT_OF_RESOURCES
;
650 ASSERT_EFI_ERROR (Status
);
654 ZeroMem (FtwLiteDevice
, sizeof (EFI_FTW_LITE_DEVICE
));
655 FtwLiteDevice
->Signature
= FTW_LITE_DEVICE_SIGNATURE
;
658 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
660 FtwLiteDevice
->FtwWorkSpace
= (UINT8
*) (FtwLiteDevice
+ 1);
661 FtwLiteDevice
->FtwWorkSpaceSize
= FTW_WORK_SPACE_SIZE
;
663 FtwLiteDevice
->FtwWorkSpace
,
664 FtwLiteDevice
->FtwWorkSpaceSize
,
667 FtwLiteDevice
->FtwWorkSpaceHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) FtwLiteDevice
->FtwWorkSpace
;
669 FtwLiteDevice
->FtwLastRecord
= NULL
;
671 FtwLiteDevice
->WorkSpaceAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwWorkingBase
);
672 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwWorkingSize
);
674 FtwLiteDevice
->SpareAreaAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwSpareBase
);
675 FtwLiteDevice
->SpareAreaLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwSpareSize
);
677 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
680 // Locate FVB protocol
682 Status
= gBS
->LocateHandleBuffer (
684 &gEfiFirmwareVolumeBlockProtocolGuid
,
689 ASSERT_EFI_ERROR (Status
);
691 ASSERT (HandleCount
> 0);
693 FtwLiteDevice
->FtwFvBlock
= NULL
;
694 FtwLiteDevice
->FtwBackupFvb
= NULL
;
695 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
696 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
697 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
698 Status
= gBS
->HandleProtocol (
700 &gEfiFirmwareVolumeBlockProtocolGuid
,
703 ASSERT_EFI_ERROR (Status
);
705 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
706 if (EFI_ERROR (Status
)) {
710 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
712 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
713 (FtwLiteDevice
->WorkSpaceAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
715 FtwLiteDevice
->FtwFvBlock
= Fvb
;
717 // To get the LBA of work space
719 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
721 // FV may have multiple types of BlockLength
723 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
724 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
725 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
726 if (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
727 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
729 // Get the Work space size and Base(Offset)
731 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
732 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)));
747 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
748 (FtwLiteDevice
->SpareAreaAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
750 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
752 // To get the LBA of spare
754 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
756 // FV may have multiple types of BlockLength
758 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
759 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
760 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
761 if (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
763 // Get the NumberOfSpareBlock and SizeOfSpareBlock
765 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
766 FtwLiteDevice
->SizeOfSpareBlock
= FvbMapEntry
->Length
;
767 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->SizeOfSpareBlock
;
769 // Check the range of spare area to make sure that it's in FV range
771 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
785 // Calculate the start LBA of working block. Working block is an area which
786 // contains working space in its last block and has the same size as spare
787 // block, unless there are not enough blocks before the block that contains
790 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
791 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
792 FtwLiteDevice
->FtwWorkBlockLba
= 0;
795 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
796 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
797 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
798 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
800 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
801 ASSERT_EFI_ERROR (Status
);
804 // Refresh workspace data from working block
806 Status
= WorkSpaceRefresh (FtwLiteDevice
);
807 ASSERT_EFI_ERROR (Status
);
810 // If the working block workspace is not valid, try the spare block
812 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
813 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace invalid, read from backup\n"));
815 // Read from spare block
817 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
818 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
819 FtwLiteDevice
->FtwBackupFvb
,
820 FtwLiteDevice
->FtwSpareLba
,
821 FtwLiteDevice
->FtwWorkSpaceBase
,
823 FtwLiteDevice
->FtwWorkSpace
825 ASSERT_EFI_ERROR (Status
);
828 // If spare block is valid, then replace working block content.
830 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
831 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
832 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart working block in Init() - %r\n", Status
));
833 ASSERT_EFI_ERROR (Status
);
835 FtwAbort (FtwLiteDevice
);
837 // Refresh work space.
839 Status
= WorkSpaceRefresh (FtwLiteDevice
);
840 if (EFI_ERROR (Status
)) {
844 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Both are invalid, init workspace\n"));
846 // If both are invalid, then initialize work space.
849 FtwLiteDevice
->FtwWorkSpace
,
850 FtwLiteDevice
->FtwWorkSpaceSize
,
853 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
855 // Write to work space on the working block
857 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
858 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
859 FtwLiteDevice
->FtwFvBlock
,
860 FtwLiteDevice
->FtwWorkSpaceLba
,
861 FtwLiteDevice
->FtwWorkSpaceBase
,
863 FtwLiteDevice
->FtwWorkSpace
865 if (EFI_ERROR (Status
)) {
871 // Hook the protocol API
873 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
876 // Install protocol interface
878 Status
= gBS
->InstallProtocolInterface (
879 &FtwLiteDevice
->Handle
,
880 &gEfiFaultTolerantWriteLiteProtocolGuid
,
881 EFI_NATIVE_INTERFACE
,
882 &FtwLiteDevice
->FtwLiteInstance
884 if (EFI_ERROR (Status
)) {
888 // If (!SpareCompleted) THEN Abort to rollback.
890 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
891 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
893 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
894 FtwAbort (FtwLiteDevice
);
897 // if (SpareCompleted) THEN Restart to fault tolerant write.
899 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
900 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
903 Status
= FtwRestart (FtwLiteDevice
);
904 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart last write - %r\n", Status
));
905 if (EFI_ERROR (Status
)) {
910 // To check the workspace buffer behind last records is EMPTY or not.
911 // If it's not EMPTY, FTW_LITE also need to call reclaim().
913 Record
= FtwLiteDevice
->FtwLastRecord
;
914 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
915 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
916 Offset
+= WRITE_TOTAL_SIZE
;
919 if (!IsErasedFlashBuffer (
921 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
922 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
924 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace is dirty, call reclaim...\n"));
925 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
926 if (EFI_ERROR (Status
)) {
927 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace reclaim - %r\n", Status
));