3 These are the common Fault Tolerant Write (FTW) functions that are shared
4 by DXE FTW driver and SMM FTW driver.
6 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "FaultTolerantWrite.h"
20 // Fault Tolerant Write Protocol API
23 Query the largest block that may be updated in a fault tolerant manner.
26 @param This The pointer to this protocol instance.
27 @param BlockSize A pointer to a caller allocated UINTN that is updated to
28 indicate the size of the largest block that can be updated.
30 @return EFI_SUCCESS The function completed successfully
36 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
40 EFI_FTW_DEVICE
*FtwDevice
;
42 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
43 return EFI_UNSUPPORTED
;
46 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
48 *BlockSize
= FtwDevice
->SpareAreaLength
;
54 Allocates space for the protocol to maintain information about writes.
55 Since writes must be completed in a fault tolerant manner and multiple
56 updates will require more resources to be successful, this function
57 enables the protocol to ensure that enough space exists to track
58 information about the upcoming writes.
60 All writes must be completed or aborted before another fault tolerant write can occur.
62 @param This The pointer to this protocol instance.
63 @param CallerId The GUID identifying the write.
64 @param PrivateDataSize The size of the caller's private data
65 that must be recorded for each write.
66 @param NumberOfWrites The number of fault tolerant block writes
67 that will need to occur.
69 @return EFI_SUCCESS The function completed successfully
70 @retval EFI_ABORTED The function could not complete successfully.
71 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
77 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
78 IN EFI_GUID
*CallerId
,
79 IN UINTN PrivateDataSize
,
80 IN UINTN NumberOfWrites
85 EFI_FTW_DEVICE
*FtwDevice
;
86 EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwHeader
;
88 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
90 Status
= WorkSpaceRefresh (FtwDevice
);
91 if (EFI_ERROR (Status
)) {
95 // Check if there is enough space for the coming allocation
97 if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceHeader
->WriteQueueSize
) {
98 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId
));
99 return EFI_BUFFER_TOO_SMALL
;
102 // Find the last write header and record.
103 // If the FtwHeader is complete, skip the completed last write header/records
105 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
108 // Previous write has not completed, access denied.
110 if ((FtwHeader
->HeaderAllocated
== FTW_VALID_STATE
) || (FtwHeader
->WritesAllocated
== FTW_VALID_STATE
)) {
111 return EFI_ACCESS_DENIED
;
114 // If workspace is not enough, then reclaim workspace
116 Offset
= (UINT8
*) FtwHeader
- (UINT8
*) FtwDevice
->FtwWorkSpace
;
117 if (Offset
+ FTW_WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceSize
) {
118 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
119 if (EFI_ERROR (Status
)) {
123 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
126 // Prepare FTW write header,
127 // overwrite the buffer and write to workspace.
129 FtwHeader
->WritesAllocated
= FTW_INVALID_STATE
;
130 FtwHeader
->Complete
= FTW_INVALID_STATE
;
131 CopyMem (&FtwHeader
->CallerId
, CallerId
, sizeof (EFI_GUID
));
132 FtwHeader
->NumberOfWrites
= NumberOfWrites
;
133 FtwHeader
->PrivateDataSize
= PrivateDataSize
;
134 FtwHeader
->HeaderAllocated
= FTW_VALID_STATE
;
136 Status
= WriteWorkSpaceData (
137 FtwDevice
->FtwFvBlock
,
138 FtwDevice
->WorkBlockSize
,
139 FtwDevice
->FtwWorkSpaceLba
,
140 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
141 sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
),
144 if (EFI_ERROR (Status
)) {
148 // Update Header->WriteAllocated as VALID
150 Status
= FtwUpdateFvState (
151 FtwDevice
->FtwFvBlock
,
152 FtwDevice
->WorkBlockSize
,
153 FtwDevice
->FtwWorkSpaceLba
,
154 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
157 if (EFI_ERROR (Status
)) {
163 "Ftw: Allocate() success, Caller:%g, # %d\n",
173 Write a record with fault tolerant manner.
174 Since the content has already backuped in spare block, the write is
175 guaranteed to be completed with fault tolerant manner.
177 @param This The pointer to this protocol instance.
178 @param Fvb The FVB protocol that provides services for
179 reading, writing, and erasing the target block.
180 @param BlockSize The size of the block.
182 @retval EFI_SUCCESS The function completed successfully
183 @retval EFI_ABORTED The function could not complete successfully
188 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
189 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
194 EFI_FTW_DEVICE
*FtwDevice
;
195 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
196 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
198 UINTN NumberOfWriteBlocks
;
200 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
203 // Spare Complete but Destination not complete,
204 // Recover the target block with the spare block.
206 Header
= FtwDevice
->FtwLastWriteHeader
;
207 Record
= FtwDevice
->FtwLastWriteRecord
;
210 // IF target block is working block, THEN Flush Spare Block To Working Block;
211 // ELSE flush spare block to target block, which may be boot block after all.
213 if (IsWorkingBlock (FtwDevice
, Fvb
, Record
->Lba
)) {
215 // If target block is working block,
216 // it also need to set SPARE_COMPLETED to spare block.
218 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
219 Status
= FtwUpdateFvState (
220 FtwDevice
->FtwBackupFvb
,
221 FtwDevice
->SpareBlockSize
,
222 FtwDevice
->FtwSpareLba
+ FtwDevice
->FtwWorkSpaceLbaInSpare
,
223 FtwDevice
->FtwWorkSpaceBaseInSpare
+ Offset
,
226 if (EFI_ERROR (Status
)) {
230 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
231 } else if (IsBootBlock (FtwDevice
, Fvb
)) {
235 Status
= FlushSpareBlockToBootBlock (FtwDevice
);
238 // Update blocks other than working block or boot block
240 NumberOfWriteBlocks
= FTW_BLOCKS ((UINTN
) (Record
->Offset
+ Record
->Length
), BlockSize
);
241 Status
= FlushSpareBlockToTargetBlock (FtwDevice
, Fvb
, Record
->Lba
, BlockSize
, NumberOfWriteBlocks
);
244 if (EFI_ERROR (Status
)) {
248 // Record the DestionationComplete in record
250 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
251 Status
= FtwUpdateFvState (
252 FtwDevice
->FtwFvBlock
,
253 FtwDevice
->WorkBlockSize
,
254 FtwDevice
->FtwWorkSpaceLba
,
255 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
258 if (EFI_ERROR (Status
)) {
262 Record
->DestinationComplete
= FTW_VALID_STATE
;
265 // If this is the last Write in these write sequence,
266 // set the complete flag of write header.
268 if (IsLastRecordOfWrites (Header
, Record
)) {
269 Offset
= (UINT8
*) Header
- FtwDevice
->FtwWorkSpace
;
270 Status
= FtwUpdateFvState (
271 FtwDevice
->FtwFvBlock
,
272 FtwDevice
->WorkBlockSize
,
273 FtwDevice
->FtwWorkSpaceLba
,
274 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
277 Header
->Complete
= FTW_VALID_STATE
;
278 if (EFI_ERROR (Status
)) {
287 Starts a target block update. This function will record data about write
288 in fault tolerant storage and will complete the write in a recoverable
289 manner, ensuring at all times that either the original contents or
290 the modified contents are available.
292 @param This The pointer to this protocol instance.
293 @param Lba The logical block address of the target block.
294 @param Offset The offset within the target block to place the data.
295 @param Length The number of bytes to write to the target block.
296 @param PrivateData A pointer to private data that the caller requires to
297 complete any pending writes in the event of a fault.
298 @param FvBlockHandle The handle of FVB protocol that provides services for
299 reading, writing, and erasing the target block.
300 @param Buffer The data to write.
302 @retval EFI_SUCCESS The function completed successfully
303 @retval EFI_ABORTED The function could not complete successfully.
304 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
305 Offset + *NumBytes > SpareAreaLength.
306 @retval EFI_ACCESS_DENIED No writes have been allocated.
307 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
308 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
314 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
318 IN VOID
*PrivateData
,
319 IN EFI_HANDLE FvBlockHandle
,
324 EFI_FTW_DEVICE
*FtwDevice
;
325 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
326 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
327 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
332 UINTN SpareBufferSize
;
336 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
338 UINTN NumberOfBlocks
;
339 UINTN NumberOfWriteBlocks
;
342 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
344 Status
= WorkSpaceRefresh (FtwDevice
);
345 if (EFI_ERROR (Status
)) {
349 Header
= FtwDevice
->FtwLastWriteHeader
;
350 Record
= FtwDevice
->FtwLastWriteRecord
;
352 if (IsErasedFlashBuffer ((UINT8
*) Header
, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
))) {
353 if (PrivateData
== NULL
) {
355 // Ftw Write Header is not allocated.
356 // No additional private data, the private data size is zero. Number of record can be set to 1.
358 Status
= FtwAllocate (This
, &gEfiCallerIdGuid
, 0, 1);
359 if (EFI_ERROR (Status
)) {
364 // Ftw Write Header is not allocated
365 // Additional private data is not NULL, the private data size can't be determined.
367 DEBUG ((EFI_D_ERROR
, "Ftw: no allocates space for write record!\n"));
368 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate service should be called before Write service!\n"));
369 return EFI_NOT_READY
;
374 // If Record is out of the range of Header, return access denied.
376 if (((UINTN
)((UINT8
*) Record
- (UINT8
*) Header
)) > FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
- 1, Header
->PrivateDataSize
)) {
377 return EFI_ACCESS_DENIED
;
381 // Check the COMPLETE flag of last write header
383 if (Header
->Complete
== FTW_VALID_STATE
) {
384 return EFI_ACCESS_DENIED
;
387 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
388 return EFI_ACCESS_DENIED
;
391 if ((Record
->SpareComplete
== FTW_VALID_STATE
) && (Record
->DestinationComplete
!= FTW_VALID_STATE
)) {
392 return EFI_NOT_READY
;
396 // Get the FVB protocol by handle
398 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
399 if (EFI_ERROR (Status
)) {
400 return EFI_NOT_FOUND
;
403 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
404 if (EFI_ERROR (Status
)) {
405 DEBUG ((EFI_D_ERROR
, "Ftw: Write(), Get FVB physical address - %r\n", Status
));
410 // Now, one FVB has one type of BlockSize.
412 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
413 if (EFI_ERROR (Status
)) {
414 DEBUG ((EFI_D_ERROR
, "Ftw: Write(), Get block size - %r\n", Status
));
418 NumberOfWriteBlocks
= FTW_BLOCKS (Offset
+ Length
, BlockSize
);
419 DEBUG ((EFI_D_INFO
, "Ftw: Write(), BlockSize - 0x%x, NumberOfWriteBlock - 0x%x\n", BlockSize
, NumberOfWriteBlocks
));
420 WriteLength
= NumberOfWriteBlocks
* BlockSize
;
423 // Check if the input data can fit within the spare block.
425 if (WriteLength
> FtwDevice
->SpareAreaLength
) {
426 return EFI_BAD_BUFFER_SIZE
;
430 // Set BootBlockUpdate FLAG if it's updating boot block.
432 if (IsBootBlock (FtwDevice
, Fvb
)) {
433 Record
->BootBlockUpdate
= FTW_VALID_STATE
;
435 // Boot Block and Spare Block should have same block size and block numbers.
437 ASSERT ((BlockSize
== FtwDevice
->SpareBlockSize
) && (NumberOfWriteBlocks
== FtwDevice
->NumberOfSpareBlock
));
440 // Write the record to the work space.
443 Record
->Offset
= Offset
;
444 Record
->Length
= Length
;
445 Record
->RelativeOffset
= (INT64
) (FvbPhysicalAddress
+ (UINTN
) Lba
* BlockSize
) - (INT64
) FtwDevice
->SpareAreaAddress
;
446 if (PrivateData
!= NULL
) {
447 CopyMem ((Record
+ 1), PrivateData
, (UINTN
) Header
->PrivateDataSize
);
450 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
451 MyLength
= FTW_RECORD_SIZE (Header
->PrivateDataSize
);
453 Status
= WriteWorkSpaceData (
454 FtwDevice
->FtwFvBlock
,
455 FtwDevice
->WorkBlockSize
,
456 FtwDevice
->FtwWorkSpaceLba
,
457 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
461 if (EFI_ERROR (Status
)) {
465 // Record has written to working block, then do the data.
468 // Allocate a memory buffer
470 MyBufferSize
= WriteLength
;
471 MyBuffer
= AllocatePool (MyBufferSize
);
472 if (MyBuffer
== NULL
) {
473 return EFI_OUT_OF_RESOURCES
;
476 // Read all original data from target block to memory buffer
479 for (Index
= 0; Index
< NumberOfWriteBlocks
; Index
+= 1) {
480 MyLength
= BlockSize
;
481 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
482 if (EFI_ERROR (Status
)) {
490 // Overwrite the updating range data with
491 // the input buffer content
493 CopyMem (MyBuffer
+ Offset
, Buffer
, Length
);
496 // Try to keep the content of spare block
497 // Save spare block into a spare backup memory buffer (Sparebuffer)
499 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
500 SpareBuffer
= AllocatePool (SpareBufferSize
);
501 if (SpareBuffer
== NULL
) {
503 return EFI_OUT_OF_RESOURCES
;
507 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
508 MyLength
= FtwDevice
->SpareBlockSize
;
509 Status
= FtwDevice
->FtwBackupFvb
->Read (
510 FtwDevice
->FtwBackupFvb
,
511 FtwDevice
->FtwSpareLba
+ Index
,
516 if (EFI_ERROR (Status
)) {
518 FreePool (SpareBuffer
);
525 // Write the memory buffer to spare block
526 // Do not assume Spare Block and Target Block have same block size
528 Status
= FtwEraseSpareBlock (FtwDevice
);
529 if (EFI_ERROR (Status
)) {
531 FreePool (SpareBuffer
);
535 for (Index
= 0; MyBufferSize
> 0; Index
+= 1) {
536 if (MyBufferSize
> FtwDevice
->SpareBlockSize
) {
537 MyLength
= FtwDevice
->SpareBlockSize
;
539 MyLength
= MyBufferSize
;
541 Status
= FtwDevice
->FtwBackupFvb
->Write (
542 FtwDevice
->FtwBackupFvb
,
543 FtwDevice
->FtwSpareLba
+ Index
,
548 if (EFI_ERROR (Status
)) {
550 FreePool (SpareBuffer
);
555 MyBufferSize
-= MyLength
;
563 // Set the SpareComplete in the FTW record,
565 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
566 Status
= FtwUpdateFvState (
567 FtwDevice
->FtwFvBlock
,
568 FtwDevice
->WorkBlockSize
,
569 FtwDevice
->FtwWorkSpaceLba
,
570 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
573 if (EFI_ERROR (Status
)) {
574 FreePool (SpareBuffer
);
578 Record
->SpareComplete
= FTW_VALID_STATE
;
581 // Since the content has already backuped in spare block, the write is
582 // guaranteed to be completed with fault tolerant manner.
584 Status
= FtwWriteRecord (This
, Fvb
, BlockSize
);
585 if (EFI_ERROR (Status
)) {
586 FreePool (SpareBuffer
);
590 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
592 Status
= FtwEraseSpareBlock (FtwDevice
);
593 if (EFI_ERROR (Status
)) {
594 FreePool (SpareBuffer
);
598 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
599 MyLength
= FtwDevice
->SpareBlockSize
;
600 Status
= FtwDevice
->FtwBackupFvb
->Write (
601 FtwDevice
->FtwBackupFvb
,
602 FtwDevice
->FtwSpareLba
+ Index
,
607 if (EFI_ERROR (Status
)) {
608 FreePool (SpareBuffer
);
617 FreePool (SpareBuffer
);
621 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
631 Restarts a previously interrupted write. The caller must provide the
632 block protocol needed to complete the interrupted write.
634 @param This The pointer to this protocol instance.
635 @param FvBlockHandle The handle of FVB protocol that provides services for
636 reading, writing, and erasing the target block.
638 @retval EFI_SUCCESS The function completed successfully
639 @retval EFI_ACCESS_DENIED No pending writes exist
640 @retval EFI_NOT_FOUND FVB protocol not found by the handle
641 @retval EFI_ABORTED The function could not complete successfully
647 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
648 IN EFI_HANDLE FvBlockHandle
652 EFI_FTW_DEVICE
*FtwDevice
;
653 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
654 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
655 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
657 UINTN NumberOfBlocks
;
659 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
661 Status
= WorkSpaceRefresh (FtwDevice
);
662 if (EFI_ERROR (Status
)) {
666 Header
= FtwDevice
->FtwLastWriteHeader
;
667 Record
= FtwDevice
->FtwLastWriteRecord
;
670 // Spare Complete but Destination not complete,
671 // Recover the targt block with the spare block.
673 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
674 if (EFI_ERROR (Status
)) {
675 return EFI_NOT_FOUND
;
679 // Now, one FVB has one type of BlockSize
681 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
682 if (EFI_ERROR (Status
)) {
683 DEBUG ((EFI_D_ERROR
, "Ftw: Restart(), Get block size - %r\n", Status
));
688 // Check the COMPLETE flag of last write header
690 if (Header
->Complete
== FTW_VALID_STATE
) {
691 return EFI_ACCESS_DENIED
;
695 // Check the flags of last write record
697 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
698 return EFI_ACCESS_DENIED
;
701 if ((Record
->SpareComplete
!= FTW_VALID_STATE
)) {
706 // Since the content has already backuped in spare block, the write is
707 // guaranteed to be completed with fault tolerant manner.
709 Status
= FtwWriteRecord (This
, Fvb
, BlockSize
);
710 if (EFI_ERROR (Status
)) {
716 // This is restart, no need to keep spareblock content.
718 Status
= FtwEraseSpareBlock (FtwDevice
);
719 if (EFI_ERROR (Status
)) {
723 DEBUG ((EFI_D_INFO
, "%a(): success\n", __FUNCTION__
));
728 Aborts all previous allocated writes.
730 @param This The pointer to this protocol instance.
732 @retval EFI_SUCCESS The function completed successfully
733 @retval EFI_ABORTED The function could not complete successfully.
734 @retval EFI_NOT_FOUND No allocated writes exist.
740 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
745 EFI_FTW_DEVICE
*FtwDevice
;
747 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
749 Status
= WorkSpaceRefresh (FtwDevice
);
750 if (EFI_ERROR (Status
)) {
754 if (FtwDevice
->FtwLastWriteHeader
->HeaderAllocated
!= FTW_VALID_STATE
) {
755 return EFI_NOT_FOUND
;
758 if (FtwDevice
->FtwLastWriteHeader
->Complete
== FTW_VALID_STATE
) {
759 return EFI_NOT_FOUND
;
762 // Update the complete state of the header as VALID and abort.
764 Offset
= (UINT8
*) FtwDevice
->FtwLastWriteHeader
- FtwDevice
->FtwWorkSpace
;
765 Status
= FtwUpdateFvState (
766 FtwDevice
->FtwFvBlock
,
767 FtwDevice
->WorkBlockSize
,
768 FtwDevice
->FtwWorkSpaceLba
,
769 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
772 if (EFI_ERROR (Status
)) {
776 FtwDevice
->FtwLastWriteHeader
->Complete
= FTW_VALID_STATE
;
778 DEBUG ((EFI_D_INFO
, "%a(): success\n", __FUNCTION__
));
783 Starts a target block update. This records information about the write
784 in fault tolerant storage and will complete the write in a recoverable
785 manner, ensuring at all times that either the original contents or
786 the modified contents are available.
788 @param This The pointer to this protocol instance.
789 @param CallerId The GUID identifying the last write.
790 @param Lba The logical block address of the last write.
791 @param Offset The offset within the block of the last write.
792 @param Length The length of the last write.
793 @param PrivateDataSize bytes from the private data
794 stored for this write.
795 @param PrivateData A pointer to a buffer. The function will copy
796 @param Complete A Boolean value with TRUE indicating
797 that the write was completed.
799 @retval EFI_SUCCESS The function completed successfully
800 @retval EFI_ABORTED The function could not complete successfully
801 @retval EFI_NOT_FOUND No allocated writes exist
802 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
808 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
809 OUT EFI_GUID
*CallerId
,
813 IN OUT UINTN
*PrivateDataSize
,
814 OUT VOID
*PrivateData
,
815 OUT BOOLEAN
*Complete
819 EFI_FTW_DEVICE
*FtwDevice
;
820 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
821 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
823 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
824 return EFI_UNSUPPORTED
;
827 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
829 Status
= WorkSpaceRefresh (FtwDevice
);
830 if (EFI_ERROR (Status
)) {
834 Header
= FtwDevice
->FtwLastWriteHeader
;
835 Record
= FtwDevice
->FtwLastWriteRecord
;
838 // If Header is incompleted and the last record has completed, then
839 // call Abort() to set the Header->Complete FLAG.
841 if ((Header
->Complete
!= FTW_VALID_STATE
) &&
842 (Record
->DestinationComplete
== FTW_VALID_STATE
) &&
843 IsLastRecordOfWrites (Header
, Record
)
846 Status
= FtwAbort (This
);
848 return EFI_NOT_FOUND
;
851 // If there is no write header/record, return not found.
853 if (Header
->HeaderAllocated
!= FTW_VALID_STATE
) {
855 return EFI_NOT_FOUND
;
858 // If this record SpareComplete has not set, then it can not restart.
860 if (Record
->SpareComplete
!= FTW_VALID_STATE
) {
861 Status
= GetPreviousRecordOfWrites (Header
, &Record
);
862 if (EFI_ERROR (Status
)) {
865 return EFI_NOT_FOUND
;
867 ASSERT (Record
!= NULL
);
871 // Fill all the requested values
873 CopyMem (CallerId
, &Header
->CallerId
, sizeof (EFI_GUID
));
875 *Offset
= (UINTN
) Record
->Offset
;
876 *Length
= (UINTN
) Record
->Length
;
877 *Complete
= (BOOLEAN
) (Record
->DestinationComplete
== FTW_VALID_STATE
);
879 if (*PrivateDataSize
< Header
->PrivateDataSize
) {
880 *PrivateDataSize
= (UINTN
) Header
->PrivateDataSize
;
882 Status
= EFI_BUFFER_TOO_SMALL
;
884 *PrivateDataSize
= (UINTN
) Header
->PrivateDataSize
;
885 CopyMem (PrivateData
, Record
+ 1, *PrivateDataSize
);
886 Status
= EFI_SUCCESS
;
889 DEBUG ((EFI_D_INFO
, "%a(): success\n", __FUNCTION__
));