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 - 2010, 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
86 EFI_FTW_DEVICE
*FtwDevice
;
87 EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwHeader
;
89 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
91 Status
= WorkSpaceRefresh (FtwDevice
);
92 if (EFI_ERROR (Status
)) {
96 // Check if there is enough space for the coming allocation
98 if (WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceHeader
->WriteQueueSize
) {
99 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId
));
100 return EFI_BUFFER_TOO_SMALL
;
103 // Find the last write header and record.
104 // If the FtwHeader is complete, skip the completed last write header/records
106 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
109 // Previous write has not completed, access denied.
111 if ((FtwHeader
->HeaderAllocated
== FTW_VALID_STATE
) || (FtwHeader
->WritesAllocated
== FTW_VALID_STATE
)) {
112 return EFI_ACCESS_DENIED
;
115 // If workspace is not enough, then reclaim workspace
117 Offset
= (UINT8
*) FtwHeader
- (UINT8
*) FtwDevice
->FtwWorkSpace
;
118 if (Offset
+ WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceSize
) {
119 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
120 if (EFI_ERROR (Status
)) {
124 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
127 // Prepare FTW write header,
128 // overwrite the buffer and write to workspace.
130 FtwHeader
->WritesAllocated
= FTW_INVALID_STATE
;
131 FtwHeader
->Complete
= FTW_INVALID_STATE
;
132 CopyMem (&FtwHeader
->CallerId
, CallerId
, sizeof (EFI_GUID
));
133 FtwHeader
->NumberOfWrites
= NumberOfWrites
;
134 FtwHeader
->PrivateDataSize
= PrivateDataSize
;
135 FtwHeader
->HeaderAllocated
= FTW_VALID_STATE
;
137 Length
= sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
);
138 Status
= FtwDevice
->FtwFvBlock
->Write (
139 FtwDevice
->FtwFvBlock
,
140 FtwDevice
->FtwWorkSpaceLba
,
141 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
145 if (EFI_ERROR (Status
)) {
149 // Update Header->WriteAllocated as VALID
151 Status
= FtwUpdateFvState (
152 FtwDevice
->FtwFvBlock
,
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 mannaer.
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.
181 @retval EFI_SUCCESS The function completed successfully
182 @retval EFI_ABORTED The function could not complete successfully
187 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
188 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
192 EFI_FTW_DEVICE
*FtwDevice
;
193 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
194 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
197 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
200 // Spare Complete but Destination not complete,
201 // Recover the target block with the spare block.
203 Header
= FtwDevice
->FtwLastWriteHeader
;
204 Record
= FtwDevice
->FtwLastWriteRecord
;
207 // IF target block is working block, THEN Flush Spare Block To Working Block;
208 // ELSE flush spare block to target block, which may be boot block after all.
210 if (IsWorkingBlock (FtwDevice
, Fvb
, Record
->Lba
)) {
212 // If target block is working block,
213 // it also need to set SPARE_COMPLETED to spare block.
215 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
216 Status
= FtwUpdateFvState (
217 FtwDevice
->FtwBackupFvb
,
218 FtwDevice
->FtwWorkSpaceLba
,
219 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
222 if (EFI_ERROR (Status
)) {
226 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
227 } else if (IsBootBlock (FtwDevice
, Fvb
, Record
->Lba
)) {
231 Status
= FlushSpareBlockToBootBlock (FtwDevice
);
234 // Update blocks other than working block or boot block
236 Status
= FlushSpareBlockToTargetBlock (FtwDevice
, Fvb
, Record
->Lba
);
239 if (EFI_ERROR (Status
)) {
243 // Record the DestionationComplete in record
245 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
246 Status
= FtwUpdateFvState (
247 FtwDevice
->FtwFvBlock
,
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
->FtwWorkSpaceLba
,
267 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
270 Header
->Complete
= FTW_VALID_STATE
;
271 if (EFI_ERROR (Status
)) {
280 Starts a target block update. This function will record data about write
281 in fault tolerant storage and will complete the write in a recoverable
282 manner, ensuring at all times that either the original contents or
283 the modified contents are available.
285 @param This The pointer to this protocol instance.
286 @param Lba The logical block address of the target block.
287 @param Offset The offset within the target block to place the data.
288 @param Length The number of bytes to write to the target block.
289 @param PrivateData A pointer to private data that the caller requires to
290 complete any pending writes in the event of a fault.
291 @param FvBlockHandle The handle of FVB protocol that provides services for
292 reading, writing, and erasing the target block.
293 @param Buffer The data to write.
295 @retval EFI_SUCCESS The function completed successfully
296 @retval EFI_ABORTED The function could not complete successfully.
297 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
298 Offset + *NumBytes > SpareAreaLength.
299 @retval EFI_ACCESS_DENIED No writes have been allocated.
300 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
301 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
307 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
311 IN VOID
*PrivateData
,
312 IN EFI_HANDLE FvBlockHandle
,
317 EFI_FTW_DEVICE
*FtwDevice
;
318 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
319 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
320 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
325 UINTN SpareBufferSize
;
329 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
331 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
333 Status
= WorkSpaceRefresh (FtwDevice
);
334 if (EFI_ERROR (Status
)) {
338 Header
= FtwDevice
->FtwLastWriteHeader
;
339 Record
= FtwDevice
->FtwLastWriteRecord
;
341 if (IsErasedFlashBuffer ((UINT8
*) Header
, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
))) {
342 if (PrivateData
== NULL
) {
344 // Ftw Write Header is not allocated.
345 // No additional private data, the private data size is zero. Number of record can be set to 1.
347 Status
= FtwAllocate (This
, &gEfiCallerIdGuid
, 0, 1);
348 if (EFI_ERROR (Status
)) {
353 // Ftw Write Header is not allocated
354 // Additional private data is not NULL, the private data size can't be determined.
356 DEBUG ((EFI_D_ERROR
, "Ftw: no allocates space for write record!\n"));
357 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate service should be called before Write service!\n"));
358 return EFI_NOT_READY
;
363 // If Record is out of the range of Header, return access denied.
365 if (((UINTN
)((UINT8
*) Record
- (UINT8
*) Header
)) > WRITE_TOTAL_SIZE (Header
->NumberOfWrites
- 1, Header
->PrivateDataSize
)) {
366 return EFI_ACCESS_DENIED
;
370 // Check the COMPLETE flag of last write header
372 if (Header
->Complete
== FTW_VALID_STATE
) {
373 return EFI_ACCESS_DENIED
;
376 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
377 return EFI_ACCESS_DENIED
;
380 if ((Record
->SpareComplete
== FTW_VALID_STATE
) && (Record
->DestinationComplete
!= FTW_VALID_STATE
)) {
381 return EFI_NOT_READY
;
384 // Check if the input data can fit within the target block
386 if ((Offset
+ Length
) > FtwDevice
->SpareAreaLength
) {
387 return EFI_BAD_BUFFER_SIZE
;
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
, "FtwLite: Get FVB physical address - %r\n", Status
));
404 // Set BootBlockUpdate FLAG if it's updating boot block.
406 if (IsBootBlock (FtwDevice
, Fvb
, Lba
)) {
407 Record
->BootBlockUpdate
= FTW_VALID_STATE
;
410 // Write the record to the work space.
413 Record
->Offset
= Offset
;
414 Record
->Length
= Length
;
415 Record
->FvBaseAddress
= FvbPhysicalAddress
;
416 if (PrivateData
!= NULL
) {
417 CopyMem ((Record
+ 1), PrivateData
, Header
->PrivateDataSize
);
420 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
421 MyLength
= RECORD_SIZE (Header
->PrivateDataSize
);
423 Status
= FtwDevice
->FtwFvBlock
->Write (
424 FtwDevice
->FtwFvBlock
,
425 FtwDevice
->FtwWorkSpaceLba
,
426 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
430 if (EFI_ERROR (Status
)) {
434 // Record has written to working block, then do the data.
437 // Allocate a memory buffer
439 MyBufferSize
= FtwDevice
->SpareAreaLength
;
440 MyBuffer
= AllocatePool (MyBufferSize
);
441 if (MyBuffer
== NULL
) {
442 return EFI_OUT_OF_RESOURCES
;
445 // Read all original data from target block to memory buffer
448 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
449 MyLength
= FtwDevice
->BlockSize
;
450 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
451 if (EFI_ERROR (Status
)) {
459 // Overwrite the updating range data with
460 // the input buffer content
462 CopyMem (MyBuffer
+ Offset
, Buffer
, Length
);
465 // Try to keep the content of spare block
466 // Save spare block into a spare backup memory buffer (Sparebuffer)
468 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
469 SpareBuffer
= AllocatePool (SpareBufferSize
);
470 if (SpareBuffer
== NULL
) {
472 return EFI_OUT_OF_RESOURCES
;
476 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
477 MyLength
= FtwDevice
->BlockSize
;
478 Status
= FtwDevice
->FtwBackupFvb
->Read (
479 FtwDevice
->FtwBackupFvb
,
480 FtwDevice
->FtwSpareLba
+ Index
,
485 if (EFI_ERROR (Status
)) {
487 FreePool (SpareBuffer
);
494 // Write the memory buffer to spare block
496 Status
= FtwEraseSpareBlock (FtwDevice
);
498 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
499 MyLength
= FtwDevice
->BlockSize
;
500 Status
= FtwDevice
->FtwBackupFvb
->Write (
501 FtwDevice
->FtwBackupFvb
,
502 FtwDevice
->FtwSpareLba
+ Index
,
507 if (EFI_ERROR (Status
)) {
509 FreePool (SpareBuffer
);
521 // Set the SpareComplete in the FTW record,
523 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
524 Status
= FtwUpdateFvState (
525 FtwDevice
->FtwFvBlock
,
526 FtwDevice
->FtwWorkSpaceLba
,
527 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
530 if (EFI_ERROR (Status
)) {
531 FreePool (SpareBuffer
);
535 Record
->SpareComplete
= FTW_VALID_STATE
;
538 // Since the content has already backuped in spare block, the write is
539 // guaranteed to be completed with fault tolerant manner.
541 Status
= FtwWriteRecord (This
, Fvb
);
542 if (EFI_ERROR (Status
)) {
543 FreePool (SpareBuffer
);
547 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
549 Status
= FtwEraseSpareBlock (FtwDevice
);
551 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
552 MyLength
= FtwDevice
->BlockSize
;
553 Status
= FtwDevice
->FtwBackupFvb
->Write (
554 FtwDevice
->FtwBackupFvb
,
555 FtwDevice
->FtwSpareLba
+ Index
,
560 if (EFI_ERROR (Status
)) {
561 FreePool (SpareBuffer
);
570 FreePool (SpareBuffer
);
574 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
584 Restarts a previously interrupted write. The caller must provide the
585 block protocol needed to complete the interrupted write.
587 @param This The pointer to this protocol instance.
588 @param FvBlockHandle The handle of FVB protocol that provides services for
589 reading, writing, and erasing the target block.
591 @retval EFI_SUCCESS The function completed successfully
592 @retval EFI_ACCESS_DENIED No pending writes exist
593 @retval EFI_NOT_FOUND FVB protocol not found by the handle
594 @retval EFI_ABORTED The function could not complete successfully
600 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
601 IN EFI_HANDLE FvBlockHandle
605 EFI_FTW_DEVICE
*FtwDevice
;
606 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
607 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
608 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
610 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
612 Status
= WorkSpaceRefresh (FtwDevice
);
613 if (EFI_ERROR (Status
)) {
617 Header
= FtwDevice
->FtwLastWriteHeader
;
618 Record
= FtwDevice
->FtwLastWriteRecord
;
621 // Spare Complete but Destination not complete,
622 // Recover the targt block with the spare block.
624 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
625 if (EFI_ERROR (Status
)) {
626 return EFI_NOT_FOUND
;
630 // Check the COMPLETE flag of last write header
632 if (Header
->Complete
== FTW_VALID_STATE
) {
633 return EFI_ACCESS_DENIED
;
637 // Check the flags of last write record
639 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
640 return EFI_ACCESS_DENIED
;
643 if ((Record
->SpareComplete
!= FTW_VALID_STATE
)) {
648 // Since the content has already backuped in spare block, the write is
649 // guaranteed to be completed with fault tolerant manner.
651 Status
= FtwWriteRecord (This
, Fvb
);
652 if (EFI_ERROR (Status
)) {
658 // This is restart, no need to keep spareblock content.
660 FtwEraseSpareBlock (FtwDevice
);
662 DEBUG ((EFI_D_ERROR
, "Ftw: Restart() success \n"));
667 Aborts all previous allocated writes.
669 @param This The pointer to this protocol instance.
671 @retval EFI_SUCCESS The function completed successfully
672 @retval EFI_ABORTED The function could not complete successfully.
673 @retval EFI_NOT_FOUND No allocated writes exist.
679 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
684 EFI_FTW_DEVICE
*FtwDevice
;
686 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
688 Status
= WorkSpaceRefresh (FtwDevice
);
689 if (EFI_ERROR (Status
)) {
693 if (FtwDevice
->FtwLastWriteHeader
->Complete
== FTW_VALID_STATE
) {
694 return EFI_NOT_FOUND
;
697 // Update the complete state of the header as VALID and abort.
699 Offset
= (UINT8
*) FtwDevice
->FtwLastWriteHeader
- FtwDevice
->FtwWorkSpace
;
700 Status
= FtwUpdateFvState (
701 FtwDevice
->FtwFvBlock
,
702 FtwDevice
->FtwWorkSpaceLba
,
703 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
706 if (EFI_ERROR (Status
)) {
710 FtwDevice
->FtwLastWriteHeader
->Complete
= FTW_VALID_STATE
;
712 DEBUG ((EFI_D_ERROR
, "Ftw: Abort() success \n"));
717 Starts a target block update. This records information about the write
718 in fault tolerant storage and will complete the write in a recoverable
719 manner, ensuring at all times that either the original contents or
720 the modified contents are available.
722 @param This The pointer to this protocol instance.
723 @param CallerId The GUID identifying the last write.
724 @param Lba The logical block address of the last write.
725 @param Offset The offset within the block of the last write.
726 @param Length The length of the last write.
727 @param PrivateDataSize bytes from the private data
728 stored for this write.
729 @param PrivateData A pointer to a buffer. The function will copy
730 @param Complete A Boolean value with TRUE indicating
731 that the write was completed.
733 @retval EFI_SUCCESS The function completed successfully
734 @retval EFI_ABORTED The function could not complete successfully
735 @retval EFI_NOT_FOUND No allocated writes exist
736 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
742 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
743 OUT EFI_GUID
*CallerId
,
747 IN OUT UINTN
*PrivateDataSize
,
748 OUT VOID
*PrivateData
,
749 OUT BOOLEAN
*Complete
753 EFI_FTW_DEVICE
*FtwDevice
;
754 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
755 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
757 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
758 return EFI_UNSUPPORTED
;
761 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
763 Status
= WorkSpaceRefresh (FtwDevice
);
764 if (EFI_ERROR (Status
)) {
768 Header
= FtwDevice
->FtwLastWriteHeader
;
769 Record
= FtwDevice
->FtwLastWriteRecord
;
772 // If Header is incompleted and the last record has completed, then
773 // call Abort() to set the Header->Complete FLAG.
775 if ((Header
->Complete
!= FTW_VALID_STATE
) &&
776 (Record
->DestinationComplete
== FTW_VALID_STATE
) &&
777 IsLastRecordOfWrites (Header
, Record
)
780 Status
= FtwAbort (This
);
782 return EFI_NOT_FOUND
;
785 // If there is no write header/record, return not found.
787 if (Header
->HeaderAllocated
!= FTW_VALID_STATE
) {
789 return EFI_NOT_FOUND
;
792 // If this record SpareComplete has not set, then it can not restart.
794 if (Record
->SpareComplete
!= FTW_VALID_STATE
) {
795 Status
= GetPreviousRecordOfWrites (Header
, &Record
);
796 if (EFI_ERROR (Status
)) {
799 return EFI_NOT_FOUND
;
801 ASSERT (Record
!= NULL
);
805 // Fill all the requested values
807 CopyMem (CallerId
, &Header
->CallerId
, sizeof (EFI_GUID
));
809 *Offset
= Record
->Offset
;
810 *Length
= Record
->Length
;
811 *Complete
= (BOOLEAN
) (Record
->DestinationComplete
== FTW_VALID_STATE
);
813 if (*PrivateDataSize
< Header
->PrivateDataSize
) {
814 *PrivateDataSize
= Header
->PrivateDataSize
;
816 Status
= EFI_BUFFER_TOO_SMALL
;
818 *PrivateDataSize
= Header
->PrivateDataSize
;
819 CopyMem (PrivateData
, Record
+ 1, *PrivateDataSize
);
820 Status
= EFI_SUCCESS
;
823 DEBUG ((EFI_D_ERROR
, "Ftw: GetLasetWrite() success\n"));