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
;
637 EFI_PEI_HOB_POINTERS FvHob
;
638 EFI_FLASH_MAP_ENTRY_DATA
*FlashMapEntry
;
640 // Allocate Private data of this driver,
641 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
643 FtwLiteDevice
= NULL
;
644 FtwLiteDevice
= AllocatePool (sizeof (EFI_FTW_LITE_DEVICE
) + FTW_WORK_SPACE_SIZE
);
645 if (FtwLiteDevice
!= NULL
) {
646 Status
= EFI_SUCCESS
;
648 Status
= EFI_OUT_OF_RESOURCES
;
651 ASSERT_EFI_ERROR (Status
);
653 ZeroMem (FtwLiteDevice
, sizeof (EFI_FTW_LITE_DEVICE
));
654 FtwLiteDevice
->Signature
= FTW_LITE_DEVICE_SIGNATURE
;
657 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
659 FtwLiteDevice
->FtwWorkSpace
= (UINT8
*) (FtwLiteDevice
+ 1);
660 FtwLiteDevice
->FtwWorkSpaceSize
= FTW_WORK_SPACE_SIZE
;
662 FtwLiteDevice
->FtwWorkSpace
,
663 FtwLiteDevice
->FtwWorkSpaceSize
,
666 FtwLiteDevice
->FtwWorkSpaceHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) FtwLiteDevice
->FtwWorkSpace
;
668 FtwLiteDevice
->FtwLastRecord
= NULL
;
671 // BUGBUG: Here should use Pcd after build tool support dynamic PCD
673 FtwLiteDevice
->SpareAreaLength
= 0;
674 FtwLiteDevice
->WorkSpaceLength
= 0;
675 FvHob
.Raw
= GetHobList ();
676 while ((FvHob
.Raw
= GetNextGuidHob (&gEfiFlashMapHobGuid
, FvHob
.Raw
)) != NULL
) {
678 FlashMapEntry
= (EFI_FLASH_MAP_ENTRY_DATA
*) GET_GUID_HOB_DATA (FvHob
.Guid
);
681 // Get the FTW work space Flash Map SUB area
683 if ((FlashMapEntry
->AreaType
== EFI_FLASH_AREA_FTW_STATE
) && (FlashMapEntry
->NumEntries
== 1)) {
684 FtwLiteDevice
->WorkSpaceAddress
= FlashMapEntry
->Entries
[0].Base
;
685 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) FlashMapEntry
->Entries
[0].Length
;
688 // Get the FTW backup SUB area
690 if ((FlashMapEntry
->AreaType
== EFI_FLASH_AREA_FTW_BACKUP
) && (FlashMapEntry
->NumEntries
== 1)) {
691 FtwLiteDevice
->SpareAreaAddress
= FlashMapEntry
->Entries
[0].Base
;
692 FtwLiteDevice
->SpareAreaLength
= (UINTN
) FlashMapEntry
->Entries
[0].Length
;
695 FvHob
.Raw
= GET_NEXT_HOB (FvHob
);
698 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
701 // Locate FVB protocol
703 Status
= gBS
->LocateHandleBuffer (
705 &gEfiFirmwareVolumeBlockProtocolGuid
,
710 ASSERT_EFI_ERROR (Status
);
712 ASSERT (HandleCount
> 0);
714 FtwLiteDevice
->FtwFvBlock
= NULL
;
715 FtwLiteDevice
->FtwBackupFvb
= NULL
;
716 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
717 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
718 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
719 Status
= gBS
->HandleProtocol (
721 &gEfiFirmwareVolumeBlockProtocolGuid
,
724 ASSERT_EFI_ERROR (Status
);
726 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
727 if (EFI_ERROR (Status
)) {
731 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
733 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
734 (FtwLiteDevice
->WorkSpaceAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
736 FtwLiteDevice
->FtwFvBlock
= Fvb
;
738 // To get the LBA of work space
740 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
742 // FV may have multiple types of BlockLength
744 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
745 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
746 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
747 if (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
748 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
750 // Get the Work space size and Base(Offset)
752 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
753 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)));
768 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
769 (FtwLiteDevice
->SpareAreaAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
771 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
773 // To get the LBA of spare
775 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
777 // FV may have multiple types of BlockLength
779 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
780 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
781 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
782 if (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
784 // Get the NumberOfSpareBlock and SizeOfSpareBlock
786 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
787 FtwLiteDevice
->SizeOfSpareBlock
= FvbMapEntry
->Length
;
788 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->SizeOfSpareBlock
;
790 // Check the range of spare area to make sure that it's in FV range
792 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
806 // Calculate the start LBA of working block. Working block is an area which
807 // contains working space in its last block and has the same size as spare
808 // block, unless there are not enough blocks before the block that contains
811 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
812 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
813 FtwLiteDevice
->FtwWorkBlockLba
= 0;
816 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
817 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
818 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
819 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
821 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
822 ASSERT_EFI_ERROR (Status
);
825 // Refresh workspace data from working block
827 Status
= WorkSpaceRefresh (FtwLiteDevice
);
828 ASSERT_EFI_ERROR (Status
);
831 // If the working block workspace is not valid, try the spare block
833 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
834 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace invalid, read from backup\n"));
836 // Read from spare block
838 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
839 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
840 FtwLiteDevice
->FtwBackupFvb
,
841 FtwLiteDevice
->FtwSpareLba
,
842 FtwLiteDevice
->FtwWorkSpaceBase
,
844 FtwLiteDevice
->FtwWorkSpace
846 ASSERT_EFI_ERROR (Status
);
849 // If spare block is valid, then replace working block content.
851 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
852 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
853 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart working block in Init() - %r\n", Status
));
854 ASSERT_EFI_ERROR (Status
);
856 FtwAbort (FtwLiteDevice
);
858 // Refresh work space.
860 Status
= WorkSpaceRefresh (FtwLiteDevice
);
861 if (EFI_ERROR (Status
)) {
865 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Both are invalid, init workspace\n"));
867 // If both are invalid, then initialize work space.
870 FtwLiteDevice
->FtwWorkSpace
,
871 FtwLiteDevice
->FtwWorkSpaceSize
,
874 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
876 // Write to work space on the working block
878 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
879 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
880 FtwLiteDevice
->FtwFvBlock
,
881 FtwLiteDevice
->FtwWorkSpaceLba
,
882 FtwLiteDevice
->FtwWorkSpaceBase
,
884 FtwLiteDevice
->FtwWorkSpace
886 if (EFI_ERROR (Status
)) {
892 // Hook the protocol API
894 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
897 // Install protocol interface
899 Status
= gBS
->InstallProtocolInterface (
900 &FtwLiteDevice
->Handle
,
901 &gEfiFaultTolerantWriteLiteProtocolGuid
,
902 EFI_NATIVE_INTERFACE
,
903 &FtwLiteDevice
->FtwLiteInstance
905 if (EFI_ERROR (Status
)) {
909 // If (!SpareCompleted) THEN Abort to rollback.
911 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
912 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
914 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
915 FtwAbort (FtwLiteDevice
);
918 // if (SpareCompleted) THEN Restart to fault tolerant write.
920 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
921 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
924 Status
= FtwRestart (FtwLiteDevice
);
925 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart last write - %r\n", Status
));
926 if (EFI_ERROR (Status
)) {
931 // To check the workspace buffer behind last records is EMPTY or not.
932 // If it's not EMPTY, FTW_LITE also need to call reclaim().
934 Record
= FtwLiteDevice
->FtwLastRecord
;
935 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
936 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
937 Offset
+= WRITE_TOTAL_SIZE
;
940 if (!IsErasedFlashBuffer (
942 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
943 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
945 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace is dirty, call reclaim...\n"));
946 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
947 if (EFI_ERROR (Status
)) {
948 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace reclaim - %r\n", Status
));