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 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "FaultTolerantWrite.h"
14 // Fault Tolerant Write Protocol API
17 Query the largest block that may be updated in a fault tolerant manner.
20 @param This The pointer to this protocol instance.
21 @param BlockSize A pointer to a caller allocated UINTN that is updated to
22 indicate the size of the largest block that can be updated.
24 @return EFI_SUCCESS The function completed successfully
30 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
34 EFI_FTW_DEVICE
*FtwDevice
;
36 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
37 return EFI_UNSUPPORTED
;
40 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
42 *BlockSize
= FtwDevice
->SpareAreaLength
;
48 Allocates space for the protocol to maintain information about writes.
49 Since writes must be completed in a fault tolerant manner and multiple
50 updates will require more resources to be successful, this function
51 enables the protocol to ensure that enough space exists to track
52 information about the upcoming writes.
54 All writes must be completed or aborted before another fault tolerant write can occur.
56 @param This The pointer to this protocol instance.
57 @param CallerId The GUID identifying the write.
58 @param PrivateDataSize The size of the caller's private data
59 that must be recorded for each write.
60 @param NumberOfWrites The number of fault tolerant block writes
61 that will need to occur.
63 @return EFI_SUCCESS The function completed successfully
64 @retval EFI_ABORTED The function could not complete successfully.
65 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
71 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
72 IN EFI_GUID
*CallerId
,
73 IN UINTN PrivateDataSize
,
74 IN UINTN NumberOfWrites
79 EFI_FTW_DEVICE
*FtwDevice
;
80 EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwHeader
;
82 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
84 Status
= WorkSpaceRefresh (FtwDevice
);
85 if (EFI_ERROR (Status
)) {
89 // Check if there is enough space for the coming allocation
91 if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceHeader
->WriteQueueSize
) {
92 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId
));
93 return EFI_BUFFER_TOO_SMALL
;
96 // Find the last write header and record.
97 // If the FtwHeader is complete, skip the completed last write header/records
99 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
102 // Previous write has not completed, access denied.
104 if ((FtwHeader
->HeaderAllocated
== FTW_VALID_STATE
) || (FtwHeader
->WritesAllocated
== FTW_VALID_STATE
)) {
105 return EFI_ACCESS_DENIED
;
108 // If workspace is not enough, then reclaim workspace
110 Offset
= (UINT8
*) FtwHeader
- (UINT8
*) FtwDevice
->FtwWorkSpace
;
111 if (Offset
+ FTW_WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceSize
) {
112 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
113 if (EFI_ERROR (Status
)) {
117 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
120 // Prepare FTW write header,
121 // overwrite the buffer and write to workspace.
123 FtwHeader
->WritesAllocated
= FTW_INVALID_STATE
;
124 FtwHeader
->Complete
= FTW_INVALID_STATE
;
125 CopyMem (&FtwHeader
->CallerId
, CallerId
, sizeof (EFI_GUID
));
126 FtwHeader
->NumberOfWrites
= NumberOfWrites
;
127 FtwHeader
->PrivateDataSize
= PrivateDataSize
;
128 FtwHeader
->HeaderAllocated
= FTW_VALID_STATE
;
130 Status
= WriteWorkSpaceData (
131 FtwDevice
->FtwFvBlock
,
132 FtwDevice
->WorkBlockSize
,
133 FtwDevice
->FtwWorkSpaceLba
,
134 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
135 sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
),
138 if (EFI_ERROR (Status
)) {
142 // Update Header->WriteAllocated as VALID
144 Status
= FtwUpdateFvState (
145 FtwDevice
->FtwFvBlock
,
146 FtwDevice
->WorkBlockSize
,
147 FtwDevice
->FtwWorkSpaceLba
,
148 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
151 if (EFI_ERROR (Status
)) {
157 "Ftw: Allocate() success, Caller:%g, # %d\n",
167 Write a record with fault tolerant manner.
168 Since the content has already backuped in spare block, the write is
169 guaranteed to be completed with fault tolerant manner.
171 @param This The pointer to this protocol instance.
172 @param Fvb The FVB protocol that provides services for
173 reading, writing, and erasing the target block.
174 @param BlockSize The size of the block.
176 @retval EFI_SUCCESS The function completed successfully
177 @retval EFI_ABORTED The function could not complete successfully
182 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
183 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
188 EFI_FTW_DEVICE
*FtwDevice
;
189 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
190 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
192 UINTN NumberOfWriteBlocks
;
194 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
197 // Spare Complete but Destination not complete,
198 // Recover the target block with the spare block.
200 Header
= FtwDevice
->FtwLastWriteHeader
;
201 Record
= FtwDevice
->FtwLastWriteRecord
;
204 // IF target block is working block, THEN Flush Spare Block To Working Block;
205 // ELSE flush spare block to target block, which may be boot block after all.
207 if (IsWorkingBlock (FtwDevice
, Fvb
, Record
->Lba
)) {
209 // If target block is working block,
210 // it also need to set SPARE_COMPLETED to spare block.
212 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
213 Status
= FtwUpdateFvState (
214 FtwDevice
->FtwBackupFvb
,
215 FtwDevice
->SpareBlockSize
,
216 FtwDevice
->FtwSpareLba
+ FtwDevice
->FtwWorkSpaceLbaInSpare
,
217 FtwDevice
->FtwWorkSpaceBaseInSpare
+ Offset
,
220 if (EFI_ERROR (Status
)) {
224 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
225 } else if (IsBootBlock (FtwDevice
, Fvb
)) {
229 Status
= FlushSpareBlockToBootBlock (FtwDevice
);
232 // Update blocks other than working block or boot block
234 NumberOfWriteBlocks
= FTW_BLOCKS ((UINTN
) (Record
->Offset
+ Record
->Length
), BlockSize
);
235 Status
= FlushSpareBlockToTargetBlock (FtwDevice
, Fvb
, Record
->Lba
, BlockSize
, NumberOfWriteBlocks
);
238 if (EFI_ERROR (Status
)) {
242 // Record the DestionationComplete in record
244 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
245 Status
= FtwUpdateFvState (
246 FtwDevice
->FtwFvBlock
,
247 FtwDevice
->WorkBlockSize
,
248 FtwDevice
->FtwWorkSpaceLba
,
249 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
252 if (EFI_ERROR (Status
)) {
256 Record
->DestinationComplete
= FTW_VALID_STATE
;
259 // If this is the last Write in these write sequence,
260 // set the complete flag of write header.
262 if (IsLastRecordOfWrites (Header
, Record
)) {
263 Offset
= (UINT8
*) Header
- FtwDevice
->FtwWorkSpace
;
264 Status
= FtwUpdateFvState (
265 FtwDevice
->FtwFvBlock
,
266 FtwDevice
->WorkBlockSize
,
267 FtwDevice
->FtwWorkSpaceLba
,
268 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
271 Header
->Complete
= FTW_VALID_STATE
;
272 if (EFI_ERROR (Status
)) {
281 Starts a target block update. This function will record data about write
282 in fault tolerant storage and will complete the write in a recoverable
283 manner, ensuring at all times that either the original contents or
284 the modified contents are available.
286 @param This The pointer to this protocol instance.
287 @param Lba The logical block address of the target block.
288 @param Offset The offset within the target block to place the data.
289 @param Length The number of bytes to write to the target block.
290 @param PrivateData A pointer to private data that the caller requires to
291 complete any pending writes in the event of a fault.
292 @param FvBlockHandle The handle of FVB protocol that provides services for
293 reading, writing, and erasing the target block.
294 @param Buffer The data to write.
296 @retval EFI_SUCCESS The function completed successfully
297 @retval EFI_ABORTED The function could not complete successfully.
298 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
299 Offset + *NumBytes > SpareAreaLength.
300 @retval EFI_ACCESS_DENIED No writes have been allocated.
301 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
302 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
308 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
312 IN VOID
*PrivateData
,
313 IN EFI_HANDLE FvBlockHandle
,
318 EFI_FTW_DEVICE
*FtwDevice
;
319 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
320 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
321 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
326 UINTN SpareBufferSize
;
330 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
332 UINTN NumberOfBlocks
;
333 UINTN NumberOfWriteBlocks
;
336 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
338 Status
= WorkSpaceRefresh (FtwDevice
);
339 if (EFI_ERROR (Status
)) {
343 Header
= FtwDevice
->FtwLastWriteHeader
;
344 Record
= FtwDevice
->FtwLastWriteRecord
;
346 if (IsErasedFlashBuffer ((UINT8
*) Header
, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
))) {
347 if (PrivateData
== NULL
) {
349 // Ftw Write Header is not allocated.
350 // No additional private data, the private data size is zero. Number of record can be set to 1.
352 Status
= FtwAllocate (This
, &gEfiCallerIdGuid
, 0, 1);
353 if (EFI_ERROR (Status
)) {
358 // Ftw Write Header is not allocated
359 // Additional private data is not NULL, the private data size can't be determined.
361 DEBUG ((EFI_D_ERROR
, "Ftw: no allocates space for write record!\n"));
362 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate service should be called before Write service!\n"));
363 return EFI_NOT_READY
;
368 // If Record is out of the range of Header, return access denied.
370 if (((UINTN
) Record
- (UINTN
) Header
) > FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
- 1, Header
->PrivateDataSize
)) {
371 return EFI_ACCESS_DENIED
;
375 // Check the COMPLETE flag of last write header
377 if (Header
->Complete
== FTW_VALID_STATE
) {
378 return EFI_ACCESS_DENIED
;
381 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
382 return EFI_ACCESS_DENIED
;
385 if ((Record
->SpareComplete
== FTW_VALID_STATE
) && (Record
->DestinationComplete
!= FTW_VALID_STATE
)) {
386 return EFI_NOT_READY
;
390 // Get the FVB protocol by handle
392 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
393 if (EFI_ERROR (Status
)) {
394 return EFI_NOT_FOUND
;
397 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
398 if (EFI_ERROR (Status
)) {
399 DEBUG ((EFI_D_ERROR
, "Ftw: Write(), Get FVB physical address - %r\n", Status
));
404 // Now, one FVB has one type of BlockSize.
406 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
407 if (EFI_ERROR (Status
)) {
408 DEBUG ((EFI_D_ERROR
, "Ftw: Write(), Get block size - %r\n", Status
));
412 NumberOfWriteBlocks
= FTW_BLOCKS (Offset
+ Length
, BlockSize
);
413 DEBUG ((EFI_D_INFO
, "Ftw: Write(), BlockSize - 0x%x, NumberOfWriteBlock - 0x%x\n", BlockSize
, NumberOfWriteBlocks
));
414 WriteLength
= NumberOfWriteBlocks
* BlockSize
;
417 // Check if the input data can fit within the spare block.
419 if (WriteLength
> FtwDevice
->SpareAreaLength
) {
420 return EFI_BAD_BUFFER_SIZE
;
424 // Set BootBlockUpdate FLAG if it's updating boot block.
426 if (IsBootBlock (FtwDevice
, Fvb
)) {
427 Record
->BootBlockUpdate
= FTW_VALID_STATE
;
429 // Boot Block and Spare Block should have same block size and block numbers.
431 ASSERT ((BlockSize
== FtwDevice
->SpareBlockSize
) && (NumberOfWriteBlocks
== FtwDevice
->NumberOfSpareBlock
));
434 // Write the record to the work space.
437 Record
->Offset
= Offset
;
438 Record
->Length
= Length
;
439 Record
->RelativeOffset
= (INT64
) (FvbPhysicalAddress
+ (UINTN
) Lba
* BlockSize
) - (INT64
) FtwDevice
->SpareAreaAddress
;
440 if (PrivateData
!= NULL
) {
441 CopyMem ((Record
+ 1), PrivateData
, (UINTN
) Header
->PrivateDataSize
);
444 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
445 MyLength
= FTW_RECORD_SIZE (Header
->PrivateDataSize
);
447 Status
= WriteWorkSpaceData (
448 FtwDevice
->FtwFvBlock
,
449 FtwDevice
->WorkBlockSize
,
450 FtwDevice
->FtwWorkSpaceLba
,
451 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
455 if (EFI_ERROR (Status
)) {
459 // Record has written to working block, then do the data.
462 // Allocate a memory buffer
464 MyBufferSize
= WriteLength
;
465 MyBuffer
= AllocatePool (MyBufferSize
);
466 if (MyBuffer
== NULL
) {
467 return EFI_OUT_OF_RESOURCES
;
470 // Read all original data from target block to memory buffer
473 for (Index
= 0; Index
< NumberOfWriteBlocks
; Index
+= 1) {
474 MyLength
= BlockSize
;
475 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
476 if (EFI_ERROR (Status
)) {
484 // Overwrite the updating range data with
485 // the input buffer content
487 CopyMem (MyBuffer
+ Offset
, Buffer
, Length
);
490 // Try to keep the content of spare block
491 // Save spare block into a spare backup memory buffer (Sparebuffer)
493 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
494 SpareBuffer
= AllocatePool (SpareBufferSize
);
495 if (SpareBuffer
== NULL
) {
497 return EFI_OUT_OF_RESOURCES
;
501 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
502 MyLength
= FtwDevice
->SpareBlockSize
;
503 Status
= FtwDevice
->FtwBackupFvb
->Read (
504 FtwDevice
->FtwBackupFvb
,
505 FtwDevice
->FtwSpareLba
+ Index
,
510 if (EFI_ERROR (Status
)) {
512 FreePool (SpareBuffer
);
519 // Write the memory buffer to spare block
520 // Do not assume Spare Block and Target Block have same block size
522 Status
= FtwEraseSpareBlock (FtwDevice
);
523 if (EFI_ERROR (Status
)) {
525 FreePool (SpareBuffer
);
529 for (Index
= 0; MyBufferSize
> 0; Index
+= 1) {
530 if (MyBufferSize
> FtwDevice
->SpareBlockSize
) {
531 MyLength
= FtwDevice
->SpareBlockSize
;
533 MyLength
= MyBufferSize
;
535 Status
= FtwDevice
->FtwBackupFvb
->Write (
536 FtwDevice
->FtwBackupFvb
,
537 FtwDevice
->FtwSpareLba
+ Index
,
542 if (EFI_ERROR (Status
)) {
544 FreePool (SpareBuffer
);
549 MyBufferSize
-= MyLength
;
557 // Set the SpareComplete in the FTW record,
559 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
560 Status
= FtwUpdateFvState (
561 FtwDevice
->FtwFvBlock
,
562 FtwDevice
->WorkBlockSize
,
563 FtwDevice
->FtwWorkSpaceLba
,
564 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
567 if (EFI_ERROR (Status
)) {
568 FreePool (SpareBuffer
);
572 Record
->SpareComplete
= FTW_VALID_STATE
;
575 // Since the content has already backuped in spare block, the write is
576 // guaranteed to be completed with fault tolerant manner.
578 Status
= FtwWriteRecord (This
, Fvb
, BlockSize
);
579 if (EFI_ERROR (Status
)) {
580 FreePool (SpareBuffer
);
584 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
586 Status
= FtwEraseSpareBlock (FtwDevice
);
587 if (EFI_ERROR (Status
)) {
588 FreePool (SpareBuffer
);
592 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
593 MyLength
= FtwDevice
->SpareBlockSize
;
594 Status
= FtwDevice
->FtwBackupFvb
->Write (
595 FtwDevice
->FtwBackupFvb
,
596 FtwDevice
->FtwSpareLba
+ Index
,
601 if (EFI_ERROR (Status
)) {
602 FreePool (SpareBuffer
);
611 FreePool (SpareBuffer
);
615 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
625 Restarts a previously interrupted write. The caller must provide the
626 block protocol needed to complete the interrupted write.
628 @param This The pointer to this protocol instance.
629 @param FvBlockHandle The handle of FVB protocol that provides services for
630 reading, writing, and erasing the target block.
632 @retval EFI_SUCCESS The function completed successfully
633 @retval EFI_ACCESS_DENIED No pending writes exist
634 @retval EFI_NOT_FOUND FVB protocol not found by the handle
635 @retval EFI_ABORTED The function could not complete successfully
641 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
642 IN EFI_HANDLE FvBlockHandle
646 EFI_FTW_DEVICE
*FtwDevice
;
647 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
648 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
649 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
651 UINTN NumberOfBlocks
;
653 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
655 Status
= WorkSpaceRefresh (FtwDevice
);
656 if (EFI_ERROR (Status
)) {
660 Header
= FtwDevice
->FtwLastWriteHeader
;
661 Record
= FtwDevice
->FtwLastWriteRecord
;
664 // Spare Complete but Destination not complete,
665 // Recover the targt block with the spare block.
667 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
668 if (EFI_ERROR (Status
)) {
669 return EFI_NOT_FOUND
;
673 // Now, one FVB has one type of BlockSize
675 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
676 if (EFI_ERROR (Status
)) {
677 DEBUG ((EFI_D_ERROR
, "Ftw: Restart(), Get block size - %r\n", Status
));
682 // Check the COMPLETE flag of last write header
684 if (Header
->Complete
== FTW_VALID_STATE
) {
685 return EFI_ACCESS_DENIED
;
689 // Check the flags of last write record
691 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
692 return EFI_ACCESS_DENIED
;
695 if ((Record
->SpareComplete
!= FTW_VALID_STATE
)) {
700 // Since the content has already backuped in spare block, the write is
701 // guaranteed to be completed with fault tolerant manner.
703 Status
= FtwWriteRecord (This
, Fvb
, BlockSize
);
704 if (EFI_ERROR (Status
)) {
710 // This is restart, no need to keep spareblock content.
712 Status
= FtwEraseSpareBlock (FtwDevice
);
713 if (EFI_ERROR (Status
)) {
717 DEBUG ((EFI_D_INFO
, "%a(): success\n", __FUNCTION__
));
722 Aborts all previous allocated writes.
724 @param This The pointer to this protocol instance.
726 @retval EFI_SUCCESS The function completed successfully
727 @retval EFI_ABORTED The function could not complete successfully.
728 @retval EFI_NOT_FOUND No allocated writes exist.
734 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
739 EFI_FTW_DEVICE
*FtwDevice
;
741 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
743 Status
= WorkSpaceRefresh (FtwDevice
);
744 if (EFI_ERROR (Status
)) {
748 if (FtwDevice
->FtwLastWriteHeader
->HeaderAllocated
!= FTW_VALID_STATE
) {
749 return EFI_NOT_FOUND
;
752 if (FtwDevice
->FtwLastWriteHeader
->Complete
== FTW_VALID_STATE
) {
753 return EFI_NOT_FOUND
;
756 // Update the complete state of the header as VALID and abort.
758 Offset
= (UINT8
*) FtwDevice
->FtwLastWriteHeader
- FtwDevice
->FtwWorkSpace
;
759 Status
= FtwUpdateFvState (
760 FtwDevice
->FtwFvBlock
,
761 FtwDevice
->WorkBlockSize
,
762 FtwDevice
->FtwWorkSpaceLba
,
763 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
766 if (EFI_ERROR (Status
)) {
770 FtwDevice
->FtwLastWriteHeader
->Complete
= FTW_VALID_STATE
;
772 DEBUG ((EFI_D_INFO
, "%a(): success\n", __FUNCTION__
));
777 Starts a target block update. This records information about the write
778 in fault tolerant storage and will complete the write in a recoverable
779 manner, ensuring at all times that either the original contents or
780 the modified contents are available.
782 @param This The pointer to this protocol instance.
783 @param CallerId The GUID identifying the last write.
784 @param Lba The logical block address of the last write.
785 @param Offset The offset within the block of the last write.
786 @param Length The length of the last write.
787 @param PrivateDataSize bytes from the private data
788 stored for this write.
789 @param PrivateData A pointer to a buffer. The function will copy
790 @param Complete A Boolean value with TRUE indicating
791 that the write was completed.
793 @retval EFI_SUCCESS The function completed successfully
794 @retval EFI_ABORTED The function could not complete successfully
795 @retval EFI_NOT_FOUND No allocated writes exist
796 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
802 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
803 OUT EFI_GUID
*CallerId
,
807 IN OUT UINTN
*PrivateDataSize
,
808 OUT VOID
*PrivateData
,
809 OUT BOOLEAN
*Complete
813 EFI_FTW_DEVICE
*FtwDevice
;
814 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
815 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
817 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
818 return EFI_UNSUPPORTED
;
821 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
823 Status
= WorkSpaceRefresh (FtwDevice
);
824 if (EFI_ERROR (Status
)) {
828 Header
= FtwDevice
->FtwLastWriteHeader
;
829 Record
= FtwDevice
->FtwLastWriteRecord
;
832 // If Header is incompleted and the last record has completed, then
833 // call Abort() to set the Header->Complete FLAG.
835 if ((Header
->Complete
!= FTW_VALID_STATE
) &&
836 (Record
->DestinationComplete
== FTW_VALID_STATE
) &&
837 IsLastRecordOfWrites (Header
, Record
)
840 Status
= FtwAbort (This
);
842 return EFI_NOT_FOUND
;
845 // If there is no write header/record, return not found.
847 if (Header
->HeaderAllocated
!= FTW_VALID_STATE
) {
849 return EFI_NOT_FOUND
;
852 // If this record SpareComplete has not set, then it can not restart.
854 if (Record
->SpareComplete
!= FTW_VALID_STATE
) {
855 Status
= GetPreviousRecordOfWrites (Header
, &Record
);
856 if (EFI_ERROR (Status
)) {
859 return EFI_NOT_FOUND
;
861 ASSERT (Record
!= NULL
);
865 // Fill all the requested values
867 CopyMem (CallerId
, &Header
->CallerId
, sizeof (EFI_GUID
));
869 *Offset
= (UINTN
) Record
->Offset
;
870 *Length
= (UINTN
) Record
->Length
;
871 *Complete
= (BOOLEAN
) (Record
->DestinationComplete
== FTW_VALID_STATE
);
873 if (*PrivateDataSize
< Header
->PrivateDataSize
) {
874 *PrivateDataSize
= (UINTN
) Header
->PrivateDataSize
;
876 Status
= EFI_BUFFER_TOO_SMALL
;
878 *PrivateDataSize
= (UINTN
) Header
->PrivateDataSize
;
879 CopyMem (PrivateData
, Record
+ 1, *PrivateDataSize
);
880 Status
= EFI_SUCCESS
;
883 DEBUG ((EFI_D_INFO
, "%a(): success\n", __FUNCTION__
));