]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
MdeModulePkg: Add DriverHealthManagerDxe driver.
[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 - 2014, 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 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
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
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 Ptr = MyBuffer;
530 for (Index = 0; MyBufferSize > 0; Index += 1) {
531 if (MyBufferSize > FtwDevice->SpareBlockSize) {
532 MyLength = FtwDevice->SpareBlockSize;
533 } else {
534 MyLength = MyBufferSize;
535 }
536 Status = FtwDevice->FtwBackupFvb->Write (
537 FtwDevice->FtwBackupFvb,
538 FtwDevice->FtwSpareLba + Index,
539 0,
540 &MyLength,
541 Ptr
542 );
543 if (EFI_ERROR (Status)) {
544 FreePool (MyBuffer);
545 FreePool (SpareBuffer);
546 return EFI_ABORTED;
547 }
548
549 Ptr += MyLength;
550 MyBufferSize -= MyLength;
551 }
552 //
553 // Free MyBuffer
554 //
555 FreePool (MyBuffer);
556
557 //
558 // Set the SpareComplete in the FTW record,
559 //
560 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
561 Status = FtwUpdateFvState (
562 FtwDevice->FtwFvBlock,
563 FtwDevice->WorkBlockSize,
564 FtwDevice->FtwWorkSpaceLba,
565 FtwDevice->FtwWorkSpaceBase + MyOffset,
566 SPARE_COMPLETED
567 );
568 if (EFI_ERROR (Status)) {
569 FreePool (SpareBuffer);
570 return EFI_ABORTED;
571 }
572
573 Record->SpareComplete = FTW_VALID_STATE;
574
575 //
576 // Since the content has already backuped in spare block, the write is
577 // guaranteed to be completed with fault tolerant manner.
578 //
579 Status = FtwWriteRecord (This, Fvb, BlockSize);
580 if (EFI_ERROR (Status)) {
581 FreePool (SpareBuffer);
582 return EFI_ABORTED;
583 }
584 //
585 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
586 //
587 Status = FtwEraseSpareBlock (FtwDevice);
588 Ptr = SpareBuffer;
589 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
590 MyLength = FtwDevice->SpareBlockSize;
591 Status = FtwDevice->FtwBackupFvb->Write (
592 FtwDevice->FtwBackupFvb,
593 FtwDevice->FtwSpareLba + Index,
594 0,
595 &MyLength,
596 Ptr
597 );
598 if (EFI_ERROR (Status)) {
599 FreePool (SpareBuffer);
600 return EFI_ABORTED;
601 }
602
603 Ptr += MyLength;
604 }
605 //
606 // All success.
607 //
608 FreePool (SpareBuffer);
609
610 DEBUG (
611 (EFI_D_INFO,
612 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
613 Lba,
614 Offset,
615 Length)
616 );
617
618 return EFI_SUCCESS;
619 }
620
621 /**
622 Restarts a previously interrupted write. The caller must provide the
623 block protocol needed to complete the interrupted write.
624
625 @param This The pointer to this protocol instance.
626 @param FvBlockHandle The handle of FVB protocol that provides services for
627 reading, writing, and erasing the target block.
628
629 @retval EFI_SUCCESS The function completed successfully
630 @retval EFI_ACCESS_DENIED No pending writes exist
631 @retval EFI_NOT_FOUND FVB protocol not found by the handle
632 @retval EFI_ABORTED The function could not complete successfully
633
634 **/
635 EFI_STATUS
636 EFIAPI
637 FtwRestart (
638 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
639 IN EFI_HANDLE FvBlockHandle
640 )
641 {
642 EFI_STATUS Status;
643 EFI_FTW_DEVICE *FtwDevice;
644 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
645 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
646 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
647 UINTN BlockSize;
648 UINTN NumberOfBlocks;
649
650 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
651
652 Status = WorkSpaceRefresh (FtwDevice);
653 if (EFI_ERROR (Status)) {
654 return EFI_ABORTED;
655 }
656
657 Header = FtwDevice->FtwLastWriteHeader;
658 Record = FtwDevice->FtwLastWriteRecord;
659
660 //
661 // Spare Complete but Destination not complete,
662 // Recover the targt block with the spare block.
663 //
664 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
665 if (EFI_ERROR (Status)) {
666 return EFI_NOT_FOUND;
667 }
668
669 //
670 // Now, one FVB has one type of BlockSize
671 //
672 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
673 if (EFI_ERROR (Status)) {
674 DEBUG ((EFI_D_ERROR, "Ftw: Restart(), Get block size - %r\n", Status));
675 return EFI_ABORTED;
676 }
677
678 //
679 // Check the COMPLETE flag of last write header
680 //
681 if (Header->Complete == FTW_VALID_STATE) {
682 return EFI_ACCESS_DENIED;
683 }
684
685 //
686 // Check the flags of last write record
687 //
688 if (Record->DestinationComplete == FTW_VALID_STATE) {
689 return EFI_ACCESS_DENIED;
690 }
691
692 if ((Record->SpareComplete != FTW_VALID_STATE)) {
693 return EFI_ABORTED;
694 }
695
696 //
697 // Since the content has already backuped in spare block, the write is
698 // guaranteed to be completed with fault tolerant manner.
699 //
700 Status = FtwWriteRecord (This, Fvb, BlockSize);
701 if (EFI_ERROR (Status)) {
702 return EFI_ABORTED;
703 }
704
705 //
706 // Erase Spare block
707 // This is restart, no need to keep spareblock content.
708 //
709 FtwEraseSpareBlock (FtwDevice);
710
711 DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));
712 return EFI_SUCCESS;
713 }
714
715 /**
716 Aborts all previous allocated writes.
717
718 @param This The pointer to this protocol instance.
719
720 @retval EFI_SUCCESS The function completed successfully
721 @retval EFI_ABORTED The function could not complete successfully.
722 @retval EFI_NOT_FOUND No allocated writes exist.
723
724 **/
725 EFI_STATUS
726 EFIAPI
727 FtwAbort (
728 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
729 )
730 {
731 EFI_STATUS Status;
732 UINTN Offset;
733 EFI_FTW_DEVICE *FtwDevice;
734
735 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
736
737 Status = WorkSpaceRefresh (FtwDevice);
738 if (EFI_ERROR (Status)) {
739 return EFI_ABORTED;
740 }
741
742 if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
743 return EFI_NOT_FOUND;
744 }
745
746 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
747 return EFI_NOT_FOUND;
748 }
749 //
750 // Update the complete state of the header as VALID and abort.
751 //
752 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
753 Status = FtwUpdateFvState (
754 FtwDevice->FtwFvBlock,
755 FtwDevice->WorkBlockSize,
756 FtwDevice->FtwWorkSpaceLba,
757 FtwDevice->FtwWorkSpaceBase + Offset,
758 WRITES_COMPLETED
759 );
760 if (EFI_ERROR (Status)) {
761 return EFI_ABORTED;
762 }
763
764 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
765
766 DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));
767 return EFI_SUCCESS;
768 }
769
770 /**
771 Starts a target block update. This records information about the write
772 in fault tolerant storage and will complete the write in a recoverable
773 manner, ensuring at all times that either the original contents or
774 the modified contents are available.
775
776 @param This The pointer to this protocol instance.
777 @param CallerId The GUID identifying the last write.
778 @param Lba The logical block address of the last write.
779 @param Offset The offset within the block of the last write.
780 @param Length The length of the last write.
781 @param PrivateDataSize bytes from the private data
782 stored for this write.
783 @param PrivateData A pointer to a buffer. The function will copy
784 @param Complete A Boolean value with TRUE indicating
785 that the write was completed.
786
787 @retval EFI_SUCCESS The function completed successfully
788 @retval EFI_ABORTED The function could not complete successfully
789 @retval EFI_NOT_FOUND No allocated writes exist
790 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
791
792 **/
793 EFI_STATUS
794 EFIAPI
795 FtwGetLastWrite (
796 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
797 OUT EFI_GUID *CallerId,
798 OUT EFI_LBA *Lba,
799 OUT UINTN *Offset,
800 OUT UINTN *Length,
801 IN OUT UINTN *PrivateDataSize,
802 OUT VOID *PrivateData,
803 OUT BOOLEAN *Complete
804 )
805 {
806 EFI_STATUS Status;
807 EFI_FTW_DEVICE *FtwDevice;
808 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
809 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
810
811 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
812 return EFI_UNSUPPORTED;
813 }
814
815 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
816
817 Status = WorkSpaceRefresh (FtwDevice);
818 if (EFI_ERROR (Status)) {
819 return EFI_ABORTED;
820 }
821
822 Header = FtwDevice->FtwLastWriteHeader;
823 Record = FtwDevice->FtwLastWriteRecord;
824
825 //
826 // If Header is incompleted and the last record has completed, then
827 // call Abort() to set the Header->Complete FLAG.
828 //
829 if ((Header->Complete != FTW_VALID_STATE) &&
830 (Record->DestinationComplete == FTW_VALID_STATE) &&
831 IsLastRecordOfWrites (Header, Record)
832 ) {
833
834 Status = FtwAbort (This);
835 *Complete = TRUE;
836 return EFI_NOT_FOUND;
837 }
838 //
839 // If there is no write header/record, return not found.
840 //
841 if (Header->HeaderAllocated != FTW_VALID_STATE) {
842 *Complete = TRUE;
843 return EFI_NOT_FOUND;
844 }
845 //
846 // If this record SpareComplete has not set, then it can not restart.
847 //
848 if (Record->SpareComplete != FTW_VALID_STATE) {
849 Status = GetPreviousRecordOfWrites (Header, &Record);
850 if (EFI_ERROR (Status)) {
851 FtwAbort (This);
852 *Complete = TRUE;
853 return EFI_NOT_FOUND;
854 }
855 ASSERT (Record != NULL);
856 }
857
858 //
859 // Fill all the requested values
860 //
861 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
862 *Lba = Record->Lba;
863 *Offset = (UINTN) Record->Offset;
864 *Length = (UINTN) Record->Length;
865 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
866
867 if (*PrivateDataSize < Header->PrivateDataSize) {
868 *PrivateDataSize = (UINTN) Header->PrivateDataSize;
869 PrivateData = NULL;
870 Status = EFI_BUFFER_TOO_SMALL;
871 } else {
872 *PrivateDataSize = (UINTN) Header->PrivateDataSize;
873 CopyMem (PrivateData, Record + 1, *PrivateDataSize);
874 Status = EFI_SUCCESS;
875 }
876
877 DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));
878
879 return Status;
880 }
881