]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
Add SMM Variable implementation.
[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 - 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
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 (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 + 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
197 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
198
199 //
200 // Spare Complete but Destination not complete,
201 // Recover the target block with the spare block.
202 //
203 Header = FtwDevice->FtwLastWriteHeader;
204 Record = FtwDevice->FtwLastWriteRecord;
205
206 //
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.
209 //
210 if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
211 //
212 // If target block is working block,
213 // it also need to set SPARE_COMPLETED to spare block.
214 //
215 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
216 Status = FtwUpdateFvState (
217 FtwDevice->FtwBackupFvb,
218 FtwDevice->FtwWorkSpaceLba,
219 FtwDevice->FtwWorkSpaceBase + Offset,
220 SPARE_COMPLETED
221 );
222 if (EFI_ERROR (Status)) {
223 return EFI_ABORTED;
224 }
225
226 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
227 } else if (IsBootBlock (FtwDevice, Fvb, Record->Lba)) {
228 //
229 // Update boot block
230 //
231 Status = FlushSpareBlockToBootBlock (FtwDevice);
232 } else {
233 //
234 // Update blocks other than working block or boot block
235 //
236 Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba);
237 }
238
239 if (EFI_ERROR (Status)) {
240 return EFI_ABORTED;
241 }
242 //
243 // Record the DestionationComplete in record
244 //
245 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
246 Status = FtwUpdateFvState (
247 FtwDevice->FtwFvBlock,
248 FtwDevice->FtwWorkSpaceLba,
249 FtwDevice->FtwWorkSpaceBase + Offset,
250 DEST_COMPLETED
251 );
252 if (EFI_ERROR (Status)) {
253 return EFI_ABORTED;
254 }
255
256 Record->DestinationComplete = FTW_VALID_STATE;
257
258 //
259 // If this is the last Write in these write sequence,
260 // set the complete flag of write header.
261 //
262 if (IsLastRecordOfWrites (Header, Record)) {
263 Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
264 Status = FtwUpdateFvState (
265 FtwDevice->FtwFvBlock,
266 FtwDevice->FtwWorkSpaceLba,
267 FtwDevice->FtwWorkSpaceBase + Offset,
268 WRITES_COMPLETED
269 );
270 Header->Complete = FTW_VALID_STATE;
271 if (EFI_ERROR (Status)) {
272 return EFI_ABORTED;
273 }
274 }
275
276 return EFI_SUCCESS;
277 }
278
279 /**
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.
284
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.
294
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.
302
303 **/
304 EFI_STATUS
305 EFIAPI
306 FtwWrite (
307 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
308 IN EFI_LBA Lba,
309 IN UINTN Offset,
310 IN UINTN Length,
311 IN VOID *PrivateData,
312 IN EFI_HANDLE FvBlockHandle,
313 IN VOID *Buffer
314 )
315 {
316 EFI_STATUS Status;
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;
321 UINTN MyLength;
322 UINTN MyOffset;
323 UINTN MyBufferSize;
324 UINT8 *MyBuffer;
325 UINTN SpareBufferSize;
326 UINT8 *SpareBuffer;
327 UINTN Index;
328 UINT8 *Ptr;
329 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
330
331 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
332
333 Status = WorkSpaceRefresh (FtwDevice);
334 if (EFI_ERROR (Status)) {
335 return EFI_ABORTED;
336 }
337
338 Header = FtwDevice->FtwLastWriteHeader;
339 Record = FtwDevice->FtwLastWriteRecord;
340
341 if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
342 if (PrivateData == NULL) {
343 //
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.
346 //
347 Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
348 if (EFI_ERROR (Status)) {
349 return Status;
350 }
351 } else {
352 //
353 // Ftw Write Header is not allocated
354 // Additional private data is not NULL, the private data size can't be determined.
355 //
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;
359 }
360 }
361
362 //
363 // If Record is out of the range of Header, return access denied.
364 //
365 if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
366 return EFI_ACCESS_DENIED;
367 }
368
369 //
370 // Check the COMPLETE flag of last write header
371 //
372 if (Header->Complete == FTW_VALID_STATE) {
373 return EFI_ACCESS_DENIED;
374 }
375
376 if (Record->DestinationComplete == FTW_VALID_STATE) {
377 return EFI_ACCESS_DENIED;
378 }
379
380 if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
381 return EFI_NOT_READY;
382 }
383 //
384 // Check if the input data can fit within the target block
385 //
386 if ((Offset + Length) > FtwDevice->SpareAreaLength) {
387 return EFI_BAD_BUFFER_SIZE;
388 }
389 //
390 // Get the FVB protocol by handle
391 //
392 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
393 if (EFI_ERROR (Status)) {
394 return EFI_NOT_FOUND;
395 }
396
397 Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
398 if (EFI_ERROR (Status)) {
399 DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));
400 return EFI_ABORTED;
401 }
402
403 //
404 // Set BootBlockUpdate FLAG if it's updating boot block.
405 //
406 if (IsBootBlock (FtwDevice, Fvb, Lba)) {
407 Record->BootBlockUpdate = FTW_VALID_STATE;
408 }
409 //
410 // Write the record to the work space.
411 //
412 Record->Lba = Lba;
413 Record->Offset = Offset;
414 Record->Length = Length;
415 Record->FvBaseAddress = FvbPhysicalAddress;
416 if (PrivateData != NULL) {
417 CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize);
418 }
419
420 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
421 MyLength = RECORD_SIZE (Header->PrivateDataSize);
422
423 Status = FtwDevice->FtwFvBlock->Write (
424 FtwDevice->FtwFvBlock,
425 FtwDevice->FtwWorkSpaceLba,
426 FtwDevice->FtwWorkSpaceBase + MyOffset,
427 &MyLength,
428 (UINT8 *) Record
429 );
430 if (EFI_ERROR (Status)) {
431 return EFI_ABORTED;
432 }
433 //
434 // Record has written to working block, then do the data.
435 //
436 //
437 // Allocate a memory buffer
438 //
439 MyBufferSize = FtwDevice->SpareAreaLength;
440 MyBuffer = AllocatePool (MyBufferSize);
441 if (MyBuffer == NULL) {
442 return EFI_OUT_OF_RESOURCES;
443 }
444 //
445 // Read all original data from target block to memory buffer
446 //
447 Ptr = MyBuffer;
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)) {
452 FreePool (MyBuffer);
453 return EFI_ABORTED;
454 }
455
456 Ptr += MyLength;
457 }
458 //
459 // Overwrite the updating range data with
460 // the input buffer content
461 //
462 CopyMem (MyBuffer + Offset, Buffer, Length);
463
464 //
465 // Try to keep the content of spare block
466 // Save spare block into a spare backup memory buffer (Sparebuffer)
467 //
468 SpareBufferSize = FtwDevice->SpareAreaLength;
469 SpareBuffer = AllocatePool (SpareBufferSize);
470 if (SpareBuffer == NULL) {
471 FreePool (MyBuffer);
472 return EFI_OUT_OF_RESOURCES;
473 }
474
475 Ptr = SpareBuffer;
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,
481 0,
482 &MyLength,
483 Ptr
484 );
485 if (EFI_ERROR (Status)) {
486 FreePool (MyBuffer);
487 FreePool (SpareBuffer);
488 return EFI_ABORTED;
489 }
490
491 Ptr += MyLength;
492 }
493 //
494 // Write the memory buffer to spare block
495 //
496 Status = FtwEraseSpareBlock (FtwDevice);
497 Ptr = MyBuffer;
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,
503 0,
504 &MyLength,
505 Ptr
506 );
507 if (EFI_ERROR (Status)) {
508 FreePool (MyBuffer);
509 FreePool (SpareBuffer);
510 return EFI_ABORTED;
511 }
512
513 Ptr += MyLength;
514 }
515 //
516 // Free MyBuffer
517 //
518 FreePool (MyBuffer);
519
520 //
521 // Set the SpareComplete in the FTW record,
522 //
523 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
524 Status = FtwUpdateFvState (
525 FtwDevice->FtwFvBlock,
526 FtwDevice->FtwWorkSpaceLba,
527 FtwDevice->FtwWorkSpaceBase + MyOffset,
528 SPARE_COMPLETED
529 );
530 if (EFI_ERROR (Status)) {
531 FreePool (SpareBuffer);
532 return EFI_ABORTED;
533 }
534
535 Record->SpareComplete = FTW_VALID_STATE;
536
537 //
538 // Since the content has already backuped in spare block, the write is
539 // guaranteed to be completed with fault tolerant manner.
540 //
541 Status = FtwWriteRecord (This, Fvb);
542 if (EFI_ERROR (Status)) {
543 FreePool (SpareBuffer);
544 return EFI_ABORTED;
545 }
546 //
547 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
548 //
549 Status = FtwEraseSpareBlock (FtwDevice);
550 Ptr = SpareBuffer;
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,
556 0,
557 &MyLength,
558 Ptr
559 );
560 if (EFI_ERROR (Status)) {
561 FreePool (SpareBuffer);
562 return EFI_ABORTED;
563 }
564
565 Ptr += MyLength;
566 }
567 //
568 // All success.
569 //
570 FreePool (SpareBuffer);
571
572 DEBUG (
573 (EFI_D_ERROR,
574 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
575 Lba,
576 Offset,
577 Length)
578 );
579
580 return EFI_SUCCESS;
581 }
582
583 /**
584 Restarts a previously interrupted write. The caller must provide the
585 block protocol needed to complete the interrupted write.
586
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.
590
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
595
596 **/
597 EFI_STATUS
598 EFIAPI
599 FtwRestart (
600 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
601 IN EFI_HANDLE FvBlockHandle
602 )
603 {
604 EFI_STATUS Status;
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;
609
610 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
611
612 Status = WorkSpaceRefresh (FtwDevice);
613 if (EFI_ERROR (Status)) {
614 return EFI_ABORTED;
615 }
616
617 Header = FtwDevice->FtwLastWriteHeader;
618 Record = FtwDevice->FtwLastWriteRecord;
619
620 //
621 // Spare Complete but Destination not complete,
622 // Recover the targt block with the spare block.
623 //
624 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
625 if (EFI_ERROR (Status)) {
626 return EFI_NOT_FOUND;
627 }
628
629 //
630 // Check the COMPLETE flag of last write header
631 //
632 if (Header->Complete == FTW_VALID_STATE) {
633 return EFI_ACCESS_DENIED;
634 }
635
636 //
637 // Check the flags of last write record
638 //
639 if (Record->DestinationComplete == FTW_VALID_STATE) {
640 return EFI_ACCESS_DENIED;
641 }
642
643 if ((Record->SpareComplete != FTW_VALID_STATE)) {
644 return EFI_ABORTED;
645 }
646
647 //
648 // Since the content has already backuped in spare block, the write is
649 // guaranteed to be completed with fault tolerant manner.
650 //
651 Status = FtwWriteRecord (This, Fvb);
652 if (EFI_ERROR (Status)) {
653 return EFI_ABORTED;
654 }
655
656 //
657 // Erase Spare block
658 // This is restart, no need to keep spareblock content.
659 //
660 FtwEraseSpareBlock (FtwDevice);
661
662 DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));
663 return EFI_SUCCESS;
664 }
665
666 /**
667 Aborts all previous allocated writes.
668
669 @param This The pointer to this protocol instance.
670
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.
674
675 **/
676 EFI_STATUS
677 EFIAPI
678 FtwAbort (
679 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
680 )
681 {
682 EFI_STATUS Status;
683 UINTN Offset;
684 EFI_FTW_DEVICE *FtwDevice;
685
686 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
687
688 Status = WorkSpaceRefresh (FtwDevice);
689 if (EFI_ERROR (Status)) {
690 return EFI_ABORTED;
691 }
692
693 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
694 return EFI_NOT_FOUND;
695 }
696 //
697 // Update the complete state of the header as VALID and abort.
698 //
699 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
700 Status = FtwUpdateFvState (
701 FtwDevice->FtwFvBlock,
702 FtwDevice->FtwWorkSpaceLba,
703 FtwDevice->FtwWorkSpaceBase + Offset,
704 WRITES_COMPLETED
705 );
706 if (EFI_ERROR (Status)) {
707 return EFI_ABORTED;
708 }
709
710 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
711
712 DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));
713 return EFI_SUCCESS;
714 }
715
716 /**
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.
721
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.
732
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
737
738 **/
739 EFI_STATUS
740 EFIAPI
741 FtwGetLastWrite (
742 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
743 OUT EFI_GUID *CallerId,
744 OUT EFI_LBA *Lba,
745 OUT UINTN *Offset,
746 OUT UINTN *Length,
747 IN OUT UINTN *PrivateDataSize,
748 OUT VOID *PrivateData,
749 OUT BOOLEAN *Complete
750 )
751 {
752 EFI_STATUS Status;
753 EFI_FTW_DEVICE *FtwDevice;
754 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
755 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
756
757 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
758 return EFI_UNSUPPORTED;
759 }
760
761 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
762
763 Status = WorkSpaceRefresh (FtwDevice);
764 if (EFI_ERROR (Status)) {
765 return EFI_ABORTED;
766 }
767
768 Header = FtwDevice->FtwLastWriteHeader;
769 Record = FtwDevice->FtwLastWriteRecord;
770
771 //
772 // If Header is incompleted and the last record has completed, then
773 // call Abort() to set the Header->Complete FLAG.
774 //
775 if ((Header->Complete != FTW_VALID_STATE) &&
776 (Record->DestinationComplete == FTW_VALID_STATE) &&
777 IsLastRecordOfWrites (Header, Record)
778 ) {
779
780 Status = FtwAbort (This);
781 *Complete = TRUE;
782 return EFI_NOT_FOUND;
783 }
784 //
785 // If there is no write header/record, return not found.
786 //
787 if (Header->HeaderAllocated != FTW_VALID_STATE) {
788 *Complete = TRUE;
789 return EFI_NOT_FOUND;
790 }
791 //
792 // If this record SpareComplete has not set, then it can not restart.
793 //
794 if (Record->SpareComplete != FTW_VALID_STATE) {
795 Status = GetPreviousRecordOfWrites (Header, &Record);
796 if (EFI_ERROR (Status)) {
797 FtwAbort (This);
798 *Complete = TRUE;
799 return EFI_NOT_FOUND;
800 }
801 ASSERT (Record != NULL);
802 }
803
804 //
805 // Fill all the requested values
806 //
807 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
808 *Lba = Record->Lba;
809 *Offset = Record->Offset;
810 *Length = Record->Length;
811 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
812
813 if (*PrivateDataSize < Header->PrivateDataSize) {
814 *PrivateDataSize = Header->PrivateDataSize;
815 PrivateData = NULL;
816 Status = EFI_BUFFER_TOO_SMALL;
817 } else {
818 *PrivateDataSize = Header->PrivateDataSize;
819 CopyMem (PrivateData, Record + 1, *PrivateDataSize);
820 Status = EFI_SUCCESS;
821 }
822
823 DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));
824
825 return Status;
826 }
827