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
);
652 ZeroMem (FtwLiteDevice
, sizeof (EFI_FTW_LITE_DEVICE
));
653 FtwLiteDevice
->Signature
= FTW_LITE_DEVICE_SIGNATURE
;
656 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
658 FtwLiteDevice
->FtwWorkSpace
= (UINT8
*) (FtwLiteDevice
+ 1);
659 FtwLiteDevice
->FtwWorkSpaceSize
= FTW_WORK_SPACE_SIZE
;
661 FtwLiteDevice
->FtwWorkSpace
,
662 FtwLiteDevice
->FtwWorkSpaceSize
,
665 FtwLiteDevice
->FtwWorkSpaceHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) FtwLiteDevice
->FtwWorkSpace
;
667 FtwLiteDevice
->FtwLastRecord
= NULL
;
669 FtwLiteDevice
->WorkSpaceAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwWorkingBase
);
670 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwWorkingSize
);
672 FtwLiteDevice
->SpareAreaAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwSpareBase
);
673 FtwLiteDevice
->SpareAreaLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwSpareSize
);
675 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
678 // Locate FVB protocol
680 Status
= gBS
->LocateHandleBuffer (
682 &gEfiFirmwareVolumeBlockProtocolGuid
,
687 ASSERT_EFI_ERROR (Status
);
689 ASSERT (HandleCount
> 0);
691 FtwLiteDevice
->FtwFvBlock
= NULL
;
692 FtwLiteDevice
->FtwBackupFvb
= NULL
;
693 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
694 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
695 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
696 Status
= gBS
->HandleProtocol (
698 &gEfiFirmwareVolumeBlockProtocolGuid
,
701 ASSERT_EFI_ERROR (Status
);
703 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
704 if (EFI_ERROR (Status
)) {
708 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
710 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
711 (FtwLiteDevice
->WorkSpaceAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
713 FtwLiteDevice
->FtwFvBlock
= Fvb
;
715 // To get the LBA of work space
717 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
719 // FV may have multiple types of BlockLength
721 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
722 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
723 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
724 if (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
725 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
727 // Get the Work space size and Base(Offset)
729 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
730 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)));
745 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
746 (FtwLiteDevice
->SpareAreaAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
748 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
750 // To get the LBA of spare
752 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
754 // FV may have multiple types of BlockLength
756 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
757 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
758 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
759 if (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
761 // Get the NumberOfSpareBlock and SizeOfSpareBlock
763 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
764 FtwLiteDevice
->SizeOfSpareBlock
= FvbMapEntry
->Length
;
765 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->SizeOfSpareBlock
;
767 // Check the range of spare area to make sure that it's in FV range
769 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
783 // Calculate the start LBA of working block. Working block is an area which
784 // contains working space in its last block and has the same size as spare
785 // block, unless there are not enough blocks before the block that contains
788 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
789 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
790 FtwLiteDevice
->FtwWorkBlockLba
= 0;
793 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
794 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
795 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
796 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
798 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
799 ASSERT_EFI_ERROR (Status
);
802 // Refresh workspace data from working block
804 Status
= WorkSpaceRefresh (FtwLiteDevice
);
805 ASSERT_EFI_ERROR (Status
);
808 // If the working block workspace is not valid, try the spare block
810 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
811 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace invalid, read from backup\n"));
813 // Read from spare block
815 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
816 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
817 FtwLiteDevice
->FtwBackupFvb
,
818 FtwLiteDevice
->FtwSpareLba
,
819 FtwLiteDevice
->FtwWorkSpaceBase
,
821 FtwLiteDevice
->FtwWorkSpace
823 ASSERT_EFI_ERROR (Status
);
826 // If spare block is valid, then replace working block content.
828 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
829 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
830 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart working block in Init() - %r\n", Status
));
831 ASSERT_EFI_ERROR (Status
);
833 FtwAbort (FtwLiteDevice
);
835 // Refresh work space.
837 Status
= WorkSpaceRefresh (FtwLiteDevice
);
838 if (EFI_ERROR (Status
)) {
842 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Both are invalid, init workspace\n"));
844 // If both are invalid, then initialize work space.
847 FtwLiteDevice
->FtwWorkSpace
,
848 FtwLiteDevice
->FtwWorkSpaceSize
,
851 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
853 // Write to work space on the working block
855 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
856 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
857 FtwLiteDevice
->FtwFvBlock
,
858 FtwLiteDevice
->FtwWorkSpaceLba
,
859 FtwLiteDevice
->FtwWorkSpaceBase
,
861 FtwLiteDevice
->FtwWorkSpace
863 if (EFI_ERROR (Status
)) {
869 // Hook the protocol API
871 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
874 // Install protocol interface
876 Status
= gBS
->InstallProtocolInterface (
877 &FtwLiteDevice
->Handle
,
878 &gEfiFaultTolerantWriteLiteProtocolGuid
,
879 EFI_NATIVE_INTERFACE
,
880 &FtwLiteDevice
->FtwLiteInstance
882 if (EFI_ERROR (Status
)) {
886 // If (!SpareCompleted) THEN Abort to rollback.
888 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
889 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
891 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
892 FtwAbort (FtwLiteDevice
);
895 // if (SpareCompleted) THEN Restart to fault tolerant write.
897 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
898 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
901 Status
= FtwRestart (FtwLiteDevice
);
902 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart last write - %r\n", Status
));
903 if (EFI_ERROR (Status
)) {
908 // To check the workspace buffer behind last records is EMPTY or not.
909 // If it's not EMPTY, FTW_LITE also need to call reclaim().
911 Record
= FtwLiteDevice
->FtwLastRecord
;
912 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
913 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
914 Offset
+= WRITE_TOTAL_SIZE
;
917 if (!IsErasedFlashBuffer (
919 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
920 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
922 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace is dirty, call reclaim...\n"));
923 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
924 if (EFI_ERROR (Status
)) {
925 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace reclaim - %r\n", Status
));