]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
MdeModulePkg: Variable drivers robustly handle crashes during Reclaim().
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FaultTolerantWrite.c
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 - 2013, 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
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
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 Length;
85 UINTN Offset;
86 EFI_FTW_DEVICE *FtwDevice;
87 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
88
89 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
90
91 Status = WorkSpaceRefresh (FtwDevice);
92 if (EFI_ERROR (Status)) {
93 return EFI_ABORTED;
94 }
95 //
96 // Check if there is enough space for the coming allocation
97 //
98 if (FTW_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;
101 }
102 //
103 // Find the last write header and record.
104 // If the FtwHeader is complete, skip the completed last write header/records
105 //
106 FtwHeader = FtwDevice->FtwLastWriteHeader;
107
108 //
109 // Previous write has not completed, access denied.
110 //
111 if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
112 return EFI_ACCESS_DENIED;
113 }
114 //
115 // If workspace is not enough, then reclaim workspace
116 //
117 Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
118 if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
119 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
120 if (EFI_ERROR (Status)) {
121 return EFI_ABORTED;
122 }
123
124 FtwHeader = FtwDevice->FtwLastWriteHeader;
125 }
126 //
127 // Prepare FTW write header,
128 // overwrite the buffer and write to workspace.
129 //
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;
136
137 Length = sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
138 Status = FtwDevice->FtwFvBlock->Write (
139 FtwDevice->FtwFvBlock,
140 FtwDevice->FtwWorkSpaceLba,
141 FtwDevice->FtwWorkSpaceBase + Offset,
142 &Length,
143 (UINT8 *) FtwHeader
144 );
145 if (EFI_ERROR (Status)) {
146 return EFI_ABORTED;
147 }
148 //
149 // Update Header->WriteAllocated as VALID
150 //
151 Status = FtwUpdateFvState (
152 FtwDevice->FtwFvBlock,
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_ERROR,
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 mannaer.
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
181 @retval EFI_SUCCESS The function completed successfully
182 @retval EFI_ABORTED The function could not complete successfully
183
184 **/
185 EFI_STATUS
186 FtwWriteRecord (
187 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
188 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
189 )
190 {
191 EFI_STATUS Status;
192 EFI_FTW_DEVICE *FtwDevice;
193 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
194 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
195 UINTN Offset;
196 EFI_LBA WorkSpaceLbaOffset;
197
198 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
199
200 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
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->FtwSpareLba + WorkSpaceLbaOffset,
222 FtwDevice->FtwWorkSpaceBase + Offset,
223 SPARE_COMPLETED
224 );
225 if (EFI_ERROR (Status)) {
226 return EFI_ABORTED;
227 }
228
229 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
230 } else if (IsBootBlock (FtwDevice, Fvb, Record->Lba)) {
231 //
232 // Update boot block
233 //
234 Status = FlushSpareBlockToBootBlock (FtwDevice);
235 } else {
236 //
237 // Update blocks other than working block or boot block
238 //
239 Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba);
240 }
241
242 if (EFI_ERROR (Status)) {
243 return EFI_ABORTED;
244 }
245 //
246 // Record the DestionationComplete in record
247 //
248 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
249 Status = FtwUpdateFvState (
250 FtwDevice->FtwFvBlock,
251 FtwDevice->FtwWorkSpaceLba,
252 FtwDevice->FtwWorkSpaceBase + Offset,
253 DEST_COMPLETED
254 );
255 if (EFI_ERROR (Status)) {
256 return EFI_ABORTED;
257 }
258
259 Record->DestinationComplete = FTW_VALID_STATE;
260
261 //
262 // If this is the last Write in these write sequence,
263 // set the complete flag of write header.
264 //
265 if (IsLastRecordOfWrites (Header, Record)) {
266 Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
267 Status = FtwUpdateFvState (
268 FtwDevice->FtwFvBlock,
269 FtwDevice->FtwWorkSpaceLba,
270 FtwDevice->FtwWorkSpaceBase + Offset,
271 WRITES_COMPLETED
272 );
273 Header->Complete = FTW_VALID_STATE;
274 if (EFI_ERROR (Status)) {
275 return EFI_ABORTED;
276 }
277 }
278
279 return EFI_SUCCESS;
280 }
281
282 /**
283 Starts a target block update. This function will record data about write
284 in fault tolerant storage and will complete the write in a recoverable
285 manner, ensuring at all times that either the original contents or
286 the modified contents are available.
287
288 @param This The pointer to this protocol instance.
289 @param Lba The logical block address of the target block.
290 @param Offset The offset within the target block to place the data.
291 @param Length The number of bytes to write to the target block.
292 @param PrivateData A pointer to private data that the caller requires to
293 complete any pending writes in the event of a fault.
294 @param FvBlockHandle The handle of FVB protocol that provides services for
295 reading, writing, and erasing the target block.
296 @param Buffer The data to write.
297
298 @retval EFI_SUCCESS The function completed successfully
299 @retval EFI_ABORTED The function could not complete successfully.
300 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
301 Offset + *NumBytes > SpareAreaLength.
302 @retval EFI_ACCESS_DENIED No writes have been allocated.
303 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
304 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
305
306 **/
307 EFI_STATUS
308 EFIAPI
309 FtwWrite (
310 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
311 IN EFI_LBA Lba,
312 IN UINTN Offset,
313 IN UINTN Length,
314 IN VOID *PrivateData,
315 IN EFI_HANDLE FvBlockHandle,
316 IN VOID *Buffer
317 )
318 {
319 EFI_STATUS Status;
320 EFI_FTW_DEVICE *FtwDevice;
321 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
322 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
323 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
324 UINTN MyLength;
325 UINTN MyOffset;
326 UINTN MyBufferSize;
327 UINT8 *MyBuffer;
328 UINTN SpareBufferSize;
329 UINT8 *SpareBuffer;
330 UINTN Index;
331 UINT8 *Ptr;
332 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
333
334 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
335
336 Status = WorkSpaceRefresh (FtwDevice);
337 if (EFI_ERROR (Status)) {
338 return EFI_ABORTED;
339 }
340
341 Header = FtwDevice->FtwLastWriteHeader;
342 Record = FtwDevice->FtwLastWriteRecord;
343
344 if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
345 if (PrivateData == NULL) {
346 //
347 // Ftw Write Header is not allocated.
348 // No additional private data, the private data size is zero. Number of record can be set to 1.
349 //
350 Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
351 if (EFI_ERROR (Status)) {
352 return Status;
353 }
354 } else {
355 //
356 // Ftw Write Header is not allocated
357 // Additional private data is not NULL, the private data size can't be determined.
358 //
359 DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
360 DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
361 return EFI_NOT_READY;
362 }
363 }
364
365 //
366 // If Record is out of the range of Header, return access denied.
367 //
368 if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
369 return EFI_ACCESS_DENIED;
370 }
371
372 //
373 // Check the COMPLETE flag of last write header
374 //
375 if (Header->Complete == FTW_VALID_STATE) {
376 return EFI_ACCESS_DENIED;
377 }
378
379 if (Record->DestinationComplete == FTW_VALID_STATE) {
380 return EFI_ACCESS_DENIED;
381 }
382
383 if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
384 return EFI_NOT_READY;
385 }
386 //
387 // Check if the input data can fit within the target block
388 //
389 if ((Offset + Length) > FtwDevice->SpareAreaLength) {
390 return EFI_BAD_BUFFER_SIZE;
391 }
392 //
393 // Get the FVB protocol by handle
394 //
395 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
396 if (EFI_ERROR (Status)) {
397 return EFI_NOT_FOUND;
398 }
399
400 Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
401 if (EFI_ERROR (Status)) {
402 DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));
403 return EFI_ABORTED;
404 }
405
406 //
407 // Set BootBlockUpdate FLAG if it's updating boot block.
408 //
409 if (IsBootBlock (FtwDevice, Fvb, Lba)) {
410 Record->BootBlockUpdate = FTW_VALID_STATE;
411 }
412 //
413 // Write the record to the work space.
414 //
415 Record->Lba = Lba;
416 Record->Offset = Offset;
417 Record->Length = Length;
418 Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * FtwDevice->BlockSize) - (INT64) FtwDevice->SpareAreaAddress;
419 if (PrivateData != NULL) {
420 CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);
421 }
422
423 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
424 MyLength = FTW_RECORD_SIZE (Header->PrivateDataSize);
425
426 Status = FtwDevice->FtwFvBlock->Write (
427 FtwDevice->FtwFvBlock,
428 FtwDevice->FtwWorkSpaceLba,
429 FtwDevice->FtwWorkSpaceBase + MyOffset,
430 &MyLength,
431 (UINT8 *) Record
432 );
433 if (EFI_ERROR (Status)) {
434 return EFI_ABORTED;
435 }
436 //
437 // Record has written to working block, then do the data.
438 //
439 //
440 // Allocate a memory buffer
441 //
442 MyBufferSize = FtwDevice->SpareAreaLength;
443 MyBuffer = AllocatePool (MyBufferSize);
444 if (MyBuffer == NULL) {
445 return EFI_OUT_OF_RESOURCES;
446 }
447 //
448 // Read all original data from target block to memory buffer
449 //
450 Ptr = MyBuffer;
451 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
452 MyLength = FtwDevice->BlockSize;
453 Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
454 if (EFI_ERROR (Status)) {
455 FreePool (MyBuffer);
456 return EFI_ABORTED;
457 }
458
459 Ptr += MyLength;
460 }
461 //
462 // Overwrite the updating range data with
463 // the input buffer content
464 //
465 CopyMem (MyBuffer + Offset, Buffer, Length);
466
467 //
468 // Try to keep the content of spare block
469 // Save spare block into a spare backup memory buffer (Sparebuffer)
470 //
471 SpareBufferSize = FtwDevice->SpareAreaLength;
472 SpareBuffer = AllocatePool (SpareBufferSize);
473 if (SpareBuffer == NULL) {
474 FreePool (MyBuffer);
475 return EFI_OUT_OF_RESOURCES;
476 }
477
478 Ptr = SpareBuffer;
479 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
480 MyLength = FtwDevice->BlockSize;
481 Status = FtwDevice->FtwBackupFvb->Read (
482 FtwDevice->FtwBackupFvb,
483 FtwDevice->FtwSpareLba + Index,
484 0,
485 &MyLength,
486 Ptr
487 );
488 if (EFI_ERROR (Status)) {
489 FreePool (MyBuffer);
490 FreePool (SpareBuffer);
491 return EFI_ABORTED;
492 }
493
494 Ptr += MyLength;
495 }
496 //
497 // Write the memory buffer to spare block
498 //
499 Status = FtwEraseSpareBlock (FtwDevice);
500 Ptr = MyBuffer;
501 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
502 MyLength = FtwDevice->BlockSize;
503 Status = FtwDevice->FtwBackupFvb->Write (
504 FtwDevice->FtwBackupFvb,
505 FtwDevice->FtwSpareLba + Index,
506 0,
507 &MyLength,
508 Ptr
509 );
510 if (EFI_ERROR (Status)) {
511 FreePool (MyBuffer);
512 FreePool (SpareBuffer);
513 return EFI_ABORTED;
514 }
515
516 Ptr += MyLength;
517 }
518 //
519 // Free MyBuffer
520 //
521 FreePool (MyBuffer);
522
523 //
524 // Set the SpareComplete in the FTW record,
525 //
526 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
527 Status = FtwUpdateFvState (
528 FtwDevice->FtwFvBlock,
529 FtwDevice->FtwWorkSpaceLba,
530 FtwDevice->FtwWorkSpaceBase + MyOffset,
531 SPARE_COMPLETED
532 );
533 if (EFI_ERROR (Status)) {
534 FreePool (SpareBuffer);
535 return EFI_ABORTED;
536 }
537
538 Record->SpareComplete = FTW_VALID_STATE;
539
540 //
541 // Since the content has already backuped in spare block, the write is
542 // guaranteed to be completed with fault tolerant manner.
543 //
544 Status = FtwWriteRecord (This, Fvb);
545 if (EFI_ERROR (Status)) {
546 FreePool (SpareBuffer);
547 return EFI_ABORTED;
548 }
549 //
550 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
551 //
552 Status = FtwEraseSpareBlock (FtwDevice);
553 Ptr = SpareBuffer;
554 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
555 MyLength = FtwDevice->BlockSize;
556 Status = FtwDevice->FtwBackupFvb->Write (
557 FtwDevice->FtwBackupFvb,
558 FtwDevice->FtwSpareLba + Index,
559 0,
560 &MyLength,
561 Ptr
562 );
563 if (EFI_ERROR (Status)) {
564 FreePool (SpareBuffer);
565 return EFI_ABORTED;
566 }
567
568 Ptr += MyLength;
569 }
570 //
571 // All success.
572 //
573 FreePool (SpareBuffer);
574
575 DEBUG (
576 (EFI_D_ERROR,
577 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
578 Lba,
579 Offset,
580 Length)
581 );
582
583 return EFI_SUCCESS;
584 }
585
586 /**
587 Restarts a previously interrupted write. The caller must provide the
588 block protocol needed to complete the interrupted write.
589
590 @param This The pointer to this protocol instance.
591 @param FvBlockHandle The handle of FVB protocol that provides services for
592 reading, writing, and erasing the target block.
593
594 @retval EFI_SUCCESS The function completed successfully
595 @retval EFI_ACCESS_DENIED No pending writes exist
596 @retval EFI_NOT_FOUND FVB protocol not found by the handle
597 @retval EFI_ABORTED The function could not complete successfully
598
599 **/
600 EFI_STATUS
601 EFIAPI
602 FtwRestart (
603 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
604 IN EFI_HANDLE FvBlockHandle
605 )
606 {
607 EFI_STATUS Status;
608 EFI_FTW_DEVICE *FtwDevice;
609 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
610 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
611 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
612
613 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
614
615 Status = WorkSpaceRefresh (FtwDevice);
616 if (EFI_ERROR (Status)) {
617 return EFI_ABORTED;
618 }
619
620 Header = FtwDevice->FtwLastWriteHeader;
621 Record = FtwDevice->FtwLastWriteRecord;
622
623 //
624 // Spare Complete but Destination not complete,
625 // Recover the targt block with the spare block.
626 //
627 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
628 if (EFI_ERROR (Status)) {
629 return EFI_NOT_FOUND;
630 }
631
632 //
633 // Check the COMPLETE flag of last write header
634 //
635 if (Header->Complete == FTW_VALID_STATE) {
636 return EFI_ACCESS_DENIED;
637 }
638
639 //
640 // Check the flags of last write record
641 //
642 if (Record->DestinationComplete == FTW_VALID_STATE) {
643 return EFI_ACCESS_DENIED;
644 }
645
646 if ((Record->SpareComplete != FTW_VALID_STATE)) {
647 return EFI_ABORTED;
648 }
649
650 //
651 // Since the content has already backuped in spare block, the write is
652 // guaranteed to be completed with fault tolerant manner.
653 //
654 Status = FtwWriteRecord (This, Fvb);
655 if (EFI_ERROR (Status)) {
656 return EFI_ABORTED;
657 }
658
659 //
660 // Erase Spare block
661 // This is restart, no need to keep spareblock content.
662 //
663 FtwEraseSpareBlock (FtwDevice);
664
665 DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));
666 return EFI_SUCCESS;
667 }
668
669 /**
670 Aborts all previous allocated writes.
671
672 @param This The pointer to this protocol instance.
673
674 @retval EFI_SUCCESS The function completed successfully
675 @retval EFI_ABORTED The function could not complete successfully.
676 @retval EFI_NOT_FOUND No allocated writes exist.
677
678 **/
679 EFI_STATUS
680 EFIAPI
681 FtwAbort (
682 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
683 )
684 {
685 EFI_STATUS Status;
686 UINTN Offset;
687 EFI_FTW_DEVICE *FtwDevice;
688
689 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
690
691 Status = WorkSpaceRefresh (FtwDevice);
692 if (EFI_ERROR (Status)) {
693 return EFI_ABORTED;
694 }
695
696 if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
697 return EFI_NOT_FOUND;
698 }
699
700 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
701 return EFI_NOT_FOUND;
702 }
703 //
704 // Update the complete state of the header as VALID and abort.
705 //
706 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
707 Status = FtwUpdateFvState (
708 FtwDevice->FtwFvBlock,
709 FtwDevice->FtwWorkSpaceLba,
710 FtwDevice->FtwWorkSpaceBase + Offset,
711 WRITES_COMPLETED
712 );
713 if (EFI_ERROR (Status)) {
714 return EFI_ABORTED;
715 }
716
717 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
718
719 DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));
720 return EFI_SUCCESS;
721 }
722
723 /**
724 Starts a target block update. This records information about the write
725 in fault tolerant storage and will complete the write in a recoverable
726 manner, ensuring at all times that either the original contents or
727 the modified contents are available.
728
729 @param This The pointer to this protocol instance.
730 @param CallerId The GUID identifying the last write.
731 @param Lba The logical block address of the last write.
732 @param Offset The offset within the block of the last write.
733 @param Length The length of the last write.
734 @param PrivateDataSize bytes from the private data
735 stored for this write.
736 @param PrivateData A pointer to a buffer. The function will copy
737 @param Complete A Boolean value with TRUE indicating
738 that the write was completed.
739
740 @retval EFI_SUCCESS The function completed successfully
741 @retval EFI_ABORTED The function could not complete successfully
742 @retval EFI_NOT_FOUND No allocated writes exist
743 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
744
745 **/
746 EFI_STATUS
747 EFIAPI
748 FtwGetLastWrite (
749 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
750 OUT EFI_GUID *CallerId,
751 OUT EFI_LBA *Lba,
752 OUT UINTN *Offset,
753 OUT UINTN *Length,
754 IN OUT UINTN *PrivateDataSize,
755 OUT VOID *PrivateData,
756 OUT BOOLEAN *Complete
757 )
758 {
759 EFI_STATUS Status;
760 EFI_FTW_DEVICE *FtwDevice;
761 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
762 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
763
764 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
765 return EFI_UNSUPPORTED;
766 }
767
768 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
769
770 Status = WorkSpaceRefresh (FtwDevice);
771 if (EFI_ERROR (Status)) {
772 return EFI_ABORTED;
773 }
774
775 Header = FtwDevice->FtwLastWriteHeader;
776 Record = FtwDevice->FtwLastWriteRecord;
777
778 //
779 // If Header is incompleted and the last record has completed, then
780 // call Abort() to set the Header->Complete FLAG.
781 //
782 if ((Header->Complete != FTW_VALID_STATE) &&
783 (Record->DestinationComplete == FTW_VALID_STATE) &&
784 IsLastRecordOfWrites (Header, Record)
785 ) {
786
787 Status = FtwAbort (This);
788 *Complete = TRUE;
789 return EFI_NOT_FOUND;
790 }
791 //
792 // If there is no write header/record, return not found.
793 //
794 if (Header->HeaderAllocated != FTW_VALID_STATE) {
795 *Complete = TRUE;
796 return EFI_NOT_FOUND;
797 }
798 //
799 // If this record SpareComplete has not set, then it can not restart.
800 //
801 if (Record->SpareComplete != FTW_VALID_STATE) {
802 Status = GetPreviousRecordOfWrites (Header, &Record);
803 if (EFI_ERROR (Status)) {
804 FtwAbort (This);
805 *Complete = TRUE;
806 return EFI_NOT_FOUND;
807 }
808 ASSERT (Record != NULL);
809 }
810
811 //
812 // Fill all the requested values
813 //
814 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
815 *Lba = Record->Lba;
816 *Offset = (UINTN) Record->Offset;
817 *Length = (UINTN) Record->Length;
818 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
819
820 if (*PrivateDataSize < Header->PrivateDataSize) {
821 *PrivateDataSize = (UINTN) Header->PrivateDataSize;
822 PrivateData = NULL;
823 Status = EFI_BUFFER_TOO_SMALL;
824 } else {
825 *PrivateDataSize = (UINTN) Header->PrivateDataSize;
826 CopyMem (PrivateData, Record + 1, *PrivateDataSize);
827 Status = EFI_SUCCESS;
828 }
829
830 DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));
831
832 return Status;
833 }
834