]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "FaultTolerantWrite.h"
12
13 //
14 // Fault Tolerant Write Protocol API
15 //
16 /**
17 Query the largest block that may be updated in a fault tolerant manner.
18
19
20 @param This The pointer to this protocol instance.
21 @param BlockSize A pointer to a caller allocated UINTN that is updated to
22 indicate the size of the largest block that can be updated.
23
24 @return EFI_SUCCESS The function completed successfully
25
26 **/
27 EFI_STATUS
28 EFIAPI
29 FtwGetMaxBlockSize (
30 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
31 OUT UINTN *BlockSize
32 )
33 {
34 EFI_FTW_DEVICE *FtwDevice;
35
36 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
37 return EFI_UNSUPPORTED;
38 }
39
40 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
41
42 *BlockSize = FtwDevice->SpareAreaLength;
43
44 return EFI_SUCCESS;
45 }
46
47 /**
48 Allocates space for the protocol to maintain information about writes.
49 Since writes must be completed in a fault tolerant manner and multiple
50 updates will require more resources to be successful, this function
51 enables the protocol to ensure that enough space exists to track
52 information about the upcoming writes.
53
54 All writes must be completed or aborted before another fault tolerant write can occur.
55
56 @param This The pointer to this protocol instance.
57 @param CallerId The GUID identifying the write.
58 @param PrivateDataSize The size of the caller's private data
59 that must be recorded for each write.
60 @param NumberOfWrites The number of fault tolerant block writes
61 that will need to occur.
62
63 @return EFI_SUCCESS The function completed successfully
64 @retval EFI_ABORTED The function could not complete successfully.
65 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
66
67 **/
68 EFI_STATUS
69 EFIAPI
70 FtwAllocate (
71 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
72 IN EFI_GUID *CallerId,
73 IN UINTN PrivateDataSize,
74 IN UINTN NumberOfWrites
75 )
76 {
77 EFI_STATUS Status;
78 UINTN Offset;
79 EFI_FTW_DEVICE *FtwDevice;
80 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
81
82 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
83
84 Status = WorkSpaceRefresh (FtwDevice);
85 if (EFI_ERROR (Status)) {
86 return EFI_ABORTED;
87 }
88 //
89 // Check if there is enough space for the coming allocation
90 //
91 if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
92 DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
93 return EFI_BUFFER_TOO_SMALL;
94 }
95 //
96 // Find the last write header and record.
97 // If the FtwHeader is complete, skip the completed last write header/records
98 //
99 FtwHeader = FtwDevice->FtwLastWriteHeader;
100
101 //
102 // Previous write has not completed, access denied.
103 //
104 if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
105 return EFI_ACCESS_DENIED;
106 }
107 //
108 // If workspace is not enough, then reclaim workspace
109 //
110 Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
111 if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
112 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
113 if (EFI_ERROR (Status)) {
114 return EFI_ABORTED;
115 }
116
117 FtwHeader = FtwDevice->FtwLastWriteHeader;
118 }
119 //
120 // Prepare FTW write header,
121 // overwrite the buffer and write to workspace.
122 //
123 FtwHeader->WritesAllocated = FTW_INVALID_STATE;
124 FtwHeader->Complete = FTW_INVALID_STATE;
125 CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
126 FtwHeader->NumberOfWrites = NumberOfWrites;
127 FtwHeader->PrivateDataSize = PrivateDataSize;
128 FtwHeader->HeaderAllocated = FTW_VALID_STATE;
129
130 Status = WriteWorkSpaceData (
131 FtwDevice->FtwFvBlock,
132 FtwDevice->WorkBlockSize,
133 FtwDevice->FtwWorkSpaceLba,
134 FtwDevice->FtwWorkSpaceBase + Offset,
135 sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER),
136 (UINT8 *) FtwHeader
137 );
138 if (EFI_ERROR (Status)) {
139 return EFI_ABORTED;
140 }
141 //
142 // Update Header->WriteAllocated as VALID
143 //
144 Status = FtwUpdateFvState (
145 FtwDevice->FtwFvBlock,
146 FtwDevice->WorkBlockSize,
147 FtwDevice->FtwWorkSpaceLba,
148 FtwDevice->FtwWorkSpaceBase + Offset,
149 WRITES_ALLOCATED
150 );
151 if (EFI_ERROR (Status)) {
152 return EFI_ABORTED;
153 }
154
155 DEBUG (
156 (EFI_D_INFO,
157 "Ftw: Allocate() success, Caller:%g, # %d\n",
158 CallerId,
159 NumberOfWrites)
160 );
161
162 return EFI_SUCCESS;
163 }
164
165
166 /**
167 Write a record with fault tolerant manner.
168 Since the content has already backuped in spare block, the write is
169 guaranteed to be completed with fault tolerant manner.
170
171 @param This The pointer to this protocol instance.
172 @param Fvb The FVB protocol that provides services for
173 reading, writing, and erasing the target block.
174 @param BlockSize The size of the block.
175
176 @retval EFI_SUCCESS The function completed successfully
177 @retval EFI_ABORTED The function could not complete successfully
178
179 **/
180 EFI_STATUS
181 FtwWriteRecord (
182 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
183 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
184 IN UINTN BlockSize
185 )
186 {
187 EFI_STATUS Status;
188 EFI_FTW_DEVICE *FtwDevice;
189 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
190 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
191 UINTN Offset;
192 UINTN NumberOfWriteBlocks;
193
194 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
195
196 //
197 // Spare Complete but Destination not complete,
198 // Recover the target block with the spare block.
199 //
200 Header = FtwDevice->FtwLastWriteHeader;
201 Record = FtwDevice->FtwLastWriteRecord;
202
203 //
204 // IF target block is working block, THEN Flush Spare Block To Working Block;
205 // ELSE flush spare block to target block, which may be boot block after all.
206 //
207 if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
208 //
209 // If target block is working block,
210 // it also need to set SPARE_COMPLETED to spare block.
211 //
212 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
213 Status = FtwUpdateFvState (
214 FtwDevice->FtwBackupFvb,
215 FtwDevice->SpareBlockSize,
216 FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
217 FtwDevice->FtwWorkSpaceBaseInSpare + Offset,
218 SPARE_COMPLETED
219 );
220 if (EFI_ERROR (Status)) {
221 return EFI_ABORTED;
222 }
223
224 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
225 } else if (IsBootBlock (FtwDevice, Fvb)) {
226 //
227 // Update boot block
228 //
229 Status = FlushSpareBlockToBootBlock (FtwDevice);
230 } else {
231 //
232 // Update blocks other than working block or boot block
233 //
234 NumberOfWriteBlocks = FTW_BLOCKS ((UINTN) (Record->Offset + Record->Length), BlockSize);
235 Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba, BlockSize, NumberOfWriteBlocks);
236 }
237
238 if (EFI_ERROR (Status)) {
239 return EFI_ABORTED;
240 }
241 //
242 // Record the DestionationComplete in record
243 //
244 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
245 Status = FtwUpdateFvState (
246 FtwDevice->FtwFvBlock,
247 FtwDevice->WorkBlockSize,
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->WorkBlockSize,
267 FtwDevice->FtwWorkSpaceLba,
268 FtwDevice->FtwWorkSpaceBase + Offset,
269 WRITES_COMPLETED
270 );
271 Header->Complete = FTW_VALID_STATE;
272 if (EFI_ERROR (Status)) {
273 return EFI_ABORTED;
274 }
275 }
276
277 return EFI_SUCCESS;
278 }
279
280 /**
281 Starts a target block update. This function will record data about write
282 in fault tolerant storage and will complete the write in a recoverable
283 manner, ensuring at all times that either the original contents or
284 the modified contents are available.
285
286 @param This The pointer to this protocol instance.
287 @param Lba The logical block address of the target block.
288 @param Offset The offset within the target block to place the data.
289 @param Length The number of bytes to write to the target block.
290 @param PrivateData A pointer to private data that the caller requires to
291 complete any pending writes in the event of a fault.
292 @param FvBlockHandle The handle of FVB protocol that provides services for
293 reading, writing, and erasing the target block.
294 @param Buffer The data to write.
295
296 @retval EFI_SUCCESS The function completed successfully
297 @retval EFI_ABORTED The function could not complete successfully.
298 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
299 Offset + *NumBytes > SpareAreaLength.
300 @retval EFI_ACCESS_DENIED No writes have been allocated.
301 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
302 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
303
304 **/
305 EFI_STATUS
306 EFIAPI
307 FtwWrite (
308 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
309 IN EFI_LBA Lba,
310 IN UINTN Offset,
311 IN UINTN Length,
312 IN VOID *PrivateData,
313 IN EFI_HANDLE FvBlockHandle,
314 IN VOID *Buffer
315 )
316 {
317 EFI_STATUS Status;
318 EFI_FTW_DEVICE *FtwDevice;
319 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
320 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
321 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
322 UINTN MyLength;
323 UINTN MyOffset;
324 UINTN MyBufferSize;
325 UINT8 *MyBuffer;
326 UINTN SpareBufferSize;
327 UINT8 *SpareBuffer;
328 UINTN Index;
329 UINT8 *Ptr;
330 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
331 UINTN BlockSize;
332 UINTN NumberOfBlocks;
333 UINTN NumberOfWriteBlocks;
334 UINTN WriteLength;
335
336 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
337
338 Status = WorkSpaceRefresh (FtwDevice);
339 if (EFI_ERROR (Status)) {
340 return EFI_ABORTED;
341 }
342
343 Header = FtwDevice->FtwLastWriteHeader;
344 Record = FtwDevice->FtwLastWriteRecord;
345
346 if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
347 if (PrivateData == NULL) {
348 //
349 // Ftw Write Header is not allocated.
350 // No additional private data, the private data size is zero. Number of record can be set to 1.
351 //
352 Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
353 if (EFI_ERROR (Status)) {
354 return Status;
355 }
356 } else {
357 //
358 // Ftw Write Header is not allocated
359 // Additional private data is not NULL, the private data size can't be determined.
360 //
361 DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
362 DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
363 return EFI_NOT_READY;
364 }
365 }
366
367 //
368 // If Record is out of the range of Header, return access denied.
369 //
370 if (((UINTN) Record - (UINTN) Header) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
371 return EFI_ACCESS_DENIED;
372 }
373
374 //
375 // Check the COMPLETE flag of last write header
376 //
377 if (Header->Complete == FTW_VALID_STATE) {
378 return EFI_ACCESS_DENIED;
379 }
380
381 if (Record->DestinationComplete == FTW_VALID_STATE) {
382 return EFI_ACCESS_DENIED;
383 }
384
385 if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
386 return EFI_NOT_READY;
387 }
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, "Ftw: Write(), Get FVB physical address - %r\n", Status));
400 return EFI_ABORTED;
401 }
402
403 //
404 // Now, one FVB has one type of BlockSize.
405 //
406 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
407 if (EFI_ERROR (Status)) {
408 DEBUG ((EFI_D_ERROR, "Ftw: Write(), Get block size - %r\n", Status));
409 return EFI_ABORTED;
410 }
411
412 NumberOfWriteBlocks = FTW_BLOCKS (Offset + Length, BlockSize);
413 DEBUG ((EFI_D_INFO, "Ftw: Write(), BlockSize - 0x%x, NumberOfWriteBlock - 0x%x\n", BlockSize, NumberOfWriteBlocks));
414 WriteLength = NumberOfWriteBlocks * BlockSize;
415
416 //
417 // Check if the input data can fit within the spare block.
418 //
419 if (WriteLength > FtwDevice->SpareAreaLength) {
420 return EFI_BAD_BUFFER_SIZE;
421 }
422
423 //
424 // Set BootBlockUpdate FLAG if it's updating boot block.
425 //
426 if (IsBootBlock (FtwDevice, Fvb)) {
427 Record->BootBlockUpdate = FTW_VALID_STATE;
428 //
429 // Boot Block and Spare Block should have same block size and block numbers.
430 //
431 ASSERT ((BlockSize == FtwDevice->SpareBlockSize) && (NumberOfWriteBlocks == FtwDevice->NumberOfSpareBlock));
432 }
433 //
434 // Write the record to the work space.
435 //
436 Record->Lba = Lba;
437 Record->Offset = Offset;
438 Record->Length = Length;
439 Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * BlockSize) - (INT64) FtwDevice->SpareAreaAddress;
440 if (PrivateData != NULL) {
441 CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);
442 }
443
444 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
445 MyLength = FTW_RECORD_SIZE (Header->PrivateDataSize);
446
447 Status = WriteWorkSpaceData (
448 FtwDevice->FtwFvBlock,
449 FtwDevice->WorkBlockSize,
450 FtwDevice->FtwWorkSpaceLba,
451 FtwDevice->FtwWorkSpaceBase + MyOffset,
452 MyLength,
453 (UINT8 *) Record
454 );
455 if (EFI_ERROR (Status)) {
456 return EFI_ABORTED;
457 }
458 //
459 // Record has written to working block, then do the data.
460 //
461 //
462 // Allocate a memory buffer
463 //
464 MyBufferSize = WriteLength;
465 MyBuffer = AllocatePool (MyBufferSize);
466 if (MyBuffer == NULL) {
467 return EFI_OUT_OF_RESOURCES;
468 }
469 //
470 // Read all original data from target block to memory buffer
471 //
472 Ptr = MyBuffer;
473 for (Index = 0; Index < NumberOfWriteBlocks; Index += 1) {
474 MyLength = BlockSize;
475 Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
476 if (EFI_ERROR (Status)) {
477 FreePool (MyBuffer);
478 return EFI_ABORTED;
479 }
480
481 Ptr += MyLength;
482 }
483 //
484 // Overwrite the updating range data with
485 // the input buffer content
486 //
487 CopyMem (MyBuffer + Offset, Buffer, Length);
488
489 //
490 // Try to keep the content of spare block
491 // Save spare block into a spare backup memory buffer (Sparebuffer)
492 //
493 SpareBufferSize = FtwDevice->SpareAreaLength;
494 SpareBuffer = AllocatePool (SpareBufferSize);
495 if (SpareBuffer == NULL) {
496 FreePool (MyBuffer);
497 return EFI_OUT_OF_RESOURCES;
498 }
499
500 Ptr = SpareBuffer;
501 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
502 MyLength = FtwDevice->SpareBlockSize;
503 Status = FtwDevice->FtwBackupFvb->Read (
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 // Write the memory buffer to spare block
520 // Do not assume Spare Block and Target Block have same block size
521 //
522 Status = FtwEraseSpareBlock (FtwDevice);
523 if (EFI_ERROR (Status)) {
524 FreePool (MyBuffer);
525 FreePool (SpareBuffer);
526 return EFI_ABORTED;
527 }
528 Ptr = MyBuffer;
529 for (Index = 0; MyBufferSize > 0; Index += 1) {
530 if (MyBufferSize > FtwDevice->SpareBlockSize) {
531 MyLength = FtwDevice->SpareBlockSize;
532 } else {
533 MyLength = MyBufferSize;
534 }
535 Status = FtwDevice->FtwBackupFvb->Write (
536 FtwDevice->FtwBackupFvb,
537 FtwDevice->FtwSpareLba + Index,
538 0,
539 &MyLength,
540 Ptr
541 );
542 if (EFI_ERROR (Status)) {
543 FreePool (MyBuffer);
544 FreePool (SpareBuffer);
545 return EFI_ABORTED;
546 }
547
548 Ptr += MyLength;
549 MyBufferSize -= MyLength;
550 }
551 //
552 // Free MyBuffer
553 //
554 FreePool (MyBuffer);
555
556 //
557 // Set the SpareComplete in the FTW record,
558 //
559 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
560 Status = FtwUpdateFvState (
561 FtwDevice->FtwFvBlock,
562 FtwDevice->WorkBlockSize,
563 FtwDevice->FtwWorkSpaceLba,
564 FtwDevice->FtwWorkSpaceBase + MyOffset,
565 SPARE_COMPLETED
566 );
567 if (EFI_ERROR (Status)) {
568 FreePool (SpareBuffer);
569 return EFI_ABORTED;
570 }
571
572 Record->SpareComplete = FTW_VALID_STATE;
573
574 //
575 // Since the content has already backuped in spare block, the write is
576 // guaranteed to be completed with fault tolerant manner.
577 //
578 Status = FtwWriteRecord (This, Fvb, BlockSize);
579 if (EFI_ERROR (Status)) {
580 FreePool (SpareBuffer);
581 return EFI_ABORTED;
582 }
583 //
584 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
585 //
586 Status = FtwEraseSpareBlock (FtwDevice);
587 if (EFI_ERROR (Status)) {
588 FreePool (SpareBuffer);
589 return EFI_ABORTED;
590 }
591 Ptr = SpareBuffer;
592 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
593 MyLength = FtwDevice->SpareBlockSize;
594 Status = FtwDevice->FtwBackupFvb->Write (
595 FtwDevice->FtwBackupFvb,
596 FtwDevice->FtwSpareLba + Index,
597 0,
598 &MyLength,
599 Ptr
600 );
601 if (EFI_ERROR (Status)) {
602 FreePool (SpareBuffer);
603 return EFI_ABORTED;
604 }
605
606 Ptr += MyLength;
607 }
608 //
609 // All success.
610 //
611 FreePool (SpareBuffer);
612
613 DEBUG (
614 (EFI_D_INFO,
615 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
616 Lba,
617 Offset,
618 Length)
619 );
620
621 return EFI_SUCCESS;
622 }
623
624 /**
625 Restarts a previously interrupted write. The caller must provide the
626 block protocol needed to complete the interrupted write.
627
628 @param This The pointer to this protocol instance.
629 @param FvBlockHandle The handle of FVB protocol that provides services for
630 reading, writing, and erasing the target block.
631
632 @retval EFI_SUCCESS The function completed successfully
633 @retval EFI_ACCESS_DENIED No pending writes exist
634 @retval EFI_NOT_FOUND FVB protocol not found by the handle
635 @retval EFI_ABORTED The function could not complete successfully
636
637 **/
638 EFI_STATUS
639 EFIAPI
640 FtwRestart (
641 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
642 IN EFI_HANDLE FvBlockHandle
643 )
644 {
645 EFI_STATUS Status;
646 EFI_FTW_DEVICE *FtwDevice;
647 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
648 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
649 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
650 UINTN BlockSize;
651 UINTN NumberOfBlocks;
652
653 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
654
655 Status = WorkSpaceRefresh (FtwDevice);
656 if (EFI_ERROR (Status)) {
657 return EFI_ABORTED;
658 }
659
660 Header = FtwDevice->FtwLastWriteHeader;
661 Record = FtwDevice->FtwLastWriteRecord;
662
663 //
664 // Spare Complete but Destination not complete,
665 // Recover the targt block with the spare block.
666 //
667 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
668 if (EFI_ERROR (Status)) {
669 return EFI_NOT_FOUND;
670 }
671
672 //
673 // Now, one FVB has one type of BlockSize
674 //
675 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
676 if (EFI_ERROR (Status)) {
677 DEBUG ((EFI_D_ERROR, "Ftw: Restart(), Get block size - %r\n", Status));
678 return EFI_ABORTED;
679 }
680
681 //
682 // Check the COMPLETE flag of last write header
683 //
684 if (Header->Complete == FTW_VALID_STATE) {
685 return EFI_ACCESS_DENIED;
686 }
687
688 //
689 // Check the flags of last write record
690 //
691 if (Record->DestinationComplete == FTW_VALID_STATE) {
692 return EFI_ACCESS_DENIED;
693 }
694
695 if ((Record->SpareComplete != FTW_VALID_STATE)) {
696 return EFI_ABORTED;
697 }
698
699 //
700 // Since the content has already backuped in spare block, the write is
701 // guaranteed to be completed with fault tolerant manner.
702 //
703 Status = FtwWriteRecord (This, Fvb, BlockSize);
704 if (EFI_ERROR (Status)) {
705 return EFI_ABORTED;
706 }
707
708 //
709 // Erase Spare block
710 // This is restart, no need to keep spareblock content.
711 //
712 Status = FtwEraseSpareBlock (FtwDevice);
713 if (EFI_ERROR (Status)) {
714 return EFI_ABORTED;
715 }
716
717 DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
718 return EFI_SUCCESS;
719 }
720
721 /**
722 Aborts all previous allocated writes.
723
724 @param This The pointer to this protocol instance.
725
726 @retval EFI_SUCCESS The function completed successfully
727 @retval EFI_ABORTED The function could not complete successfully.
728 @retval EFI_NOT_FOUND No allocated writes exist.
729
730 **/
731 EFI_STATUS
732 EFIAPI
733 FtwAbort (
734 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
735 )
736 {
737 EFI_STATUS Status;
738 UINTN Offset;
739 EFI_FTW_DEVICE *FtwDevice;
740
741 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
742
743 Status = WorkSpaceRefresh (FtwDevice);
744 if (EFI_ERROR (Status)) {
745 return EFI_ABORTED;
746 }
747
748 if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {
749 return EFI_NOT_FOUND;
750 }
751
752 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
753 return EFI_NOT_FOUND;
754 }
755 //
756 // Update the complete state of the header as VALID and abort.
757 //
758 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
759 Status = FtwUpdateFvState (
760 FtwDevice->FtwFvBlock,
761 FtwDevice->WorkBlockSize,
762 FtwDevice->FtwWorkSpaceLba,
763 FtwDevice->FtwWorkSpaceBase + Offset,
764 WRITES_COMPLETED
765 );
766 if (EFI_ERROR (Status)) {
767 return EFI_ABORTED;
768 }
769
770 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
771
772 DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
773 return EFI_SUCCESS;
774 }
775
776 /**
777 Starts a target block update. This records information about the write
778 in fault tolerant storage and will complete the write in a recoverable
779 manner, ensuring at all times that either the original contents or
780 the modified contents are available.
781
782 @param This The pointer to this protocol instance.
783 @param CallerId The GUID identifying the last write.
784 @param Lba The logical block address of the last write.
785 @param Offset The offset within the block of the last write.
786 @param Length The length of the last write.
787 @param PrivateDataSize bytes from the private data
788 stored for this write.
789 @param PrivateData A pointer to a buffer. The function will copy
790 @param Complete A Boolean value with TRUE indicating
791 that the write was completed.
792
793 @retval EFI_SUCCESS The function completed successfully
794 @retval EFI_ABORTED The function could not complete successfully
795 @retval EFI_NOT_FOUND No allocated writes exist
796 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
797
798 **/
799 EFI_STATUS
800 EFIAPI
801 FtwGetLastWrite (
802 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
803 OUT EFI_GUID *CallerId,
804 OUT EFI_LBA *Lba,
805 OUT UINTN *Offset,
806 OUT UINTN *Length,
807 IN OUT UINTN *PrivateDataSize,
808 OUT VOID *PrivateData,
809 OUT BOOLEAN *Complete
810 )
811 {
812 EFI_STATUS Status;
813 EFI_FTW_DEVICE *FtwDevice;
814 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
815 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
816
817 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
818 return EFI_UNSUPPORTED;
819 }
820
821 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
822
823 Status = WorkSpaceRefresh (FtwDevice);
824 if (EFI_ERROR (Status)) {
825 return EFI_ABORTED;
826 }
827
828 Header = FtwDevice->FtwLastWriteHeader;
829 Record = FtwDevice->FtwLastWriteRecord;
830
831 //
832 // If Header is incompleted and the last record has completed, then
833 // call Abort() to set the Header->Complete FLAG.
834 //
835 if ((Header->Complete != FTW_VALID_STATE) &&
836 (Record->DestinationComplete == FTW_VALID_STATE) &&
837 IsLastRecordOfWrites (Header, Record)
838 ) {
839
840 Status = FtwAbort (This);
841 *Complete = TRUE;
842 return EFI_NOT_FOUND;
843 }
844 //
845 // If there is no write header/record, return not found.
846 //
847 if (Header->HeaderAllocated != FTW_VALID_STATE) {
848 *Complete = TRUE;
849 return EFI_NOT_FOUND;
850 }
851 //
852 // If this record SpareComplete has not set, then it can not restart.
853 //
854 if (Record->SpareComplete != FTW_VALID_STATE) {
855 Status = GetPreviousRecordOfWrites (Header, &Record);
856 if (EFI_ERROR (Status)) {
857 FtwAbort (This);
858 *Complete = TRUE;
859 return EFI_NOT_FOUND;
860 }
861 ASSERT (Record != NULL);
862 }
863
864 //
865 // Fill all the requested values
866 //
867 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
868 *Lba = Record->Lba;
869 *Offset = (UINTN) Record->Offset;
870 *Length = (UINTN) Record->Length;
871 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
872
873 if (*PrivateDataSize < Header->PrivateDataSize) {
874 *PrivateDataSize = (UINTN) Header->PrivateDataSize;
875 PrivateData = NULL;
876 Status = EFI_BUFFER_TOO_SMALL;
877 } else {
878 *PrivateDataSize = (UINTN) Header->PrivateDataSize;
879 CopyMem (PrivateData, Record + 1, *PrivateDataSize);
880 Status = EFI_SUCCESS;
881 }
882
883 DEBUG ((EFI_D_INFO, "%a(): success\n", __FUNCTION__));
884
885 return Status;
886 }
887