]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
The code line where judges if offset exceed the FTW work space boundary, in some...
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FtwMisc.c
1 /** @file
2
3 Internal generic functions to operate flash block.
4
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "FaultTolerantWrite.h"
17
18 /**
19
20 Check whether a flash buffer is erased.
21
22 @param Buffer Buffer to check
23 @param BufferSize Size of the buffer
24
25 @return A BOOLEAN value indicating erased or not.
26
27 **/
28 BOOLEAN
29 IsErasedFlashBuffer (
30 IN UINT8 *Buffer,
31 IN UINTN BufferSize
32 )
33 {
34 BOOLEAN IsEmpty;
35 UINT8 *Ptr;
36 UINTN Index;
37
38 Ptr = Buffer;
39 IsEmpty = TRUE;
40 for (Index = 0; Index < BufferSize; Index += 1) {
41 if (*Ptr++ != FTW_ERASED_BYTE) {
42 IsEmpty = FALSE;
43 break;
44 }
45 }
46
47 return IsEmpty;
48 }
49
50 /**
51 To erase the block with the spare block size.
52
53
54 @param FtwDevice The private data of FTW driver
55 @param FvBlock FVB Protocol interface
56 @param Lba Lba of the firmware block
57
58 @retval EFI_SUCCESS Block LBA is Erased successfully
59 @retval Others Error occurs
60
61 **/
62 EFI_STATUS
63 FtwEraseBlock (
64 IN EFI_FTW_DEVICE *FtwDevice,
65 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
66 EFI_LBA Lba
67 )
68 {
69 return FvBlock->EraseBlocks (
70 FvBlock,
71 Lba,
72 FtwDevice->NumberOfSpareBlock,
73 EFI_LBA_LIST_TERMINATOR
74 );
75 }
76
77 /**
78 Erase spare block.
79
80 @param FtwDevice The private data of FTW driver
81
82 @retval EFI_SUCCESS The erase request was successfully completed.
83 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
84 @retval EFI_DEVICE_ERROR The block device is not functioning
85 correctly and could not be written.
86 The firmware device may have been
87 partially erased.
88 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
89 in the variable argument list do
90 not exist in the firmware volume.
91
92
93 **/
94 EFI_STATUS
95 FtwEraseSpareBlock (
96 IN EFI_FTW_DEVICE *FtwDevice
97 )
98 {
99 return FtwDevice->FtwBackupFvb->EraseBlocks (
100 FtwDevice->FtwBackupFvb,
101 FtwDevice->FtwSpareLba,
102 FtwDevice->NumberOfSpareBlock,
103 EFI_LBA_LIST_TERMINATOR
104 );
105 }
106
107 /**
108
109 Is it in working block?
110
111 @param FtwDevice The private data of FTW driver
112 @param FvBlock Fvb protocol instance
113 @param Lba The block specified
114
115 @return A BOOLEAN value indicating in working block or not.
116
117 **/
118 BOOLEAN
119 IsWorkingBlock (
120 EFI_FTW_DEVICE *FtwDevice,
121 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
122 EFI_LBA Lba
123 )
124 {
125 //
126 // If matching the following condition, the target block is in working block.
127 // 1. Target block is on the FV of working block (Using the same FVB protocol instance).
128 // 2. Lba falls into the range of working block.
129 //
130 return (BOOLEAN)
131 (
132 (FvBlock == FtwDevice->FtwFvBlock) &&
133 (Lba >= FtwDevice->FtwWorkBlockLba) &&
134 (Lba <= FtwDevice->FtwWorkSpaceLba)
135 );
136 }
137
138 /**
139
140 Get firmware block by address.
141
142
143 @param Address Address specified the block
144 @param FvBlock The block caller wanted
145
146 @retval EFI_SUCCESS The protocol instance if found.
147 @retval EFI_NOT_FOUND Block not found
148
149 **/
150 EFI_HANDLE
151 GetFvbByAddress (
152 IN EFI_PHYSICAL_ADDRESS Address,
153 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
154 )
155 {
156 EFI_STATUS Status;
157 EFI_HANDLE *HandleBuffer;
158 UINTN HandleCount;
159 UINTN Index;
160 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
161 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
162 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
163 EFI_HANDLE FvbHandle;
164
165 *FvBlock = NULL;
166 FvbHandle = NULL;
167 //
168 // Locate all handles of Fvb protocol
169 //
170 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
171 if (EFI_ERROR (Status)) {
172 return NULL;
173 }
174 //
175 // Get the FVB to access variable store
176 //
177 for (Index = 0; Index < HandleCount; Index += 1) {
178 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
179 if (EFI_ERROR (Status)) {
180 break;
181 }
182 //
183 // Compare the address and select the right one
184 //
185 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
186 if (EFI_ERROR (Status)) {
187 continue;
188 }
189
190 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
191 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {
192 *FvBlock = Fvb;
193 FvbHandle = HandleBuffer[Index];
194 break;
195 }
196 }
197
198 FreePool (HandleBuffer);
199 return FvbHandle;
200 }
201
202 /**
203
204 Is it in boot block?
205
206 @param FtwDevice The private data of FTW driver
207 @param FvBlock Fvb protocol instance
208 @param Lba The block specified
209
210 @return A BOOLEAN value indicating in boot block or not.
211
212 **/
213 BOOLEAN
214 IsBootBlock (
215 EFI_FTW_DEVICE *FtwDevice,
216 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
217 EFI_LBA Lba
218 )
219 {
220 EFI_STATUS Status;
221 EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;
222 EFI_PHYSICAL_ADDRESS BootBlockBase;
223 UINTN BootBlockSize;
224 EFI_PHYSICAL_ADDRESS BackupBlockBase;
225 UINTN BackupBlockSize;
226 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
227 BOOLEAN IsSwapped;
228 EFI_HANDLE FvbHandle;
229
230 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
231 return FALSE;
232 }
233
234 Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
235 if (EFI_ERROR (Status)) {
236 return FALSE;
237 }
238 //
239 // Get the boot block range
240 //
241 Status = SarProtocol->GetRangeLocation (
242 SarProtocol,
243 &BootBlockBase,
244 &BootBlockSize,
245 &BackupBlockBase,
246 &BackupBlockSize
247 );
248 if (EFI_ERROR (Status)) {
249 return FALSE;
250 }
251
252 Status = SarProtocol->GetSwapState (SarProtocol, &IsSwapped);
253 if (EFI_ERROR (Status)) {
254 return FALSE;
255 }
256 //
257 // Get FVB by address
258 //
259 if (!IsSwapped) {
260 FvbHandle = GetFvbByAddress (BootBlockBase, &BootFvb);
261 } else {
262 FvbHandle = GetFvbByAddress (BackupBlockBase, &BootFvb);
263 }
264
265 if (FvbHandle == NULL) {
266 return FALSE;
267 }
268 //
269 // Compare the Fvb
270 //
271 return (BOOLEAN) (FvBlock == BootFvb);
272 }
273
274 /**
275 Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
276 Spare block is accessed by FTW working FVB protocol interface. LBA is 1.
277 Target block is accessed by FvbBlock protocol interface. LBA is Lba.
278
279 FTW will do extra work on boot block update.
280 FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
281 which is produced by a chipset driver.
282 FTW updating boot block steps may be:
283 1. GetRangeLocation(), if the Range is inside the boot block, FTW know
284 that boot block will be update. It shall add a FLAG in the working block.
285 2. When spare block is ready,
286 3. SetSwapState(EFI_SWAPPED)
287 4. erasing boot block,
288 5. programming boot block until the boot block is ok.
289 6. SetSwapState(UNSWAPPED)
290 FTW shall not allow to update boot block when battery state is error.
291
292 @param FtwDevice The private data of FTW driver
293
294 @retval EFI_SUCCESS Spare block content is copied to boot block
295 @retval EFI_INVALID_PARAMETER Input parameter error
296 @retval EFI_OUT_OF_RESOURCES Allocate memory error
297 @retval EFI_ABORTED The function could not complete successfully
298
299 **/
300 EFI_STATUS
301 FlushSpareBlockToBootBlock (
302 EFI_FTW_DEVICE *FtwDevice
303 )
304 {
305 EFI_STATUS Status;
306 UINTN Length;
307 UINT8 *Buffer;
308 UINTN Count;
309 UINT8 *Ptr;
310 UINTN Index;
311 BOOLEAN TopSwap;
312 EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;
313 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
314 EFI_LBA BootLba;
315
316 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
317 return EFI_UNSUPPORTED;
318 }
319
320 //
321 // Locate swap address range protocol
322 //
323 Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
324 if (EFI_ERROR (Status)) {
325 return Status;
326 }
327 //
328 // Allocate a memory buffer
329 //
330 Length = FtwDevice->SpareAreaLength;
331 Buffer = AllocatePool (Length);
332 if (Buffer == NULL) {
333 return EFI_OUT_OF_RESOURCES;
334 }
335 //
336 // Get TopSwap bit state
337 //
338 Status = SarProtocol->GetSwapState (SarProtocol, &TopSwap);
339 if (EFI_ERROR (Status)) {
340 DEBUG ((EFI_D_ERROR, "Ftw: Get Top Swapped status - %r\n", Status));
341 FreePool (Buffer);
342 return EFI_ABORTED;
343 }
344
345 if (TopSwap) {
346 //
347 // Get FVB of current boot block
348 //
349 if (GetFvbByAddress (FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength, &BootFvb) == NULL) {
350 FreePool (Buffer);
351 return EFI_ABORTED;
352 }
353 //
354 // Read data from current boot block
355 //
356 BootLba = 0;
357 Ptr = Buffer;
358 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
359 Count = FtwDevice->BlockSize;
360 Status = BootFvb->Read (
361 BootFvb,
362 BootLba + Index,
363 0,
364 &Count,
365 Ptr
366 );
367 if (EFI_ERROR (Status)) {
368 FreePool (Buffer);
369 return Status;
370 }
371
372 Ptr += Count;
373 }
374 } else {
375 //
376 // Read data from spare block
377 //
378 Ptr = Buffer;
379 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
380 Count = FtwDevice->BlockSize;
381 Status = FtwDevice->FtwBackupFvb->Read (
382 FtwDevice->FtwBackupFvb,
383 FtwDevice->FtwSpareLba + Index,
384 0,
385 &Count,
386 Ptr
387 );
388 if (EFI_ERROR (Status)) {
389 FreePool (Buffer);
390 return Status;
391 }
392
393 Ptr += Count;
394 }
395 //
396 // Set TopSwap bit
397 //
398 Status = SarProtocol->SetSwapState (SarProtocol, TRUE);
399 if (EFI_ERROR (Status)) {
400 FreePool (Buffer);
401 return Status;
402 }
403 }
404 //
405 // Erase current spare block
406 // Because TopSwap is set, this actually erase the top block (boot block)!
407 //
408 Status = FtwEraseSpareBlock (FtwDevice);
409 if (EFI_ERROR (Status)) {
410 FreePool (Buffer);
411 return EFI_ABORTED;
412 }
413 //
414 // Write memory buffer currenet spare block. Still top block.
415 //
416 Ptr = Buffer;
417 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
418 Count = FtwDevice->BlockSize;
419 Status = FtwDevice->FtwBackupFvb->Write (
420 FtwDevice->FtwBackupFvb,
421 FtwDevice->FtwSpareLba + Index,
422 0,
423 &Count,
424 Ptr
425 );
426 if (EFI_ERROR (Status)) {
427 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write boot block - %r\n", Status));
428 FreePool (Buffer);
429 return Status;
430 }
431
432 Ptr += Count;
433 }
434
435 FreePool (Buffer);
436
437 //
438 // Clear TopSwap bit
439 //
440 Status = SarProtocol->SetSwapState (SarProtocol, FALSE);
441
442 return Status;
443 }
444
445 /**
446 Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
447 Spare block is accessed by FTW backup FVB protocol interface. LBA is 1.
448 Target block is accessed by FvbBlock protocol interface. LBA is Lba.
449
450
451 @param FtwDevice The private data of FTW driver
452 @param FvBlock FVB Protocol interface to access target block
453 @param Lba Lba of the target block
454
455 @retval EFI_SUCCESS Spare block content is copied to target block
456 @retval EFI_INVALID_PARAMETER Input parameter error
457 @retval EFI_OUT_OF_RESOURCES Allocate memory error
458 @retval EFI_ABORTED The function could not complete successfully
459
460 **/
461 EFI_STATUS
462 FlushSpareBlockToTargetBlock (
463 EFI_FTW_DEVICE *FtwDevice,
464 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
465 EFI_LBA Lba
466 )
467 {
468 EFI_STATUS Status;
469 UINTN Length;
470 UINT8 *Buffer;
471 UINTN Count;
472 UINT8 *Ptr;
473 UINTN Index;
474
475 if ((FtwDevice == NULL) || (FvBlock == NULL)) {
476 return EFI_INVALID_PARAMETER;
477 }
478 //
479 // Allocate a memory buffer
480 //
481 Length = FtwDevice->SpareAreaLength;
482 Buffer = AllocatePool (Length);
483 if (Buffer == NULL) {
484 return EFI_OUT_OF_RESOURCES;
485 }
486 //
487 // Read all content of spare block to memory buffer
488 //
489 Ptr = Buffer;
490 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
491 Count = FtwDevice->BlockSize;
492 Status = FtwDevice->FtwBackupFvb->Read (
493 FtwDevice->FtwBackupFvb,
494 FtwDevice->FtwSpareLba + Index,
495 0,
496 &Count,
497 Ptr
498 );
499 if (EFI_ERROR (Status)) {
500 FreePool (Buffer);
501 return Status;
502 }
503
504 Ptr += Count;
505 }
506 //
507 // Erase the target block
508 //
509 Status = FtwEraseBlock (FtwDevice, FvBlock, Lba);
510 if (EFI_ERROR (Status)) {
511 FreePool (Buffer);
512 return EFI_ABORTED;
513 }
514 //
515 // Write memory buffer to block, using the FvbBlock protocol interface
516 //
517 Ptr = Buffer;
518 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
519 Count = FtwDevice->BlockSize;
520 Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);
521 if (EFI_ERROR (Status)) {
522 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
523 FreePool (Buffer);
524 return Status;
525 }
526
527 Ptr += Count;
528 }
529
530 FreePool (Buffer);
531
532 return Status;
533 }
534
535 /**
536 Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
537 Spare block is accessed by FTW backup FVB protocol interface. LBA is
538 FtwDevice->FtwSpareLba.
539 Working block is accessed by FTW working FVB protocol interface. LBA is
540 FtwDevice->FtwWorkBlockLba.
541
542 Since the working block header is important when FTW initializes, the
543 state of the operation should be handled carefully. The Crc value is
544 calculated without STATE element.
545
546 @param FtwDevice The private data of FTW driver
547
548 @retval EFI_SUCCESS Spare block content is copied to target block
549 @retval EFI_OUT_OF_RESOURCES Allocate memory error
550 @retval EFI_ABORTED The function could not complete successfully
551
552 **/
553 EFI_STATUS
554 FlushSpareBlockToWorkingBlock (
555 EFI_FTW_DEVICE *FtwDevice
556 )
557 {
558 EFI_STATUS Status;
559 UINTN Length;
560 UINT8 *Buffer;
561 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
562 UINTN Count;
563 UINT8 *Ptr;
564 UINTN Index;
565 EFI_LBA WorkSpaceLbaOffset;
566
567 //
568 // Allocate a memory buffer
569 //
570 Length = FtwDevice->SpareAreaLength;
571 Buffer = AllocatePool (Length);
572 if (Buffer == NULL) {
573 return EFI_OUT_OF_RESOURCES;
574 }
575 //
576 // To guarantee that the WorkingBlockValid is set on spare block
577 //
578 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
579 // WorkingBlockValid);
580 // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
581 //
582 FtwUpdateFvState (
583 FtwDevice->FtwBackupFvb,
584 FtwDevice->FtwWorkSpaceLba,
585 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
586 WORKING_BLOCK_VALID
587 );
588 //
589 // Read from spare block to memory buffer
590 //
591 Ptr = Buffer;
592 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
593 Count = FtwDevice->BlockSize;
594 Status = FtwDevice->FtwBackupFvb->Read (
595 FtwDevice->FtwBackupFvb,
596 FtwDevice->FtwSpareLba + Index,
597 0,
598 &Count,
599 Ptr
600 );
601 if (EFI_ERROR (Status)) {
602 FreePool (Buffer);
603 return Status;
604 }
605
606 Ptr += Count;
607 }
608 //
609 // Clear the CRC and STATE, copy data from spare to working block.
610 //
611 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
612 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize + FtwDevice->FtwWorkSpaceBase);
613 InitWorkSpaceHeader (WorkingBlockHeader);
614 WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
615 WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
616
617 //
618 // target block is working block, then
619 // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
620 // before erase the working block.
621 //
622 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
623 // WorkingBlockInvalid);
624 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to
625 // skip Signature and Crc.
626 //
627 Status = FtwUpdateFvState (
628 FtwDevice->FtwFvBlock,
629 FtwDevice->FtwWorkSpaceLba,
630 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
631 WORKING_BLOCK_INVALID
632 );
633 if (EFI_ERROR (Status)) {
634 FreePool (Buffer);
635 return EFI_ABORTED;
636 }
637
638 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
639
640 //
641 // Erase the working block
642 //
643 Status = FtwEraseBlock (FtwDevice, FtwDevice->FtwFvBlock, FtwDevice->FtwWorkBlockLba);
644 if (EFI_ERROR (Status)) {
645 FreePool (Buffer);
646 return EFI_ABORTED;
647 }
648 //
649 // Write memory buffer to working block, using the FvbBlock protocol interface
650 //
651 Ptr = Buffer;
652 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
653 Count = FtwDevice->BlockSize;
654 Status = FtwDevice->FtwFvBlock->Write (
655 FtwDevice->FtwFvBlock,
656 FtwDevice->FtwWorkBlockLba + Index,
657 0,
658 &Count,
659 Ptr
660 );
661 if (EFI_ERROR (Status)) {
662 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
663 FreePool (Buffer);
664 return Status;
665 }
666
667 Ptr += Count;
668 }
669 //
670 // Since the memory buffer will not be used, free memory Buffer.
671 //
672 FreePool (Buffer);
673
674 //
675 // Update the VALID of the working block
676 //
677 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, WorkingBlockValid);
678 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to skip Signature and Crc.
679 //
680 Status = FtwUpdateFvState (
681 FtwDevice->FtwFvBlock,
682 FtwDevice->FtwWorkSpaceLba,
683 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
684 WORKING_BLOCK_VALID
685 );
686 if (EFI_ERROR (Status)) {
687 return EFI_ABORTED;
688 }
689
690 FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;
691
692 return EFI_SUCCESS;
693 }
694
695 /**
696 Update a bit of state on a block device. The location of the bit is
697 calculated by the (Lba, Offset, bit). Here bit is determined by the
698 the name of a certain bit.
699
700
701 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
702 @param Lba Lba of a block
703 @param Offset Offset on the Lba
704 @param NewBit New value that will override the old value if it can be change
705
706 @retval EFI_SUCCESS A state bit has been updated successfully
707 @retval Others Access block device error.
708 Notes:
709 Assume all bits of State are inside the same BYTE.
710 @retval EFI_ABORTED Read block fail
711
712 **/
713 EFI_STATUS
714 FtwUpdateFvState (
715 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
716 IN EFI_LBA Lba,
717 IN UINTN Offset,
718 IN UINT8 NewBit
719 )
720 {
721 EFI_STATUS Status;
722 UINT8 State;
723 UINTN Length;
724
725 //
726 // Read state from device, assume State is only one byte.
727 //
728 Length = sizeof (UINT8);
729 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
730 if (EFI_ERROR (Status)) {
731 return EFI_ABORTED;
732 }
733
734 State ^= FTW_POLARITY_REVERT;
735 State = (UINT8) (State | NewBit);
736 State ^= FTW_POLARITY_REVERT;
737
738 //
739 // Write state back to device
740 //
741 Length = sizeof (UINT8);
742 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
743
744 return Status;
745 }
746
747 /**
748 Get the last Write Header pointer.
749 The last write header is the header whose 'complete' state hasn't been set.
750 After all, this header may be a EMPTY header entry for next Allocate.
751
752
753 @param FtwWorkSpaceHeader Pointer of the working block header
754 @param FtwWorkSpaceSize Size of the work space
755 @param FtwWriteHeader Pointer to retrieve the last write header
756
757 @retval EFI_SUCCESS Get the last write record successfully
758 @retval EFI_ABORTED The FTW work space is damaged
759
760 **/
761 EFI_STATUS
762 FtwGetLastWriteHeader (
763 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
764 IN UINTN FtwWorkSpaceSize,
765 OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
766 )
767 {
768 UINTN Offset;
769 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
770
771 *FtwWriteHeader = NULL;
772 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);
773 Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
774
775 while (FtwHeader->Complete == FTW_VALID_STATE) {
776 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
777 //
778 // If Offset exceed the FTW work space boudary, return error.
779 //
780 if (Offset >= FtwWorkSpaceSize) {
781 *FtwWriteHeader = FtwHeader;
782 return EFI_ABORTED;
783 }
784
785 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);
786 }
787 //
788 // Last write header is found
789 //
790 *FtwWriteHeader = FtwHeader;
791
792 return EFI_SUCCESS;
793 }
794
795 /**
796 Get the last Write Record pointer. The last write Record is the Record
797 whose DestinationCompleted state hasn't been set. After all, this Record
798 may be a EMPTY record entry for next write.
799
800
801 @param FtwWriteHeader Pointer to the write record header
802 @param FtwWriteRecord Pointer to retrieve the last write record
803
804 @retval EFI_SUCCESS Get the last write record successfully
805 @retval EFI_ABORTED The FTW work space is damaged
806
807 **/
808 EFI_STATUS
809 FtwGetLastWriteRecord (
810 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
811 OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
812 )
813 {
814 UINTN Index;
815 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;
816
817 *FtwWriteRecord = NULL;
818 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);
819
820 //
821 // Try to find the last write record "that has not completed"
822 //
823 for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
824 if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
825 //
826 // The last write record is found
827 //
828 *FtwWriteRecord = FtwRecord;
829 return EFI_SUCCESS;
830 }
831
832 FtwRecord++;
833
834 if (FtwWriteHeader->PrivateDataSize != 0) {
835 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + FtwWriteHeader->PrivateDataSize);
836 }
837 }
838 //
839 // if Index == NumberOfWrites, then
840 // the last record has been written successfully,
841 // but the Header->Complete Flag has not been set.
842 // also return the last record.
843 //
844 if (Index == FtwWriteHeader->NumberOfWrites) {
845 *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
846 return EFI_SUCCESS;
847 }
848
849 return EFI_ABORTED;
850 }
851
852 /**
853 To check if FtwRecord is the first record of FtwHeader.
854
855 @param FtwHeader Pointer to the write record header
856 @param FtwRecord Pointer to the write record
857
858 @retval TRUE FtwRecord is the first Record of the FtwHeader
859 @retval FALSE FtwRecord is not the first Record of the FtwHeader
860
861 **/
862 BOOLEAN
863 IsFirstRecordOfWrites (
864 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
865 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
866 )
867 {
868 UINT8 *Head;
869 UINT8 *Ptr;
870
871 Head = (UINT8 *) FtwHeader;
872 Ptr = (UINT8 *) FtwRecord;
873
874 Head += sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
875 return (BOOLEAN) (Head == Ptr);
876 }
877
878 /**
879 To check if FtwRecord is the last record of FtwHeader. Because the
880 FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be
881 determined if it is the last record of FtwHeader.
882
883 @param FtwHeader Pointer to the write record header
884 @param FtwRecord Pointer to the write record
885
886 @retval TRUE FtwRecord is the last Record of the FtwHeader
887 @retval FALSE FtwRecord is not the last Record of the FtwHeader
888
889 **/
890 BOOLEAN
891 IsLastRecordOfWrites (
892 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
893 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
894 )
895 {
896 UINT8 *Head;
897 UINT8 *Ptr;
898
899 Head = (UINT8 *) FtwHeader;
900 Ptr = (UINT8 *) FtwRecord;
901
902 Head += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);
903 return (BOOLEAN) (Head == Ptr);
904 }
905
906 /**
907 To check if FtwRecord is the first record of FtwHeader.
908
909 @param FtwHeader Pointer to the write record header
910 @param FtwRecord Pointer to retrieve the previous write record
911
912 @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return.
913 @retval EFI_SUCCESS The previous write record is found.
914
915 **/
916 EFI_STATUS
917 GetPreviousRecordOfWrites (
918 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
919 IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord
920 )
921 {
922 UINT8 *Ptr;
923
924 if (IsFirstRecordOfWrites (FtwHeader, *FtwRecord)) {
925 *FtwRecord = NULL;
926 return EFI_ACCESS_DENIED;
927 }
928
929 Ptr = (UINT8 *) (*FtwRecord);
930 Ptr -= RECORD_SIZE (FtwHeader->PrivateDataSize);
931 *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;
932 return EFI_SUCCESS;
933 }
934
935 /**
936 Allocate private data for FTW driver and initialize it.
937
938 @param[out] FtwData Pointer to the FTW device structure
939
940 @retval EFI_SUCCESS Initialize the FTW device successfully.
941 @retval EFI_OUT_OF_RESOURCES Allocate memory error
942 @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
943
944 **/
945 EFI_STATUS
946 InitFtwDevice (
947 OUT EFI_FTW_DEVICE **FtwData
948 )
949 {
950 EFI_FTW_DEVICE *FtwDevice;
951
952 //
953 // Allocate private data of this driver,
954 // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
955 //
956 FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
957 if (FtwDevice == NULL) {
958 return EFI_OUT_OF_RESOURCES;
959 }
960
961 //
962 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
963 //
964 FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
965 FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
966 if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
967 DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
968 FreePool (FtwDevice);
969 return EFI_INVALID_PARAMETER;
970 }
971
972 FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
973 FtwDevice->FtwFvBlock = NULL;
974 FtwDevice->FtwBackupFvb = NULL;
975 FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
976 FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
977
978 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
979 if (FtwDevice->WorkSpaceAddress == 0) {
980 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
981 }
982
983 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
984 if (FtwDevice->SpareAreaAddress == 0) {
985 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
986 }
987
988 *FtwData = FtwDevice;
989 return EFI_SUCCESS;
990 }
991
992
993 /**
994 Find the proper Firmware Volume Block protocol for FTW operation.
995
996 @param[in, out] FtwDevice Pointer to the FTW device structure
997
998 @retval EFI_SUCCESS Find the FVB protocol successfully.
999 @retval EFI_NOT_FOUND No proper FVB protocol was found.
1000 @retval EFI_ABORTED Some data can not be got or be invalid.
1001
1002 **/
1003 EFI_STATUS
1004 FindFvbForFtw (
1005 IN OUT EFI_FTW_DEVICE *FtwDevice
1006 )
1007 {
1008 EFI_STATUS Status;
1009 EFI_HANDLE *HandleBuffer;
1010 UINTN HandleCount;
1011 UINTN Index;
1012 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
1013 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1014 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1015 EFI_FVB_ATTRIBUTES_2 Attributes;
1016 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
1017 UINT32 LbaIndex;
1018
1019 //
1020 // Get all FVB handle.
1021 //
1022 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
1023 if (EFI_ERROR (Status)) {
1024 return EFI_NOT_FOUND;
1025 }
1026
1027 //
1028 // Get the FVB to access variable store
1029 //
1030 Fvb = NULL;
1031 for (Index = 0; Index < HandleCount; Index += 1) {
1032 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
1033 if (EFI_ERROR (Status)) {
1034 Status = EFI_NOT_FOUND;
1035 break;
1036 }
1037
1038 //
1039 // Ensure this FVB protocol support Write operation.
1040 //
1041 Status = Fvb->GetAttributes (Fvb, &Attributes);
1042 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
1043 continue;
1044 }
1045 //
1046 // Compare the address and select the right one
1047 //
1048 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
1049 if (EFI_ERROR (Status)) {
1050 continue;
1051 }
1052
1053 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
1054 if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
1055 ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
1056 ) {
1057 FtwDevice->FtwFvBlock = Fvb;
1058 //
1059 // To get the LBA of work space
1060 //
1061 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
1062 //
1063 // Now, one FV has one type of BlockLength
1064 //
1065 FvbMapEntry = &FwVolHeader->BlockMap[0];
1066 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
1067 if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
1068 && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
1069 FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
1070 //
1071 // Get the Work space size and Base(Offset)
1072 //
1073 FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
1074 FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
1075 break;
1076 }
1077 }
1078 }
1079 }
1080
1081 if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
1082 ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
1083 ) {
1084 FtwDevice->FtwBackupFvb = Fvb;
1085 //
1086 // To get the LBA of spare
1087 //
1088 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
1089 //
1090 // Now, one FV has one type of BlockLength
1091 //
1092 FvbMapEntry = &FwVolHeader->BlockMap[0];
1093 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
1094 if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
1095 && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
1096 //
1097 // Get the NumberOfSpareBlock and BlockSize
1098 //
1099 FtwDevice->FtwSpareLba = LbaIndex - 1;
1100 FtwDevice->BlockSize = FvbMapEntry->Length;
1101 FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;
1102 //
1103 // Check the range of spare area to make sure that it's in FV range
1104 //
1105 if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {
1106 DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
1107 FreePool (HandleBuffer);
1108 ASSERT (FALSE);
1109 return EFI_ABORTED;
1110 }
1111 break;
1112 }
1113 }
1114 }
1115 }
1116 }
1117 FreePool (HandleBuffer);
1118
1119 if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
1120 (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
1121 return EFI_ABORTED;
1122 }
1123
1124 return EFI_SUCCESS;
1125 }
1126
1127
1128 /**
1129 Initialization for Fault Tolerant Write protocol.
1130
1131 @param[in, out] FtwDevice Pointer to the FTW device structure
1132
1133 @retval EFI_SUCCESS Initialize the FTW protocol successfully.
1134 @retval EFI_NOT_FOUND No proper FVB protocol was found.
1135
1136 **/
1137 EFI_STATUS
1138 InitFtwProtocol (
1139 IN OUT EFI_FTW_DEVICE *FtwDevice
1140 )
1141 {
1142 EFI_STATUS Status;
1143 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1144 UINTN Length;
1145 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
1146 UINTN Offset;
1147 EFI_HANDLE FvbHandle;
1148
1149 //
1150 // Find the right SMM Fvb protocol instance for FTW.
1151 //
1152 Status = FindFvbForFtw (FtwDevice);
1153 if (EFI_ERROR (Status)) {
1154 return EFI_NOT_FOUND;
1155 }
1156
1157 //
1158 // Calculate the start LBA of working block. Working block is an area which
1159 // contains working space in its last block and has the same size as spare
1160 // block, unless there are not enough blocks before the block that contains
1161 // working space.
1162 //
1163 FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;
1164 ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0);
1165
1166 //
1167 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
1168 //
1169 FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
1170 FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
1171
1172 FtwDevice->FtwLastWriteHeader = NULL;
1173 FtwDevice->FtwLastWriteRecord = NULL;
1174
1175 //
1176 // Refresh the working space data from working block
1177 //
1178 Status = WorkSpaceRefresh (FtwDevice);
1179 ASSERT_EFI_ERROR (Status);
1180 //
1181 // If the working block workspace is not valid, try the spare block
1182 //
1183 if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
1184 //
1185 // Read from spare block
1186 //
1187 Length = FtwDevice->FtwWorkSpaceSize;
1188 Status = FtwDevice->FtwBackupFvb->Read (
1189 FtwDevice->FtwBackupFvb,
1190 FtwDevice->FtwSpareLba,
1191 FtwDevice->FtwWorkSpaceBase,
1192 &Length,
1193 FtwDevice->FtwWorkSpace
1194 );
1195 ASSERT_EFI_ERROR (Status);
1196
1197 //
1198 // If spare block is valid, then replace working block content.
1199 //
1200 if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
1201 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
1202 DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in InitFtwProtocol() - %r\n", Status));
1203 FtwAbort (&FtwDevice->FtwInstance);
1204 //
1205 // Refresh work space.
1206 //
1207 Status = WorkSpaceRefresh (FtwDevice);
1208 ASSERT_EFI_ERROR (Status);
1209 } else {
1210 DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));
1211 //
1212 // If both are invalid, then initialize work space.
1213 //
1214 SetMem (
1215 FtwDevice->FtwWorkSpace,
1216 FtwDevice->FtwWorkSpaceSize,
1217 FTW_ERASED_BYTE
1218 );
1219 InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
1220 //
1221 // Initialize the work space
1222 //
1223 Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
1224 ASSERT_EFI_ERROR (Status);
1225 }
1226 }
1227 //
1228 // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
1229 // (! SpareComplete) THEN call Abort().
1230 //
1231 if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
1232 (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
1233 IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
1234 ) {
1235 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
1236 FtwAbort (&FtwDevice->FtwInstance);
1237 }
1238 //
1239 // If Header is incompleted and the last record has completed, then
1240 // call Abort() to set the Header->Complete FLAG.
1241 //
1242 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
1243 (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
1244 IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
1245 ) {
1246 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
1247 FtwAbort (&FtwDevice->FtwInstance);
1248 }
1249 //
1250 // To check the workspace buffer following last Write header/records is EMPTY or not.
1251 // If it's not EMPTY, FTW also need to call reclaim().
1252 //
1253 FtwHeader = FtwDevice->FtwLastWriteHeader;
1254 Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
1255 if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
1256 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
1257 }
1258
1259 if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
1260 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
1261 ASSERT_EFI_ERROR (Status);
1262 }
1263
1264 //
1265 // Restart if it's boot block
1266 //
1267 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
1268 (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
1269 ) {
1270 if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
1271 Status = FlushSpareBlockToBootBlock (FtwDevice);
1272 DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
1273 ASSERT_EFI_ERROR (Status);
1274 FtwAbort (&FtwDevice->FtwInstance);
1275 } else {
1276 //
1277 // if (SpareCompleted) THEN Restart to fault tolerant write.
1278 //
1279 FvbHandle = NULL;
1280 FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);
1281 if (FvbHandle != NULL) {
1282 Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
1283 DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
1284 ASSERT_EFI_ERROR (Status);
1285 }
1286 FtwAbort (&FtwDevice->FtwInstance);
1287 }
1288 }
1289 //
1290 // Hook the protocol API
1291 //
1292 FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
1293 FtwDevice->FtwInstance.Allocate = FtwAllocate;
1294 FtwDevice->FtwInstance.Write = FtwWrite;
1295 FtwDevice->FtwInstance.Restart = FtwRestart;
1296 FtwDevice->FtwInstance.Abort = FtwAbort;
1297 FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
1298
1299 return EFI_SUCCESS;
1300 }
1301