3 Copyright (c) 2006, 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
)) {
239 gBS
->FreePool (MyBuffer
);
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
)) {
259 gBS
->FreePool (MyBuffer
);
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
) {
279 gBS
->FreePool (MyBuffer
);
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
)) {
294 gBS
->FreePool (MyBuffer
);
295 gBS
->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
)) {
317 gBS
->FreePool (MyBuffer
);
318 gBS
->FreePool (SpareBuffer
);
327 gBS
->FreePool (MyBuffer
);
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 gBS
->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 gBS
->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 gBS
->FreePool (SpareBuffer
);
383 gBS
->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_FLASH_MAP_ENTRY_DATA
*FlashMapEntry
;
636 EFI_FV_BLOCK_MAP_ENTRY
*FvbMapEntry
;
638 EFI_PEI_HOB_POINTERS GuidHob
;
641 // Allocate Private data of this driver,
642 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
644 FtwLiteDevice
= NULL
;
645 FtwLiteDevice
= AllocatePool (sizeof (EFI_FTW_LITE_DEVICE
) + FTW_WORK_SPACE_SIZE
);
646 if (FtwLiteDevice
!= NULL
) {
647 Status
= EFI_SUCCESS
;
649 Status
= EFI_OUT_OF_RESOURCES
;
652 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
->SpareAreaLength
= 0;
672 FtwLiteDevice
->WorkSpaceLength
= 0;
674 GuidHob
.Raw
= GetHobList ();
675 while (NULL
!= (GuidHob
.Raw
= GetNextGuidHob (&gEfiFlashMapHobGuid
, GuidHob
.Raw
))) {
676 FlashMapEntry
= (EFI_FLASH_MAP_ENTRY_DATA
*) GET_GUID_HOB_DATA (GuidHob
.Guid
);
678 // Get the FTW work space Flash Map SUB area
680 if ((FlashMapEntry
->AreaType
== EFI_FLASH_AREA_FTW_STATE
) && (FlashMapEntry
->NumEntries
== 1)) {
681 FtwLiteDevice
->WorkSpaceAddress
= FlashMapEntry
->Entries
[0].Base
;
682 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) FlashMapEntry
->Entries
[0].Length
;
685 // Get the FTW backup SUB area
687 if ((FlashMapEntry
->AreaType
== EFI_FLASH_AREA_FTW_BACKUP
) && (FlashMapEntry
->NumEntries
== 1)) {
688 FtwLiteDevice
->SpareAreaAddress
= FlashMapEntry
->Entries
[0].Base
;
689 FtwLiteDevice
->SpareAreaLength
= (UINTN
) FlashMapEntry
->Entries
[0].Length
;
692 GuidHob
.Raw
= GET_NEXT_HOB (GuidHob
);
695 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
698 // Locate FVB protocol
700 Status
= gBS
->LocateHandleBuffer (
702 &gEfiFirmwareVolumeBlockProtocolGuid
,
707 ASSERT_EFI_ERROR (Status
);
709 ASSERT (HandleCount
> 0);
711 FtwLiteDevice
->FtwFvBlock
= NULL
;
712 FtwLiteDevice
->FtwBackupFvb
= NULL
;
713 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
714 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
715 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
716 Status
= gBS
->HandleProtocol (
718 &gEfiFirmwareVolumeBlockProtocolGuid
,
721 ASSERT_EFI_ERROR (Status
);
723 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
724 if (EFI_ERROR (Status
)) {
728 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
730 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
731 (FtwLiteDevice
->WorkSpaceAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
733 FtwLiteDevice
->FtwFvBlock
= Fvb
;
735 // To get the LBA of work space
737 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
739 // FV may have multiple types of BlockLength
741 FvbMapEntry
= &FwVolHeader
->FvBlockMap
[0];
742 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->BlockLength
== 0))) {
743 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
744 if (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->BlockLength
* LbaIndex
)) {
745 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
747 // Get the Work space size and Base(Offset)
749 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
750 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->BlockLength
* (LbaIndex
- 1)));
765 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
766 (FtwLiteDevice
->SpareAreaAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
768 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
770 // To get the LBA of spare
772 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
774 // FV may have multiple types of BlockLength
776 FvbMapEntry
= &FwVolHeader
->FvBlockMap
[0];
777 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->BlockLength
== 0))) {
778 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
779 if (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->BlockLength
* LbaIndex
)) {
781 // Get the NumberOfSpareBlock and SizeOfSpareBlock
783 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
784 FtwLiteDevice
->SizeOfSpareBlock
= FvbMapEntry
->BlockLength
;
785 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->SizeOfSpareBlock
;
787 // Check the range of spare area to make sure that it's in FV range
789 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
803 // Calculate the start LBA of working block. Working block is an area which
804 // contains working space in its last block and has the same size as spare
805 // block, unless there are not enough blocks before the block that contains
808 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
809 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
810 FtwLiteDevice
->FtwWorkBlockLba
= 0;
813 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
814 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
815 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
816 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
818 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
819 ASSERT_EFI_ERROR (Status
);
822 // Refresh workspace data from working block
824 Status
= WorkSpaceRefresh (FtwLiteDevice
);
825 ASSERT_EFI_ERROR (Status
);
828 // If the working block workspace is not valid, try the spare block
830 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
831 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace invalid, read from backup\n"));
833 // Read from spare block
835 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
836 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
837 FtwLiteDevice
->FtwBackupFvb
,
838 FtwLiteDevice
->FtwSpareLba
,
839 FtwLiteDevice
->FtwWorkSpaceBase
,
841 FtwLiteDevice
->FtwWorkSpace
843 ASSERT_EFI_ERROR (Status
);
846 // If spare block is valid, then replace working block content.
848 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
849 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
850 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart working block in Init() - %r\n", Status
));
851 ASSERT_EFI_ERROR (Status
);
853 FtwAbort (FtwLiteDevice
);
855 // Refresh work space.
857 Status
= WorkSpaceRefresh (FtwLiteDevice
);
858 if (EFI_ERROR (Status
)) {
862 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Both are invalid, init workspace\n"));
864 // If both are invalid, then initialize work space.
867 FtwLiteDevice
->FtwWorkSpace
,
868 FtwLiteDevice
->FtwWorkSpaceSize
,
871 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
873 // Write to work space on the working block
875 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
876 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
877 FtwLiteDevice
->FtwFvBlock
,
878 FtwLiteDevice
->FtwWorkSpaceLba
,
879 FtwLiteDevice
->FtwWorkSpaceBase
,
881 FtwLiteDevice
->FtwWorkSpace
883 if (EFI_ERROR (Status
)) {
889 // Hook the protocol API
891 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
894 // Install protocol interface
896 Status
= gBS
->InstallProtocolInterface (
897 &FtwLiteDevice
->Handle
,
898 &gEfiFaultTolerantWriteLiteProtocolGuid
,
899 EFI_NATIVE_INTERFACE
,
900 &FtwLiteDevice
->FtwLiteInstance
902 if (EFI_ERROR (Status
)) {
906 // If (!SpareCompleted) THEN Abort to rollback.
908 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
909 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
911 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
912 FtwAbort (FtwLiteDevice
);
915 // if (SpareCompleted) THEN Restart to fault tolerant write.
917 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
918 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
921 Status
= FtwRestart (FtwLiteDevice
);
922 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart last write - %r\n", Status
));
923 if (EFI_ERROR (Status
)) {
928 // To check the workspace buffer behind last records is EMPTY or not.
929 // If it's not EMPTY, FTW_LITE also need to call reclaim().
931 Record
= FtwLiteDevice
->FtwLastRecord
;
932 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
933 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
934 Offset
+= WRITE_TOTAL_SIZE
;
937 if (!IsErasedFlashBuffer (
939 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
940 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
942 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace is dirty, call reclaim...\n"));
943 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
944 if (EFI_ERROR (Status
)) {
945 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace reclaim - %r\n", Status
));