3 This is a simple fault tolerant write driver.
4 And it only supports write BufferSize <= SpareAreaLength.
6 This boot service only protocol provides fault tolerant write capability for
7 block devices. The protocol has internal non-volatile intermediate storage
8 of the data and private information. It should be able to recover
9 automatically from a critical fault, such as power failure.
11 The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
12 This work space is a memory copy of the work space on the Working Block,
13 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
15 Copyright (c) 2006 - 2008, Intel Corporation
16 All rights reserved. This program and the accompanying materials
17 are licensed and made available under the terms and conditions of the BSD License
18 which accompanies this distribution. The full text of the license may be found at
19 http://opensource.org/licenses/bsd-license.php
21 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
22 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
29 Starts a target block update. This function will record data about write
30 in fault tolerant storage and will complete the write in a recoverable
31 manner, ensuring at all times that either the original contents or
32 the modified contents are available. We should check the target
33 range to prevent the user from writing Spare block and Working
36 @param This Calling context
37 @param FvbHandle The handle of FVB protocol that provides services for
38 reading, writing, and erasing the target block.
39 @param Lba The logical block address of the target block.
40 @param Offset The offset within the target block to place the data.
41 @param NumBytes The number of bytes to write to the target block.
42 @param Buffer The data to write.
44 @retval EFI_SUCCESS The function completed successfully
45 @retval EFI_BAD_BUFFER_SIZE The write would span a target block, which is not
47 @retval EFI_ACCESS_DENIED No writes have been allocated.
48 @retval EFI_NOT_FOUND Cannot find FVB by handle.
49 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory.
50 @retval EFI_ABORTED The function could not complete successfully.
56 IN EFI_FTW_LITE_PROTOCOL
*This
,
57 IN EFI_HANDLE FvbHandle
,
60 IN OUT UINTN
*NumBytes
,
65 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
66 EFI_FTW_LITE_RECORD
*Record
;
67 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
68 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
73 UINTN SpareBufferSize
;
77 EFI_DEV_PATH_PTR DevPtr
;
80 // Refresh work space and get last record
82 FtwLiteDevice
= FTW_LITE_CONTEXT_FROM_THIS (This
);
83 Status
= WorkSpaceRefresh (FtwLiteDevice
);
84 if (EFI_ERROR (Status
)) {
88 Record
= FtwLiteDevice
->FtwLastRecord
;
91 // Check the flags of last write record
93 if ((Record
->WriteAllocated
== FTW_VALID_STATE
) || (Record
->SpareCompleted
== FTW_VALID_STATE
)) {
94 return EFI_ACCESS_DENIED
;
97 // IF former record has completed, THEN use next record
99 if (Record
->WriteCompleted
== FTW_VALID_STATE
) {
101 FtwLiteDevice
->FtwLastRecord
= Record
;
104 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
107 // Check if the input data can fit within the target block
109 if ((Offset
+*NumBytes
) > FtwLiteDevice
->SpareAreaLength
) {
110 return EFI_BAD_BUFFER_SIZE
;
113 // Check if there is enough free space for allocate a record
115 if ((MyOffset
+ WRITE_TOTAL_SIZE
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
116 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
117 if (EFI_ERROR (Status
)) {
118 DEBUG ((EFI_D_ERROR
, "FtwLite: Reclaim work space - %r", Status
));
123 // Get the FVB protocol by handle
125 Status
= FtwGetFvbByHandle (FvbHandle
, &Fvb
);
126 if (EFI_ERROR (Status
)) {
127 return EFI_NOT_FOUND
;
130 // Allocate a write record in workspace.
131 // Update Header->WriteAllocated as VALID
133 Status
= FtwUpdateFvState (
134 FtwLiteDevice
->FtwFvBlock
,
135 FtwLiteDevice
->FtwWorkSpaceLba
,
136 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
140 if (EFI_ERROR (Status
)) {
141 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Allocate record - %r\n", Status
));
145 Record
->WriteAllocated
= FTW_VALID_STATE
;
148 // Prepare data of write record, filling DevPath with memory mapped address.
150 DevPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
151 DevPtr
.MemMap
->Header
.Type
= HARDWARE_DEVICE_PATH
;
152 DevPtr
.MemMap
->Header
.SubType
= HW_MEMMAP_DP
;
153 SetDevicePathNodeLength (&DevPtr
.MemMap
->Header
, sizeof (MEMMAP_DEVICE_PATH
));
155 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
156 if (EFI_ERROR (Status
)) {
157 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Get FVB physical address - %r\n", Status
));
161 DevPtr
.MemMap
->MemoryType
= EfiMemoryMappedIO
;
162 DevPtr
.MemMap
->StartingAddress
= FvbPhysicalAddress
;
163 DevPtr
.MemMap
->EndingAddress
= FvbPhysicalAddress
+*NumBytes
;
168 Record
->Offset
= Offset
;
169 Record
->NumBytes
= *NumBytes
;
172 // Write the record to the work space.
174 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
175 MyLength
= FTW_LITE_RECORD_SIZE
;
177 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
178 FtwLiteDevice
->FtwFvBlock
,
179 FtwLiteDevice
->FtwWorkSpaceLba
,
180 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
184 if (EFI_ERROR (Status
)) {
188 // Record has been written to working block, then write data.
191 // Allocate a memory buffer
193 MyBufferSize
= FtwLiteDevice
->SpareAreaLength
;
194 MyBuffer
= AllocatePool (MyBufferSize
);
195 if (MyBuffer
== NULL
) {
196 return EFI_OUT_OF_RESOURCES
;
199 // Starting at Lba, if the number of the rest blocks on Fvb is less
200 // than NumberOfSpareBlock.
203 // Read all original data from target block to memory buffer
205 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Lba
)) {
207 // If target block falls into working block, we must follow the process of
208 // updating working block.
211 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
212 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
213 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
214 FtwLiteDevice
->FtwFvBlock
,
215 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
220 if (EFI_ERROR (Status
)) {
228 // Update Offset by adding the offset from the start LBA of working block to
229 // the target LBA. The target block can not span working block!
231 Offset
= (((UINTN
) (Lba
- FtwLiteDevice
->FtwWorkBlockLba
)) * FtwLiteDevice
->SizeOfSpareBlock
+ Offset
);
232 ASSERT ((Offset
+*NumBytes
) <= FtwLiteDevice
->SpareAreaLength
);
237 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
238 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
239 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
240 if (EFI_ERROR (Status
)) {
249 // Overwrite the updating range data with
250 // the input buffer content
252 CopyMem (MyBuffer
+ Offset
, Buffer
, *NumBytes
);
255 // Try to keep the content of spare block
256 // Save spare block into a spare backup memory buffer (Sparebuffer)
258 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
259 SpareBuffer
= AllocatePool (SpareBufferSize
);
260 if (SpareBuffer
== NULL
) {
262 return EFI_OUT_OF_RESOURCES
;
266 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
267 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
268 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
269 FtwLiteDevice
->FtwBackupFvb
,
270 FtwLiteDevice
->FtwSpareLba
+ Index
,
275 if (EFI_ERROR (Status
)) {
277 FreePool (SpareBuffer
);
284 // Write the memory buffer to spare block
285 // Don't forget to erase Flash first.
287 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
289 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
290 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
291 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
292 FtwLiteDevice
->FtwBackupFvb
,
293 FtwLiteDevice
->FtwSpareLba
+ Index
,
298 if (EFI_ERROR (Status
)) {
300 FreePool (SpareBuffer
);
312 // Set the SpareCompleteD in the FTW record,
314 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
315 Status
= FtwUpdateFvState (
316 FtwLiteDevice
->FtwFvBlock
,
317 FtwLiteDevice
->FtwWorkSpaceLba
,
318 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
321 if (EFI_ERROR (Status
)) {
322 FreePool (SpareBuffer
);
326 Record
->SpareCompleted
= FTW_VALID_STATE
;
329 // Since the content has already backuped in spare block, the write is
330 // guaranteed to be completed with fault tolerant manner.
332 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
333 if (EFI_ERROR (Status
)) {
334 FreePool (SpareBuffer
);
339 FtwLiteDevice
->FtwLastRecord
= Record
;
342 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
344 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
346 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
347 MyLength
= FtwLiteDevice
->SizeOfSpareBlock
;
348 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
349 FtwLiteDevice
->FtwBackupFvb
,
350 FtwLiteDevice
->FtwSpareLba
+ Index
,
355 if (EFI_ERROR (Status
)) {
356 FreePool (SpareBuffer
);
365 FreePool (SpareBuffer
);
369 "FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
380 Write a record with fault tolerant manner.
381 Since the content has already backuped in spare block, the write is
382 guaranteed to be completed with fault tolerant manner.
385 @param FtwLiteDevice The private data of FTW_LITE driver
386 @param Fvb The FVB protocol that provides services for
387 reading, writing, and erasing the target block.
389 @retval EFI_SUCCESS The function completed successfully
390 @retval EFI_ABORTED The function could not complete successfully
395 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
396 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
400 EFI_FTW_LITE_RECORD
*Record
;
401 EFI_LBA WorkSpaceLbaOffset
;
405 // Spare Complete but Destination not complete,
406 // Recover the targt block with the spare block.
408 Record
= FtwLiteDevice
->FtwLastRecord
;
411 // IF target block is working block, THEN Flush Spare Block To Working Block;
412 // ELSE IF target block is boot block, THEN Flush Spare Block To boot Block;
413 // ELSE flush spare block to normal target block.ENDIF
415 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Record
->Lba
)) {
417 // If target block is working block, Attention:
418 // it's required to set SPARE_COMPLETED to spare block.
420 WorkSpaceLbaOffset
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
;
421 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
422 Status
= FtwUpdateFvState (
423 FtwLiteDevice
->FtwBackupFvb
,
424 FtwLiteDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
425 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
428 ASSERT_EFI_ERROR (Status
);
430 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
431 } else if (IsBootBlock (FtwLiteDevice
, Fvb
, Record
->Lba
)) {
435 Status
= FlushSpareBlockToBootBlock (FtwLiteDevice
);
438 // Update blocks other than working block or boot block
440 Status
= FlushSpareBlockToTargetBlock (FtwLiteDevice
, Fvb
, Record
->Lba
);
443 ASSERT_EFI_ERROR (Status
);
446 // Set WriteCompleted flag in record
448 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
449 Status
= FtwUpdateFvState (
450 FtwLiteDevice
->FtwFvBlock
,
451 FtwLiteDevice
->FtwWorkSpaceLba
,
452 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
455 ASSERT_EFI_ERROR (Status
);
457 Record
->WriteCompleted
= FTW_VALID_STATE
;
463 Restarts a previously interrupted write. The caller must provide the
464 block protocol needed to complete the interrupted write.
467 @param FtwLiteDevice The private data of FTW_LITE driver
468 FvbHandle - The handle of FVB protocol that provides services for
469 reading, writing, and erasing the target block.
471 @retval EFI_SUCCESS The function completed successfully
472 @retval EFI_ACCESS_DENIED No pending writes exist
473 @retval EFI_NOT_FOUND FVB protocol not found by the handle
474 @retval EFI_ABORTED The function could not complete successfully
479 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
483 EFI_FTW_LITE_RECORD
*Record
;
484 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
485 EFI_DEV_PATH_PTR DevPathPtr
;
488 // Spare Completed but Destination not complete,
489 // Recover the targt block with the spare block.
491 Record
= FtwLiteDevice
->FtwLastRecord
;
494 // Only support memory mapped FVB device path by now.
496 DevPathPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
497 if (!((DevPathPtr
.MemMap
->Header
.Type
== HARDWARE_DEVICE_PATH
) && (DevPathPtr
.MemMap
->Header
.SubType
== HW_MEMMAP_DP
))
499 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: FVB Device Path is not memory mapped\n"));
503 Status
= GetFvbByAddress (DevPathPtr
.MemMap
->StartingAddress
, &Fvb
);
504 if (EFI_ERROR (Status
)) {
505 return EFI_NOT_FOUND
;
508 // Since the content has already backuped in spare block, the write is
509 // guaranteed to be completed with fault tolerant manner.
511 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
512 DEBUG ((EFI_D_FTW_INFO
, "FtwLite: Restart() - %r\n", Status
));
515 FtwLiteDevice
->FtwLastRecord
= Record
;
519 // This is restart, no need to keep spareblock content.
521 FtwEraseSpareBlock (FtwLiteDevice
);
528 Aborts all previous allocated writes.
531 @param FtwLiteDevice The private data of FTW_LITE driver
533 @retval EFI_SUCCESS The function completed successfully
534 @retval EFI_ABORTED The function could not complete successfully.
535 @retval EFI_NOT_FOUND No allocated writes exist.
540 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
546 if (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
== FTW_VALID_STATE
) {
547 return EFI_NOT_FOUND
;
550 // Update the complete state of the header as VALID and abort.
552 Offset
= (UINT8
*) FtwLiteDevice
->FtwLastRecord
- FtwLiteDevice
->FtwWorkSpace
;
553 Status
= FtwUpdateFvState (
554 FtwLiteDevice
->FtwFvBlock
,
555 FtwLiteDevice
->FtwWorkSpaceLba
,
556 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
559 if (EFI_ERROR (Status
)) {
563 FtwLiteDevice
->FtwLastRecord
->WriteCompleted
= FTW_VALID_STATE
;
565 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
568 // Erase the spare block
570 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
572 DEBUG ((EFI_D_FTW_INFO
, "FtwLite: Abort() success \n"));
577 This function is the entry point of the Fault Tolerant Write driver.
579 @param ImageHandle A handle for the image that is initializing this driver
580 @param SystemTable A pointer to the EFI system table
582 @retval EFI_SUCCESS FTW has finished the initialization
583 @retval EFI_ABORTED FTW initialization error
589 IN EFI_HANDLE ImageHandle
,
590 IN EFI_SYSTEM_TABLE
*SystemTable
593 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
595 EFI_HANDLE
*HandleBuffer
;
597 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
598 EFI_PHYSICAL_ADDRESS BaseAddress
;
599 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
600 EFI_FTW_LITE_RECORD
*Record
;
604 EFI_FV_BLOCK_MAP_ENTRY
*FvbMapEntry
;
608 // Allocate Private data of this driver, including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
610 FtwLiteDevice
= NULL
;
611 FtwLiteDevice
= AllocatePool (sizeof (EFI_FTW_LITE_DEVICE
) + FTW_WORK_SPACE_SIZE
);
612 if (FtwLiteDevice
!= NULL
) {
613 Status
= EFI_SUCCESS
;
615 Status
= EFI_OUT_OF_RESOURCES
;
618 ASSERT_EFI_ERROR (Status
);
620 ZeroMem (FtwLiteDevice
, sizeof (EFI_FTW_LITE_DEVICE
));
621 FtwLiteDevice
->Signature
= FTW_LITE_DEVICE_SIGNATURE
;
624 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
626 FtwLiteDevice
->FtwWorkSpace
= (UINT8
*) (FtwLiteDevice
+ 1);
627 FtwLiteDevice
->FtwWorkSpaceSize
= FTW_WORK_SPACE_SIZE
;
629 FtwLiteDevice
->FtwWorkSpace
,
630 FtwLiteDevice
->FtwWorkSpaceSize
,
633 FtwLiteDevice
->FtwWorkSpaceHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) FtwLiteDevice
->FtwWorkSpace
;
635 FtwLiteDevice
->FtwLastRecord
= NULL
;
637 FtwLiteDevice
->WorkSpaceAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwWorkingBase
);
638 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwWorkingSize
);
640 FtwLiteDevice
->SpareAreaAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwSpareBase
);
641 FtwLiteDevice
->SpareAreaLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwSpareSize
);
643 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
646 // Locate FVB protocol
648 Status
= gBS
->LocateHandleBuffer (
650 &gEfiFirmwareVolumeBlockProtocolGuid
,
655 ASSERT_EFI_ERROR (Status
);
657 ASSERT (HandleCount
> 0);
659 FtwLiteDevice
->FtwFvBlock
= NULL
;
660 FtwLiteDevice
->FtwBackupFvb
= NULL
;
661 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
662 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
663 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
664 Status
= gBS
->HandleProtocol (
666 &gEfiFirmwareVolumeBlockProtocolGuid
,
669 ASSERT_EFI_ERROR (Status
);
671 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
672 if (EFI_ERROR (Status
)) {
676 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
678 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
679 (FtwLiteDevice
->WorkSpaceAddress
<= (BaseAddress
+ FwVolHeader
->FvLength
))
681 FtwLiteDevice
->FtwFvBlock
= Fvb
;
683 // To get the LBA of work space
685 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
687 // FV may have multiple types of BlockLength
689 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
690 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
691 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
692 if (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
693 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
695 // Get the Work space size and Base(Offset)
697 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
698 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)));
713 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
714 (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FwVolHeader
->FvLength
))
716 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
718 // To get the LBA of spare
720 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
722 // FV may have multiple types of BlockLength
724 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
725 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
726 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
727 if (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
)) {
729 // Get the NumberOfSpareBlock and SizeOfSpareBlock
731 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
732 FtwLiteDevice
->SizeOfSpareBlock
= FvbMapEntry
->Length
;
733 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->SizeOfSpareBlock
;
735 // Check the range of spare area to make sure that it's in FV range
737 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
751 // Calculate the start LBA of working block. Working block is an area which
752 // contains working space in its last block and has the same size as spare
753 // block, unless there are not enough blocks before the block that contains
756 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
757 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
758 FtwLiteDevice
->FtwWorkBlockLba
= 0;
761 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
762 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
763 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
764 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
766 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
767 ASSERT_EFI_ERROR (Status
);
770 // Refresh workspace data from working block
772 Status
= WorkSpaceRefresh (FtwLiteDevice
);
773 ASSERT_EFI_ERROR (Status
);
776 // If the working block workspace is not valid, try the spare block
778 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
779 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace invalid, read from backup\n"));
781 // Read from spare block
783 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
784 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
785 FtwLiteDevice
->FtwBackupFvb
,
786 FtwLiteDevice
->FtwSpareLba
,
787 FtwLiteDevice
->FtwWorkSpaceBase
,
789 FtwLiteDevice
->FtwWorkSpace
791 ASSERT_EFI_ERROR (Status
);
794 // If spare block is valid, then replace working block content.
796 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
797 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
798 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart working block in Init() - %r\n", Status
));
799 ASSERT_EFI_ERROR (Status
);
801 FtwAbort (FtwLiteDevice
);
803 // Refresh work space.
805 Status
= WorkSpaceRefresh (FtwLiteDevice
);
806 if (EFI_ERROR (Status
)) {
810 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Both are invalid, init workspace\n"));
812 // If both are invalid, then initialize work space.
815 FtwLiteDevice
->FtwWorkSpace
,
816 FtwLiteDevice
->FtwWorkSpaceSize
,
819 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
821 // Initialize the work space
823 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, FALSE
);
825 if (EFI_ERROR (Status
)) {
831 // Hook the protocol API
833 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
836 // Install protocol interface
838 Status
= gBS
->InstallProtocolInterface (
839 &FtwLiteDevice
->Handle
,
840 &gEfiFaultTolerantWriteLiteProtocolGuid
,
841 EFI_NATIVE_INTERFACE
,
842 &FtwLiteDevice
->FtwLiteInstance
844 if (EFI_ERROR (Status
)) {
848 // If (!SpareCompleted) THEN Abort to rollback.
850 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
851 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
853 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
854 FtwAbort (FtwLiteDevice
);
857 // if (SpareCompleted) THEN Restart to fault tolerant write.
859 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
860 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
863 Status
= FtwRestart (FtwLiteDevice
);
864 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Restart last write - %r\n", Status
));
865 if (EFI_ERROR (Status
)) {
870 // To check the workspace buffer behind last records is EMPTY or not.
871 // If it's not EMPTY, FTW_LITE also need to call reclaim().
873 Record
= FtwLiteDevice
->FtwLastRecord
;
874 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
875 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
876 Offset
+= WRITE_TOTAL_SIZE
;
879 if (!IsErasedFlashBuffer (
881 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
882 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
884 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace is dirty, call reclaim...\n"));
885 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
886 if (EFI_ERROR (Status
)) {
887 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Workspace reclaim - %r\n", Status
));