3 This is a simple fault tolerant write driver.
5 This boot service protocol only provides fault tolerant write capability for
6 block devices. The protocol has internal non-volatile intermediate storage
7 of the data and private information. It should be able to recover
8 automatically from a critical fault, such as power failure.
10 The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
11 This work space is a memory copy of the work space on the Working Block,
12 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
14 The work space stores each write record as EFI_FTW_LITE_RECORD structure.
15 The spare block stores the write buffer before write to the target block.
17 The write record has three states to specify the different phase of write operation.
18 1) WRITE_ALLOCATED is that the record is allocated in write space.
19 The information of write operation is stored in write record structure.
20 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
21 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
23 This driver operates the data as the whole size of spare block.
24 It first read the SpareAreaLength data from the target block into the spare memory buffer.
25 Then copy the write buffer data into the spare memory buffer.
26 Then write the spare memory buffer into the spare block.
27 Final copy the data from the spare block to the target block.
29 To make this drive work well, the following conditions must be satisfied:
30 1. The write NumBytes data must be fit within Spare area.
31 Offset + NumBytes <= SpareAreaLength
32 2. The whole flash range has the same block size.
33 3. Working block is an area which contains working space in its last block and has the same size as spare block.
34 4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
35 5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
36 6. Any write data area (SpareAreaLength Area) which the data will be written into must be
37 in the single one Firmware Volume Block range which FVB protocol is produced on.
38 7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
39 The spare area must be enough large to store the write data before write them into the target range.
40 If one of them is not satisfied, FtwLiteWrite may fail.
41 Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
43 Copyright (c) 2006 - 2009, Intel Corporation
44 All rights reserved. This program and the accompanying materials
45 are licensed and made available under the terms and conditions of the BSD License
46 which accompanies this distribution. The full text of the license may be found at
47 http://opensource.org/licenses/bsd-license.php
49 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
50 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
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.
62 @param This The pointer to this protocol instance.
63 @param FvbHandle The handle of FVB protocol that provides services for
64 reading, writing, and erasing the target block.
65 @param Lba The logical block address of the target block.
66 @param Offset The offset within the target block to place the data.
67 @param NumBytes The number of bytes to write to the target block.
68 @param Buffer The data to write.
70 @retval EFI_SUCCESS The function completed successfully
71 @retval EFI_ABORTED The function could not complete successfully.
72 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
73 Offset + *NumBytes > SpareAreaLength.
74 @retval EFI_ACCESS_DENIED No writes have been allocated.
75 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
76 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
82 IN EFI_FTW_LITE_PROTOCOL
*This
,
83 IN EFI_HANDLE FvbHandle
,
86 IN OUT UINTN
*NumBytes
,
91 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
92 EFI_FTW_LITE_RECORD
*Record
;
93 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
94 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
99 UINTN SpareBufferSize
;
103 EFI_DEV_PATH_PTR DevPtr
;
105 // Refresh work space and get last record
107 FtwLiteDevice
= FTW_LITE_CONTEXT_FROM_THIS (This
);
108 Status
= WorkSpaceRefresh (FtwLiteDevice
);
109 if (EFI_ERROR (Status
)) {
113 Record
= FtwLiteDevice
->FtwLastRecord
;
116 // Check the flags of last write record
118 if ((Record
->WriteAllocated
== FTW_VALID_STATE
) || (Record
->SpareCompleted
== FTW_VALID_STATE
)) {
119 return EFI_ACCESS_DENIED
;
122 // IF former record has completed, THEN use next record
124 if (Record
->WriteCompleted
== FTW_VALID_STATE
) {
126 FtwLiteDevice
->FtwLastRecord
= Record
;
129 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
132 // Check if the input data can fit within the target block
134 if ((Offset
+*NumBytes
) > FtwLiteDevice
->SpareAreaLength
) {
135 *NumBytes
= FtwLiteDevice
->SpareAreaLength
- Offset
;
136 return EFI_BAD_BUFFER_SIZE
;
139 // Check if there is enough free space for allocate a record
141 if ((MyOffset
+ FTW_LITE_RECORD_SIZE
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
142 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
143 if (EFI_ERROR (Status
)) {
144 DEBUG ((EFI_D_ERROR
, "FtwLite: Reclaim work space - %r", Status
));
149 // Get the FVB protocol by handle
151 Status
= FtwGetFvbByHandle (FvbHandle
, &Fvb
);
152 if (EFI_ERROR (Status
)) {
153 return EFI_NOT_FOUND
;
156 // Allocate a write record in workspace.
157 // Update Header->WriteAllocated as VALID
159 Status
= FtwUpdateFvState (
160 FtwLiteDevice
->FtwFvBlock
,
161 FtwLiteDevice
->FtwWorkSpaceLba
,
162 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
166 if (EFI_ERROR (Status
)) {
167 DEBUG ((EFI_D_ERROR
, "FtwLite: Allocate record - %r\n", Status
));
171 Record
->WriteAllocated
= FTW_VALID_STATE
;
174 // Prepare data of write record, filling DevPath with memory mapped address.
176 DevPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
177 DevPtr
.MemMap
->Header
.Type
= HARDWARE_DEVICE_PATH
;
178 DevPtr
.MemMap
->Header
.SubType
= HW_MEMMAP_DP
;
179 SetDevicePathNodeLength (&DevPtr
.MemMap
->Header
, sizeof (MEMMAP_DEVICE_PATH
));
181 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
182 if (EFI_ERROR (Status
)) {
183 DEBUG ((EFI_D_ERROR
, "FtwLite: Get FVB physical address - %r\n", Status
));
187 DevPtr
.MemMap
->MemoryType
= EfiMemoryMappedIO
;
188 DevPtr
.MemMap
->StartingAddress
= FvbPhysicalAddress
;
189 DevPtr
.MemMap
->EndingAddress
= FvbPhysicalAddress
+*NumBytes
;
194 Record
->Offset
= Offset
;
195 Record
->NumBytes
= *NumBytes
;
198 // Write the record to the work space.
200 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
201 MyLength
= FTW_LITE_RECORD_SIZE
;
203 Status
= FtwLiteDevice
->FtwFvBlock
->Write (
204 FtwLiteDevice
->FtwFvBlock
,
205 FtwLiteDevice
->FtwWorkSpaceLba
,
206 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
210 if (EFI_ERROR (Status
)) {
214 // Record has been written to working block, then write data.
217 // Allocate a memory buffer
219 MyBufferSize
= FtwLiteDevice
->SpareAreaLength
;
220 MyBuffer
= AllocatePool (MyBufferSize
);
221 if (MyBuffer
== NULL
) {
222 return EFI_OUT_OF_RESOURCES
;
225 // Starting at Lba, if the number of the rest blocks on Fvb is less
226 // than NumberOfSpareBlock.
229 // Read all original data from target block to memory buffer
231 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Lba
)) {
233 // If target block falls into working block, we must follow the process of
234 // updating working block.
237 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
238 MyLength
= FtwLiteDevice
->BlockSize
;
239 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
240 FtwLiteDevice
->FtwFvBlock
,
241 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
246 if (EFI_ERROR (Status
)) {
254 // Update Offset by adding the offset from the start LBA of working block to
255 // the target LBA. The target block can not span working block!
257 Offset
= (((UINTN
) (Lba
- FtwLiteDevice
->FtwWorkBlockLba
)) * FtwLiteDevice
->BlockSize
+ Offset
);
258 ASSERT ((Offset
+*NumBytes
) <= FtwLiteDevice
->SpareAreaLength
);
263 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
264 MyLength
= FtwLiteDevice
->BlockSize
;
265 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
266 if (EFI_ERROR (Status
)) {
275 // Overwrite the updating range data with
276 // the input buffer content
278 CopyMem (MyBuffer
+ Offset
, Buffer
, *NumBytes
);
281 // Try to keep the content of spare block
282 // Save spare block into a spare backup memory buffer (Sparebuffer)
284 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
285 SpareBuffer
= AllocatePool (SpareBufferSize
);
286 if (SpareBuffer
== NULL
) {
288 return EFI_OUT_OF_RESOURCES
;
292 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
293 MyLength
= FtwLiteDevice
->BlockSize
;
294 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
295 FtwLiteDevice
->FtwBackupFvb
,
296 FtwLiteDevice
->FtwSpareLba
+ Index
,
301 if (EFI_ERROR (Status
)) {
303 FreePool (SpareBuffer
);
310 // Write the memory buffer to spare block
311 // Don't forget to erase Flash first.
313 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
315 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
316 MyLength
= FtwLiteDevice
->BlockSize
;
317 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
318 FtwLiteDevice
->FtwBackupFvb
,
319 FtwLiteDevice
->FtwSpareLba
+ Index
,
324 if (EFI_ERROR (Status
)) {
326 FreePool (SpareBuffer
);
338 // Set the SpareComplete in the FTW record,
340 MyOffset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
341 Status
= FtwUpdateFvState (
342 FtwLiteDevice
->FtwFvBlock
,
343 FtwLiteDevice
->FtwWorkSpaceLba
,
344 FtwLiteDevice
->FtwWorkSpaceBase
+ MyOffset
,
347 if (EFI_ERROR (Status
)) {
348 FreePool (SpareBuffer
);
352 Record
->SpareCompleted
= FTW_VALID_STATE
;
355 // Since the content has already backuped in spare block, the write is
356 // guaranteed to be completed with fault tolerant manner.
358 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
359 if (EFI_ERROR (Status
)) {
360 FreePool (SpareBuffer
);
365 FtwLiteDevice
->FtwLastRecord
= Record
;
368 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
370 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
372 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
373 MyLength
= FtwLiteDevice
->BlockSize
;
374 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
375 FtwLiteDevice
->FtwBackupFvb
,
376 FtwLiteDevice
->FtwSpareLba
+ Index
,
381 if (EFI_ERROR (Status
)) {
382 FreePool (SpareBuffer
);
391 FreePool (SpareBuffer
);
395 "FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
406 Write a record with fault tolerant manner.
407 Since the content has already backuped in spare block, the write is
408 guaranteed to be completed with fault tolerant manner.
411 @param FtwLiteDevice The private data of FTW_LITE driver
412 @param Fvb The FVB protocol that provides services for
413 reading, writing, and erasing the target block.
415 @retval EFI_SUCCESS The function completed successfully
416 @retval EFI_ABORTED The function could not complete successfully
421 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
422 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
426 EFI_FTW_LITE_RECORD
*Record
;
427 EFI_LBA WorkSpaceLbaOffset
;
431 // Spare Complete but Destination not complete,
432 // Recover the targt block with the spare block.
434 Record
= FtwLiteDevice
->FtwLastRecord
;
437 // IF target block is working block, THEN Flush Spare Block To Working Block;
438 // ELSE flush spare block to normal target block.ENDIF
440 if (IsInWorkingBlock (FtwLiteDevice
, Fvb
, Record
->Lba
)) {
442 // If target block is working block, Attention:
443 // it's required to set SPARE_COMPLETED to spare block.
445 WorkSpaceLbaOffset
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
;
446 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
447 Status
= FtwUpdateFvState (
448 FtwLiteDevice
->FtwBackupFvb
,
449 FtwLiteDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
450 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
453 ASSERT_EFI_ERROR (Status
);
455 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
458 // Update blocks other than working block
460 Status
= FlushSpareBlockToTargetBlock (FtwLiteDevice
, Fvb
, Record
->Lba
);
463 ASSERT_EFI_ERROR (Status
);
466 // Set WriteCompleted flag in record
468 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
469 Status
= FtwUpdateFvState (
470 FtwLiteDevice
->FtwFvBlock
,
471 FtwLiteDevice
->FtwWorkSpaceLba
,
472 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
475 ASSERT_EFI_ERROR (Status
);
477 Record
->WriteCompleted
= FTW_VALID_STATE
;
483 Restarts a previously interrupted write. The caller must provide the
484 block protocol needed to complete the interrupted write.
487 @param FtwLiteDevice The private data of FTW_LITE driver
488 FvbHandle - The handle of FVB protocol that provides services for
489 reading, writing, and erasing the target block.
491 @retval EFI_SUCCESS The function completed successfully
492 @retval EFI_ACCESS_DENIED No pending writes exist
493 @retval EFI_NOT_FOUND FVB protocol not found by the handle
494 @retval EFI_ABORTED The function could not complete successfully
499 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
503 EFI_FTW_LITE_RECORD
*Record
;
504 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
505 EFI_DEV_PATH_PTR DevPathPtr
;
508 // Spare Completed but Destination not complete,
509 // Recover the targt block with the spare block.
511 Record
= FtwLiteDevice
->FtwLastRecord
;
514 // Only support memory mapped FVB device path by now.
516 DevPathPtr
.MemMap
= (MEMMAP_DEVICE_PATH
*) &Record
->DevPath
;
517 if (!((DevPathPtr
.MemMap
->Header
.Type
== HARDWARE_DEVICE_PATH
) && (DevPathPtr
.MemMap
->Header
.SubType
== HW_MEMMAP_DP
))
519 DEBUG ((EFI_D_ERROR
, "FtwLite: FVB Device Path is not memory mapped\n"));
523 Status
= GetFvbByAddress (DevPathPtr
.MemMap
->StartingAddress
, &Fvb
);
524 if (EFI_ERROR (Status
)) {
525 return EFI_NOT_FOUND
;
528 // Since the content has already backuped in spare block, the write is
529 // guaranteed to be completed with fault tolerant manner.
531 Status
= FtwWriteRecord (FtwLiteDevice
, Fvb
);
532 DEBUG ((EFI_D_INFO
, "FtwLite: Restart() - %r\n", Status
));
535 FtwLiteDevice
->FtwLastRecord
= Record
;
539 // This is restart, no need to keep spareblock content.
541 FtwEraseSpareBlock (FtwLiteDevice
);
548 Aborts all previous allocated writes.
551 @param FtwLiteDevice The private data of FTW_LITE driver
553 @retval EFI_SUCCESS The function completed successfully
554 @retval EFI_ABORTED The function could not complete successfully.
555 @retval EFI_NOT_FOUND No allocated writes exist.
560 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
566 if (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
== FTW_VALID_STATE
) {
567 return EFI_NOT_FOUND
;
570 // Update the complete state of the header as VALID and abort.
572 Offset
= (UINT8
*) FtwLiteDevice
->FtwLastRecord
- FtwLiteDevice
->FtwWorkSpace
;
573 Status
= FtwUpdateFvState (
574 FtwLiteDevice
->FtwFvBlock
,
575 FtwLiteDevice
->FtwWorkSpaceLba
,
576 FtwLiteDevice
->FtwWorkSpaceBase
+ Offset
,
579 if (EFI_ERROR (Status
)) {
583 FtwLiteDevice
->FtwLastRecord
->WriteCompleted
= FTW_VALID_STATE
;
585 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
588 // Erase the spare block
590 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
592 DEBUG ((EFI_D_INFO
, "FtwLite: Abort() success \n"));
597 This function is the entry point of the Fault Tolerant Write driver.
599 @param ImageHandle A handle for the image that is initializing this driver
600 @param SystemTable A pointer to the EFI system table
602 @retval EFI_SUCCESS FTW has finished the initialization
603 @retval EFI_ABORTED FTW initialization error
609 IN EFI_HANDLE ImageHandle
,
610 IN EFI_SYSTEM_TABLE
*SystemTable
613 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
615 EFI_HANDLE
*HandleBuffer
;
617 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
618 EFI_PHYSICAL_ADDRESS BaseAddress
;
619 EFI_FTW_LITE_DEVICE
*FtwLiteDevice
;
620 EFI_FTW_LITE_RECORD
*Record
;
624 EFI_FV_BLOCK_MAP_ENTRY
*FvbMapEntry
;
627 // Allocate Private data of this driver, including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
629 FtwLiteDevice
= NULL
;
630 FtwLiteDevice
= AllocatePool (sizeof (EFI_FTW_LITE_DEVICE
) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize
));
631 ASSERT (FtwLiteDevice
!= NULL
);
633 ZeroMem (FtwLiteDevice
, sizeof (EFI_FTW_LITE_DEVICE
));
634 FtwLiteDevice
->Signature
= FTW_LITE_DEVICE_SIGNATURE
;
637 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
639 FtwLiteDevice
->FtwWorkSpace
= (UINT8
*) (FtwLiteDevice
+ 1);
640 FtwLiteDevice
->FtwWorkSpaceHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) FtwLiteDevice
->FtwWorkSpace
;
641 FtwLiteDevice
->FtwLastRecord
= NULL
;
643 FtwLiteDevice
->WorkSpaceAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwWorkingBase
);
644 FtwLiteDevice
->WorkSpaceLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwWorkingSize
);
646 FtwLiteDevice
->SpareAreaAddress
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageFtwSpareBase
);
647 FtwLiteDevice
->SpareAreaLength
= (UINTN
) PcdGet32 (PcdFlashNvStorageFtwSpareSize
);
649 ASSERT ((FtwLiteDevice
->WorkSpaceLength
!= 0) && (FtwLiteDevice
->SpareAreaLength
!= 0));
652 // Locate FVB protocol
654 Status
= gBS
->LocateHandleBuffer (
656 &gEfiFirmwareVolumeBlockProtocolGuid
,
661 ASSERT_EFI_ERROR (Status
);
663 ASSERT (HandleCount
> 0);
665 FtwLiteDevice
->FtwFvBlock
= NULL
;
666 FtwLiteDevice
->FtwBackupFvb
= NULL
;
667 FtwLiteDevice
->FtwWorkSpaceLba
= (EFI_LBA
) (-1);
668 FtwLiteDevice
->FtwSpareLba
= (EFI_LBA
) (-1);
669 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
670 Status
= gBS
->HandleProtocol (
672 &gEfiFirmwareVolumeBlockProtocolGuid
,
675 ASSERT_EFI_ERROR (Status
);
677 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
678 if (EFI_ERROR (Status
)) {
682 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) BaseAddress
);
684 if ((FtwLiteDevice
->WorkSpaceAddress
>= BaseAddress
) &&
685 ((FtwLiteDevice
->WorkSpaceAddress
+ FtwLiteDevice
->WorkSpaceLength
) <= (BaseAddress
+ FwVolHeader
->FvLength
))
687 FtwLiteDevice
->FtwFvBlock
= Fvb
;
689 // To get the LBA of work space
691 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
693 // FV may have multiple types of BlockLength
695 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
696 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
697 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
698 if ((FtwLiteDevice
->WorkSpaceAddress
>= (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)))
699 && (FtwLiteDevice
->WorkSpaceAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
))) {
700 FtwLiteDevice
->FtwWorkSpaceLba
= LbaIndex
- 1;
702 // Get the Work space size and Base(Offset)
704 FtwLiteDevice
->FtwWorkSpaceSize
= FtwLiteDevice
->WorkSpaceLength
;
705 FtwLiteDevice
->FtwWorkSpaceBase
= (UINTN
) (FtwLiteDevice
->WorkSpaceAddress
- (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)));
712 if (LbaIndex
<= FvbMapEntry
->NumBlocks
) {
714 // Work space range is found.
726 if ((FtwLiteDevice
->SpareAreaAddress
>= BaseAddress
) &&
727 ((FtwLiteDevice
->SpareAreaAddress
+ FtwLiteDevice
->SpareAreaLength
) <= (BaseAddress
+ FwVolHeader
->FvLength
))
729 FtwLiteDevice
->FtwBackupFvb
= Fvb
;
731 // To get the LBA of spare
733 if ((FwVolHeader
->FvLength
) > (FwVolHeader
->HeaderLength
)) {
735 // FV may have multiple types of BlockLength
737 FvbMapEntry
= &FwVolHeader
->BlockMap
[0];
738 while (!((FvbMapEntry
->NumBlocks
== 0) && (FvbMapEntry
->Length
== 0))) {
739 for (LbaIndex
= 1; LbaIndex
<= FvbMapEntry
->NumBlocks
; LbaIndex
+= 1) {
740 if ((FtwLiteDevice
->SpareAreaAddress
>= (BaseAddress
+ FvbMapEntry
->Length
* (LbaIndex
- 1)))
741 && (FtwLiteDevice
->SpareAreaAddress
< (BaseAddress
+ FvbMapEntry
->Length
* LbaIndex
))) {
743 // Get the NumberOfSpareBlock and BlockSize
745 FtwLiteDevice
->FtwSpareLba
= LbaIndex
- 1;
746 FtwLiteDevice
->BlockSize
= FvbMapEntry
->Length
;
747 FtwLiteDevice
->NumberOfSpareBlock
= FtwLiteDevice
->SpareAreaLength
/ FtwLiteDevice
->BlockSize
;
749 // Check the range of spare area to make sure that it's in FV range
752 ASSERT ((FtwLiteDevice
->FtwSpareLba
+ FtwLiteDevice
->NumberOfSpareBlock
) <= FvbMapEntry
->NumBlocks
);
756 if (LbaIndex
<= FvbMapEntry
->NumBlocks
) {
758 // Spare FV range is found.
772 // Calculate the start LBA of working block. Working block is an area which
773 // contains working space in its last block and has the same size as spare
774 // block, unless there are not enough blocks before the block that contains
777 FtwLiteDevice
->FtwWorkBlockLba
= FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->NumberOfSpareBlock
+ 1;
778 if ((INT64
) (FtwLiteDevice
->FtwWorkBlockLba
) < 0) {
779 DEBUG ((EFI_D_ERROR
, "FtwLite: The spare block range is too large than the working block range!\n"));
780 FreePool (FtwLiteDevice
);
784 if ((FtwLiteDevice
->FtwFvBlock
== NULL
) ||
785 (FtwLiteDevice
->FtwBackupFvb
== NULL
) ||
786 (FtwLiteDevice
->FtwWorkSpaceLba
== (EFI_LBA
) (-1)) ||
787 (FtwLiteDevice
->FtwSpareLba
== (EFI_LBA
) (-1))
789 DEBUG ((EFI_D_ERROR
, "FtwLite: Working or spare FVB not ready\n"));
790 FreePool (FtwLiteDevice
);
795 // Refresh workspace data from working block
797 Status
= WorkSpaceRefresh (FtwLiteDevice
);
798 ASSERT_EFI_ERROR (Status
);
801 // If the working block workspace is not valid, try the spare block
803 if (!IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
804 DEBUG ((EFI_D_ERROR
, "FtwLite: Workspace invalid, read from backup\n"));
806 // Read from spare block
808 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
809 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
810 FtwLiteDevice
->FtwBackupFvb
,
811 FtwLiteDevice
->FtwSpareLba
,
812 FtwLiteDevice
->FtwWorkSpaceBase
,
814 FtwLiteDevice
->FtwWorkSpace
816 ASSERT_EFI_ERROR (Status
);
819 // If spare block is valid, then replace working block content.
821 if (IsValidWorkSpace (FtwLiteDevice
->FtwWorkSpaceHeader
)) {
822 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
823 DEBUG ((EFI_D_ERROR
, "FtwLite: Restart working block in Init() - %r\n", Status
));
824 ASSERT_EFI_ERROR (Status
);
826 FtwAbort (FtwLiteDevice
);
828 // Refresh work space.
830 Status
= WorkSpaceRefresh (FtwLiteDevice
);
831 if (EFI_ERROR (Status
)) {
832 FreePool (FtwLiteDevice
);
836 DEBUG ((EFI_D_ERROR
, "FtwLite: Both are invalid, init workspace\n"));
838 // If both are invalid, then initialize work space.
841 FtwLiteDevice
->FtwWorkSpace
,
842 FtwLiteDevice
->FtwWorkSpaceSize
,
845 InitWorkSpaceHeader (FtwLiteDevice
->FtwWorkSpaceHeader
);
847 // Initialize the work space
849 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, FALSE
);
851 if (EFI_ERROR (Status
)) {
852 FreePool (FtwLiteDevice
);
858 // Hook the protocol API
860 FtwLiteDevice
->FtwLiteInstance
.Write
= FtwLiteWrite
;
863 // Install protocol interface
865 Status
= gBS
->InstallProtocolInterface (
866 &FtwLiteDevice
->Handle
,
867 &gEfiFaultTolerantWriteLiteProtocolGuid
,
868 EFI_NATIVE_INTERFACE
,
869 &FtwLiteDevice
->FtwLiteInstance
871 if (EFI_ERROR (Status
)) {
872 FreePool (FtwLiteDevice
);
876 // If (!SpareCompleted) THEN Abort to rollback.
878 if ((FtwLiteDevice
->FtwLastRecord
->WriteAllocated
== FTW_VALID_STATE
) &&
879 (FtwLiteDevice
->FtwLastRecord
->SpareCompleted
!= FTW_VALID_STATE
)
881 DEBUG ((EFI_D_ERROR
, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
882 FtwAbort (FtwLiteDevice
);
885 // if (SpareCompleted) THEN Restart to fault tolerant write.
887 if ((FtwLiteDevice
->FtwLastRecord
->SpareCompleted
== FTW_VALID_STATE
) &&
888 (FtwLiteDevice
->FtwLastRecord
->WriteCompleted
!= FTW_VALID_STATE
)
891 Status
= FtwRestart (FtwLiteDevice
);
892 DEBUG ((EFI_D_ERROR
, "FtwLite: Restart last write - %r\n", Status
));
893 if (EFI_ERROR (Status
)) {
898 // To check the workspace buffer behind last records is EMPTY or not.
899 // If it's not EMPTY, FTW_LITE also need to call reclaim().
901 Record
= FtwLiteDevice
->FtwLastRecord
;
902 Offset
= (UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
;
903 if (FtwLiteDevice
->FtwWorkSpace
[Offset
] != FTW_ERASED_BYTE
) {
904 Offset
+= FTW_LITE_RECORD_SIZE
;
907 if (!IsErasedFlashBuffer (
909 FtwLiteDevice
->FtwWorkSpace
+ Offset
,
910 FtwLiteDevice
->FtwWorkSpaceSize
- Offset
912 DEBUG ((EFI_D_ERROR
, "FtwLite: Workspace is dirty, call reclaim...\n"));
913 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
914 if (EFI_ERROR (Status
)) {
915 DEBUG ((EFI_D_ERROR
, "FtwLite: Workspace reclaim - %r\n", Status
));
916 FreePool (FtwLiteDevice
);