1 /** @file
2 
3   These are the common Fault Tolerant Write (FTW) functions that are shared
4   by DXE FTW driver and SMM FTW driver.
5 
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
11 
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.
14 
15 **/
16 
17 #include "FaultTolerantWrite.h"
18 
19 //
20 // Fault Tolerant Write Protocol API
21 //
22 /**
23   Query the largest block that may be updated in a fault tolerant manner.
24 
25 
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.
29 
30   @return EFI_SUCCESS   The function completed successfully
31 
32 **/
33 EFI_STATUS
34 EFIAPI
FtwGetMaxBlockSize(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,OUT UINTN * BlockSize)35 FtwGetMaxBlockSize (
36   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL    *This,
37   OUT UINTN                               *BlockSize
38   )
39 {
40   EFI_FTW_DEVICE  *FtwDevice;
41 
42   if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
43     return EFI_UNSUPPORTED;
44   }
45 
46   FtwDevice   = FTW_CONTEXT_FROM_THIS (This);
47 
48   *BlockSize  = FtwDevice->SpareAreaLength;
49 
50   return EFI_SUCCESS;
51 }
52 
53 /**
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.
59 
60   All writes must be completed or aborted before another fault tolerant write can occur.
61 
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.
68 
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.
72 
73 **/
74 EFI_STATUS
75 EFIAPI
FtwAllocate(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,IN EFI_GUID * CallerId,IN UINTN PrivateDataSize,IN UINTN NumberOfWrites)76 FtwAllocate (
77   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL    *This,
78   IN EFI_GUID                             *CallerId,
79   IN UINTN                                PrivateDataSize,
80   IN UINTN                                NumberOfWrites
81   )
82 {
83   EFI_STATUS                      Status;
84   UINTN                           Offset;
85   EFI_FTW_DEVICE                  *FtwDevice;
86   EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
87 
88   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
89 
90   Status    = WorkSpaceRefresh (FtwDevice);
91   if (EFI_ERROR (Status)) {
92     return EFI_ABORTED;
93   }
94   //
95   // Check if there is enough space for the coming allocation
96   //
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;
100   }
101   //
102   // Find the last write header and record.
103   // If the FtwHeader is complete, skip the completed last write header/records
104   //
105   FtwHeader = FtwDevice->FtwLastWriteHeader;
106 
107   //
108   // Previous write has not completed, access denied.
109   //
110   if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
111     return EFI_ACCESS_DENIED;
112   }
113   //
114   // If workspace is not enough, then reclaim workspace
115   //
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)) {
120       return EFI_ABORTED;
121     }
122 
123     FtwHeader = FtwDevice->FtwLastWriteHeader;
124   }
125   //
126   // Prepare FTW write header,
127   // overwrite the buffer and write to workspace.
128   //
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;
135 
136   Status = WriteWorkSpaceData (
137              FtwDevice->FtwFvBlock,
138              FtwDevice->WorkBlockSize,
139              FtwDevice->FtwWorkSpaceLba,
140              FtwDevice->FtwWorkSpaceBase + Offset,
141              sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER),
142              (UINT8 *) FtwHeader
143              );
144   if (EFI_ERROR (Status)) {
145     return EFI_ABORTED;
146   }
147   //
148   // Update Header->WriteAllocated as VALID
149   //
150   Status = FtwUpdateFvState (
151             FtwDevice->FtwFvBlock,
152             FtwDevice->WorkBlockSize,
153             FtwDevice->FtwWorkSpaceLba,
154             FtwDevice->FtwWorkSpaceBase + Offset,
155             WRITES_ALLOCATED
156             );
157   if (EFI_ERROR (Status)) {
158     return EFI_ABORTED;
159   }
160 
161   DEBUG (
162     (EFI_D_INFO,
163     "Ftw: Allocate() success, Caller:%g, # %d\n",
164     CallerId,
165     NumberOfWrites)
166     );
167 
168   return EFI_SUCCESS;
169 }
170 
171 
172 /**
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.
176 
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.
181 
182   @retval  EFI_SUCCESS          The function completed successfully
183   @retval  EFI_ABORTED          The function could not complete successfully
184 
185 **/
186 EFI_STATUS
FtwWriteRecord(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb,IN UINTN BlockSize)187 FtwWriteRecord (
188   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
189   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb,
190   IN UINTN                                 BlockSize
191   )
192 {
193   EFI_STATUS                      Status;
194   EFI_FTW_DEVICE                  *FtwDevice;
195   EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
196   EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
197   UINTN                           Offset;
198   UINTN                           NumberOfWriteBlocks;
199 
200   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
201 
202   //
203   // Spare Complete but Destination not complete,
204   // Recover the target block with the spare block.
205   //
206   Header  = FtwDevice->FtwLastWriteHeader;
207   Record  = FtwDevice->FtwLastWriteRecord;
208 
209   //
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.
212   //
213   if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
214     //
215     // If target block is working block,
216     // it also need to set SPARE_COMPLETED to spare block.
217     //
218     Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
219     Status = FtwUpdateFvState (
220               FtwDevice->FtwBackupFvb,
221               FtwDevice->SpareBlockSize,
222               FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
223               FtwDevice->FtwWorkSpaceBaseInSpare + Offset,
224               SPARE_COMPLETED
225               );
226     if (EFI_ERROR (Status)) {
227       return EFI_ABORTED;
228     }
229 
230     Status = FlushSpareBlockToWorkingBlock (FtwDevice);
231   } else if (IsBootBlock (FtwDevice, Fvb)) {
232     //
233     // Update boot block
234     //
235     Status = FlushSpareBlockToBootBlock (FtwDevice);
236   } else {
237     //
238     // Update blocks other than working block or boot block
239     //
240     NumberOfWriteBlocks = FTW_BLOCKS ((UINTN) (Record->Offset + Record->Length), BlockSize);
241     Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba, BlockSize, NumberOfWriteBlocks);
242   }
243 
244   if (EFI_ERROR (Status)) {
245     return EFI_ABORTED;
246   }
247   //
248   // Record the DestionationComplete in record
249   //
250   Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
251   Status = FtwUpdateFvState (
252             FtwDevice->FtwFvBlock,
253             FtwDevice->WorkBlockSize,
254             FtwDevice->FtwWorkSpaceLba,
255             FtwDevice->FtwWorkSpaceBase + Offset,
256             DEST_COMPLETED
257             );
258   if (EFI_ERROR (Status)) {
259     return EFI_ABORTED;
260   }
261 
262   Record->DestinationComplete = FTW_VALID_STATE;
263 
264   //
265   // If this is the last Write in these write sequence,
266   // set the complete flag of write header.
267   //
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,
275               WRITES_COMPLETED
276               );
277     Header->Complete = FTW_VALID_STATE;
278     if (EFI_ERROR (Status)) {
279       return EFI_ABORTED;
280     }
281   }
282 
283   return EFI_SUCCESS;
284 }
285 
286 /**
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.
291 
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.
301 
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.
309 
310 **/
311 EFI_STATUS
312 EFIAPI
FtwWrite(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN UINTN Length,IN VOID * PrivateData,IN EFI_HANDLE FvBlockHandle,IN VOID * Buffer)313 FtwWrite (
314   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
315   IN EFI_LBA                               Lba,
316   IN UINTN                                 Offset,
317   IN UINTN                                 Length,
318   IN VOID                                  *PrivateData,
319   IN EFI_HANDLE                            FvBlockHandle,
320   IN VOID                                  *Buffer
321   )
322 {
323   EFI_STATUS                          Status;
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;
328   UINTN                               MyLength;
329   UINTN                               MyOffset;
330   UINTN                               MyBufferSize;
331   UINT8                               *MyBuffer;
332   UINTN                               SpareBufferSize;
333   UINT8                               *SpareBuffer;
334   UINTN                               Index;
335   UINT8                               *Ptr;
336   EFI_PHYSICAL_ADDRESS                FvbPhysicalAddress;
337   UINTN                               BlockSize;
338   UINTN                               NumberOfBlocks;
339   UINTN                               NumberOfWriteBlocks;
340   UINTN                               WriteLength;
341 
342   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
343 
344   Status    = WorkSpaceRefresh (FtwDevice);
345   if (EFI_ERROR (Status)) {
346     return EFI_ABORTED;
347   }
348 
349   Header  = FtwDevice->FtwLastWriteHeader;
350   Record  = FtwDevice->FtwLastWriteRecord;
351 
352   if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
353     if (PrivateData == NULL) {
354       //
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.
357       //
358       Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
359       if (EFI_ERROR (Status)) {
360         return Status;
361       }
362     } else {
363       //
364       // Ftw Write Header is not allocated
365       // Additional private data is not NULL, the private data size can't be determined.
366       //
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;
370     }
371   }
372 
373   //
374   // If Record is out of the range of Header, return access denied.
375   //
376   if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
377     return EFI_ACCESS_DENIED;
378   }
379 
380   //
381   // Check the COMPLETE flag of last write header
382   //
383   if (Header->Complete == FTW_VALID_STATE) {
384     return EFI_ACCESS_DENIED;
385   }
386 
387   if (Record->DestinationComplete == FTW_VALID_STATE) {
388     return EFI_ACCESS_DENIED;
389   }
390 
391   if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
392     return EFI_NOT_READY;
393   }
394 
395   //
396   // Get the FVB protocol by handle
397   //
398   Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
399   if (EFI_ERROR (Status)) {
400     return EFI_NOT_FOUND;
401   }
402 
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));
406     return EFI_ABORTED;
407   }
408 
409   //
410   // Now, one FVB has one type of BlockSize.
411   //
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));
415     return EFI_ABORTED;
416   }
417 
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;
421 
422   //
423   // Check if the input data can fit within the spare block.
424   //
425   if (WriteLength > FtwDevice->SpareAreaLength) {
426     return EFI_BAD_BUFFER_SIZE;
427   }
428 
429   //
430   // Set BootBlockUpdate FLAG if it's updating boot block.
431   //
432   if (IsBootBlock (FtwDevice, Fvb)) {
433     Record->BootBlockUpdate = FTW_VALID_STATE;
434     //
435     // Boot Block and Spare Block should have same block size and block numbers.
436     //
437     ASSERT ((BlockSize == FtwDevice->SpareBlockSize) && (NumberOfWriteBlocks == FtwDevice->NumberOfSpareBlock));
438   }
439   //
440   // Write the record to the work space.
441   //
442   Record->Lba     = Lba;
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);
448   }
449 
450   MyOffset  = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
451   MyLength  = FTW_RECORD_SIZE (Header->PrivateDataSize);
452 
453   Status = WriteWorkSpaceData (
454              FtwDevice->FtwFvBlock,
455              FtwDevice->WorkBlockSize,
456              FtwDevice->FtwWorkSpaceLba,
457              FtwDevice->FtwWorkSpaceBase + MyOffset,
458              MyLength,
459              (UINT8 *) Record
460              );
461   if (EFI_ERROR (Status)) {
462     return EFI_ABORTED;
463   }
464   //
465   // Record has written to working block, then do the data.
466   //
467   //
468   // Allocate a memory buffer
469   //
470   MyBufferSize  = WriteLength;
471   MyBuffer      = AllocatePool (MyBufferSize);
472   if (MyBuffer == NULL) {
473     return EFI_OUT_OF_RESOURCES;
474   }
475   //
476   // Read all original data from target block to memory buffer
477   //
478   Ptr = MyBuffer;
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)) {
483       FreePool (MyBuffer);
484       return EFI_ABORTED;
485     }
486 
487     Ptr += MyLength;
488   }
489   //
490   // Overwrite the updating range data with
491   // the input buffer content
492   //
493   CopyMem (MyBuffer + Offset, Buffer, Length);
494 
495   //
496   // Try to keep the content of spare block
497   // Save spare block into a spare backup memory buffer (Sparebuffer)
498   //
499   SpareBufferSize = FtwDevice->SpareAreaLength;
500   SpareBuffer     = AllocatePool (SpareBufferSize);
501   if (SpareBuffer == NULL) {
502     FreePool (MyBuffer);
503     return EFI_OUT_OF_RESOURCES;
504   }
505 
506   Ptr = SpareBuffer;
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,
512                                         0,
513                                         &MyLength,
514                                         Ptr
515                                         );
516     if (EFI_ERROR (Status)) {
517       FreePool (MyBuffer);
518       FreePool (SpareBuffer);
519       return EFI_ABORTED;
520     }
521 
522     Ptr += MyLength;
523   }
524   //
525   // Write the memory buffer to spare block
526   // Do not assume Spare Block and Target Block have same block size
527   //
528   Status  = FtwEraseSpareBlock (FtwDevice);
529   if (EFI_ERROR (Status)) {
530     FreePool (MyBuffer);
531     FreePool (SpareBuffer);
532     return EFI_ABORTED;
533   }
534   Ptr     = MyBuffer;
535   for (Index = 0; MyBufferSize > 0; Index += 1) {
536     if (MyBufferSize > FtwDevice->SpareBlockSize) {
537       MyLength = FtwDevice->SpareBlockSize;
538     } else {
539       MyLength = MyBufferSize;
540     }
541     Status = FtwDevice->FtwBackupFvb->Write (
542                                         FtwDevice->FtwBackupFvb,
543                                         FtwDevice->FtwSpareLba + Index,
544                                         0,
545                                         &MyLength,
546                                         Ptr
547                                         );
548     if (EFI_ERROR (Status)) {
549       FreePool (MyBuffer);
550       FreePool (SpareBuffer);
551       return EFI_ABORTED;
552     }
553 
554     Ptr += MyLength;
555     MyBufferSize -= MyLength;
556   }
557   //
558   // Free MyBuffer
559   //
560   FreePool (MyBuffer);
561 
562   //
563   // Set the SpareComplete in the FTW record,
564   //
565   MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
566   Status = FtwUpdateFvState (
567             FtwDevice->FtwFvBlock,
568             FtwDevice->WorkBlockSize,
569             FtwDevice->FtwWorkSpaceLba,
570             FtwDevice->FtwWorkSpaceBase + MyOffset,
571             SPARE_COMPLETED
572             );
573   if (EFI_ERROR (Status)) {
574     FreePool (SpareBuffer);
575     return EFI_ABORTED;
576   }
577 
578   Record->SpareComplete = FTW_VALID_STATE;
579 
580   //
581   //  Since the content has already backuped in spare block, the write is
582   //  guaranteed to be completed with fault tolerant manner.
583   //
584   Status = FtwWriteRecord (This, Fvb, BlockSize);
585   if (EFI_ERROR (Status)) {
586     FreePool (SpareBuffer);
587     return EFI_ABORTED;
588   }
589   //
590   // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
591   //
592   Status  = FtwEraseSpareBlock (FtwDevice);
593   if (EFI_ERROR (Status)) {
594     FreePool (SpareBuffer);
595     return EFI_ABORTED;
596   }
597   Ptr     = 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,
603                                         0,
604                                         &MyLength,
605                                         Ptr
606                                         );
607     if (EFI_ERROR (Status)) {
608       FreePool (SpareBuffer);
609       return EFI_ABORTED;
610     }
611 
612     Ptr += MyLength;
613   }
614   //
615   // All success.
616   //
617   FreePool (SpareBuffer);
618 
619   DEBUG (
620     (EFI_D_INFO,
621     "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
622     Lba,
623     Offset,
624     Length)
625     );
626 
627   return EFI_SUCCESS;
628 }
629 
630 /**
631   Restarts a previously interrupted write. The caller must provide the
632   block protocol needed to complete the interrupted write.
633 
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.
637 
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
642 
643 **/
644 EFI_STATUS
645 EFIAPI
FtwRestart(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,IN EFI_HANDLE FvBlockHandle)646 FtwRestart (
647   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
648   IN EFI_HANDLE                            FvBlockHandle
649   )
650 {
651   EFI_STATUS                          Status;
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;
656   UINTN                               BlockSize;
657   UINTN                               NumberOfBlocks;
658 
659   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
660 
661   Status    = WorkSpaceRefresh (FtwDevice);
662   if (EFI_ERROR (Status)) {
663     return EFI_ABORTED;
664   }
665 
666   Header  = FtwDevice->FtwLastWriteHeader;
667   Record  = FtwDevice->FtwLastWriteRecord;
668 
669   //
670   // Spare Complete but Destination not complete,
671   // Recover the targt block with the spare block.
672   //
673   Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
674   if (EFI_ERROR (Status)) {
675     return EFI_NOT_FOUND;
676   }
677 
678   //
679   // Now, one FVB has one type of BlockSize
680   //
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));
684     return EFI_ABORTED;
685   }
686 
687   //
688   // Check the COMPLETE flag of last write header
689   //
690   if (Header->Complete == FTW_VALID_STATE) {
691     return EFI_ACCESS_DENIED;
692   }
693 
694   //
695   // Check the flags of last write record
696   //
697   if (Record->DestinationComplete == FTW_VALID_STATE) {
698     return EFI_ACCESS_DENIED;
699   }
700 
701   if ((Record->SpareComplete != FTW_VALID_STATE)) {
702     return EFI_ABORTED;
703   }
704 
705   //
706   //  Since the content has already backuped in spare block, the write is
707   //  guaranteed to be completed with fault tolerant manner.
708   //
709   Status = FtwWriteRecord (This, Fvb, BlockSize);
710   if (EFI_ERROR (Status)) {
711     return EFI_ABORTED;
712   }
713 
714   //
715   // Erase Spare block
716   // This is restart, no need to keep spareblock content.
717   //
718   Status = FtwEraseSpareBlock (FtwDevice);
719   if (EFI_ERROR (Status)) {
720     return EFI_ABORTED;
721   }
722 
723   DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
724   return EFI_SUCCESS;
725 }
726 
727 /**
728   Aborts all previous allocated writes.
729 
730   @param This                  The pointer to this protocol instance.
731 
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.
735 
736 **/
737 EFI_STATUS
738 EFIAPI
FtwAbort(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This)739 FtwAbort (
740   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This
741   )
742 {
743   EFI_STATUS      Status;
744   UINTN           Offset;
745   EFI_FTW_DEVICE  *FtwDevice;
746 
747   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
748 
749   Status    = WorkSpaceRefresh (FtwDevice);
750   if (EFI_ERROR (Status)) {
751     return EFI_ABORTED;
752   }
753 
754   if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
755     return EFI_NOT_FOUND;
756   }
757 
758   if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
759     return EFI_NOT_FOUND;
760   }
761   //
762   // Update the complete state of the header as VALID and abort.
763   //
764   Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
765   Status = FtwUpdateFvState (
766             FtwDevice->FtwFvBlock,
767             FtwDevice->WorkBlockSize,
768             FtwDevice->FtwWorkSpaceLba,
769             FtwDevice->FtwWorkSpaceBase + Offset,
770             WRITES_COMPLETED
771             );
772   if (EFI_ERROR (Status)) {
773     return EFI_ABORTED;
774   }
775 
776   FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
777 
778   DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
779   return EFI_SUCCESS;
780 }
781 
782 /**
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.
787 
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.
798 
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
803 
804 **/
805 EFI_STATUS
806 EFIAPI
FtwGetLastWrite(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,OUT EFI_GUID * CallerId,OUT EFI_LBA * Lba,OUT UINTN * Offset,OUT UINTN * Length,IN OUT UINTN * PrivateDataSize,OUT VOID * PrivateData,OUT BOOLEAN * Complete)807 FtwGetLastWrite (
808   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *This,
809   OUT EFI_GUID                             *CallerId,
810   OUT EFI_LBA                              *Lba,
811   OUT UINTN                                *Offset,
812   OUT UINTN                                *Length,
813   IN OUT UINTN                             *PrivateDataSize,
814   OUT VOID                                 *PrivateData,
815   OUT BOOLEAN                              *Complete
816   )
817 {
818   EFI_STATUS                      Status;
819   EFI_FTW_DEVICE                  *FtwDevice;
820   EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
821   EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
822 
823   if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
824     return EFI_UNSUPPORTED;
825   }
826 
827   FtwDevice = FTW_CONTEXT_FROM_THIS (This);
828 
829   Status    = WorkSpaceRefresh (FtwDevice);
830   if (EFI_ERROR (Status)) {
831     return EFI_ABORTED;
832   }
833 
834   Header  = FtwDevice->FtwLastWriteHeader;
835   Record  = FtwDevice->FtwLastWriteRecord;
836 
837   //
838   // If Header is incompleted and the last record has completed, then
839   // call Abort() to set the Header->Complete FLAG.
840   //
841   if ((Header->Complete != FTW_VALID_STATE) &&
842       (Record->DestinationComplete == FTW_VALID_STATE) &&
843       IsLastRecordOfWrites (Header, Record)
844         ) {
845 
846     Status    = FtwAbort (This);
847     *Complete = TRUE;
848     return EFI_NOT_FOUND;
849   }
850   //
851   // If there is no write header/record, return not found.
852   //
853   if (Header->HeaderAllocated != FTW_VALID_STATE) {
854     *Complete = TRUE;
855     return EFI_NOT_FOUND;
856   }
857   //
858   // If this record SpareComplete has not set, then it can not restart.
859   //
860   if (Record->SpareComplete != FTW_VALID_STATE) {
861     Status = GetPreviousRecordOfWrites (Header, &Record);
862     if (EFI_ERROR (Status)) {
863       FtwAbort (This);
864       *Complete = TRUE;
865       return EFI_NOT_FOUND;
866     }
867     ASSERT (Record != NULL);
868   }
869 
870   //
871   // Fill all the requested values
872   //
873   CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
874   *Lba      = Record->Lba;
875   *Offset   = (UINTN) Record->Offset;
876   *Length   = (UINTN) Record->Length;
877   *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
878 
879   if (*PrivateDataSize < Header->PrivateDataSize) {
880     *PrivateDataSize  = (UINTN) Header->PrivateDataSize;
881     PrivateData       = NULL;
882     Status            = EFI_BUFFER_TOO_SMALL;
883   } else {
884     *PrivateDataSize = (UINTN) Header->PrivateDataSize;
885     CopyMem (PrivateData, Record + 1, *PrivateDataSize);
886     Status = EFI_SUCCESS;
887   }
888 
889   DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
890 
891   return Status;
892 }
893 
894