]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
Add more exact SMM check in SmmFaultTolerantWriteHandler.
[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 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
577
578 //
579 // To guarantee that the WorkingBlockValid is set on spare block
580 //
581 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
582 // WorkingBlockValid);
583 // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
584 //
585 FtwUpdateFvState (
586 FtwDevice->FtwBackupFvb,
587 FtwDevice->FtwSpareLba + WorkSpaceLbaOffset,
588 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
589 WORKING_BLOCK_VALID
590 );
591 //
592 // Read from spare block to memory buffer
593 //
594 Ptr = Buffer;
595 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
596 Count = FtwDevice->BlockSize;
597 Status = FtwDevice->FtwBackupFvb->Read (
598 FtwDevice->FtwBackupFvb,
599 FtwDevice->FtwSpareLba + Index,
600 0,
601 &Count,
602 Ptr
603 );
604 if (EFI_ERROR (Status)) {
605 FreePool (Buffer);
606 return Status;
607 }
608
609 Ptr += Count;
610 }
611 //
612 // Clear the CRC and STATE, copy data from spare to working block.
613 //
614 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize + FtwDevice->FtwWorkSpaceBase);
615 InitWorkSpaceHeader (WorkingBlockHeader);
616 WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
617 WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
618
619 //
620 // target block is working block, then
621 // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
622 // before erase the working block.
623 //
624 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
625 // WorkingBlockInvalid);
626 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to
627 // skip Signature and Crc.
628 //
629 Status = FtwUpdateFvState (
630 FtwDevice->FtwFvBlock,
631 FtwDevice->FtwWorkSpaceLba,
632 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
633 WORKING_BLOCK_INVALID
634 );
635 if (EFI_ERROR (Status)) {
636 FreePool (Buffer);
637 return EFI_ABORTED;
638 }
639
640 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
641
642 //
643 // Erase the working block
644 //
645 Status = FtwEraseBlock (FtwDevice, FtwDevice->FtwFvBlock, FtwDevice->FtwWorkBlockLba);
646 if (EFI_ERROR (Status)) {
647 FreePool (Buffer);
648 return EFI_ABORTED;
649 }
650 //
651 // Write memory buffer to working block, using the FvbBlock protocol interface
652 //
653 Ptr = Buffer;
654 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
655 Count = FtwDevice->BlockSize;
656 Status = FtwDevice->FtwFvBlock->Write (
657 FtwDevice->FtwFvBlock,
658 FtwDevice->FtwWorkBlockLba + Index,
659 0,
660 &Count,
661 Ptr
662 );
663 if (EFI_ERROR (Status)) {
664 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));
665 FreePool (Buffer);
666 return Status;
667 }
668
669 Ptr += Count;
670 }
671 //
672 // Since the memory buffer will not be used, free memory Buffer.
673 //
674 FreePool (Buffer);
675
676 //
677 // Update the VALID of the working block
678 //
679 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, WorkingBlockValid);
680 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to skip Signature and Crc.
681 //
682 Status = FtwUpdateFvState (
683 FtwDevice->FtwFvBlock,
684 FtwDevice->FtwWorkSpaceLba,
685 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
686 WORKING_BLOCK_VALID
687 );
688 if (EFI_ERROR (Status)) {
689 return EFI_ABORTED;
690 }
691
692 FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;
693
694 return EFI_SUCCESS;
695 }
696
697 /**
698 Update a bit of state on a block device. The location of the bit is
699 calculated by the (Lba, Offset, bit). Here bit is determined by the
700 the name of a certain bit.
701
702
703 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
704 @param Lba Lba of a block
705 @param Offset Offset on the Lba
706 @param NewBit New value that will override the old value if it can be change
707
708 @retval EFI_SUCCESS A state bit has been updated successfully
709 @retval Others Access block device error.
710 Notes:
711 Assume all bits of State are inside the same BYTE.
712 @retval EFI_ABORTED Read block fail
713
714 **/
715 EFI_STATUS
716 FtwUpdateFvState (
717 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
718 IN EFI_LBA Lba,
719 IN UINTN Offset,
720 IN UINT8 NewBit
721 )
722 {
723 EFI_STATUS Status;
724 UINT8 State;
725 UINTN Length;
726
727 //
728 // Read state from device, assume State is only one byte.
729 //
730 Length = sizeof (UINT8);
731 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
732 if (EFI_ERROR (Status)) {
733 return EFI_ABORTED;
734 }
735
736 State ^= FTW_POLARITY_REVERT;
737 State = (UINT8) (State | NewBit);
738 State ^= FTW_POLARITY_REVERT;
739
740 //
741 // Write state back to device
742 //
743 Length = sizeof (UINT8);
744 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
745
746 return Status;
747 }
748
749 /**
750 Get the last Write Header pointer.
751 The last write header is the header whose 'complete' state hasn't been set.
752 After all, this header may be a EMPTY header entry for next Allocate.
753
754
755 @param FtwWorkSpaceHeader Pointer of the working block header
756 @param FtwWorkSpaceSize Size of the work space
757 @param FtwWriteHeader Pointer to retrieve the last write header
758
759 @retval EFI_SUCCESS Get the last write record successfully
760 @retval EFI_ABORTED The FTW work space is damaged
761
762 **/
763 EFI_STATUS
764 FtwGetLastWriteHeader (
765 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
766 IN UINTN FtwWorkSpaceSize,
767 OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
768 )
769 {
770 UINTN Offset;
771 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
772
773 *FtwWriteHeader = NULL;
774 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);
775 Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
776
777 while (FtwHeader->Complete == FTW_VALID_STATE) {
778 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
779 //
780 // If Offset exceed the FTW work space boudary, return error.
781 //
782 if (Offset >= FtwWorkSpaceSize) {
783 *FtwWriteHeader = FtwHeader;
784 return EFI_ABORTED;
785 }
786
787 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);
788 }
789 //
790 // Last write header is found
791 //
792 *FtwWriteHeader = FtwHeader;
793
794 return EFI_SUCCESS;
795 }
796
797 /**
798 Get the last Write Record pointer. The last write Record is the Record
799 whose DestinationCompleted state hasn't been set. After all, this Record
800 may be a EMPTY record entry for next write.
801
802
803 @param FtwWriteHeader Pointer to the write record header
804 @param FtwWriteRecord Pointer to retrieve the last write record
805
806 @retval EFI_SUCCESS Get the last write record successfully
807 @retval EFI_ABORTED The FTW work space is damaged
808
809 **/
810 EFI_STATUS
811 FtwGetLastWriteRecord (
812 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
813 OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
814 )
815 {
816 UINTN Index;
817 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;
818
819 *FtwWriteRecord = NULL;
820 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);
821
822 //
823 // Try to find the last write record "that has not completed"
824 //
825 for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
826 if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
827 //
828 // The last write record is found
829 //
830 *FtwWriteRecord = FtwRecord;
831 return EFI_SUCCESS;
832 }
833
834 FtwRecord++;
835
836 if (FtwWriteHeader->PrivateDataSize != 0) {
837 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + FtwWriteHeader->PrivateDataSize);
838 }
839 }
840 //
841 // if Index == NumberOfWrites, then
842 // the last record has been written successfully,
843 // but the Header->Complete Flag has not been set.
844 // also return the last record.
845 //
846 if (Index == FtwWriteHeader->NumberOfWrites) {
847 *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
848 return EFI_SUCCESS;
849 }
850
851 return EFI_ABORTED;
852 }
853
854 /**
855 To check if FtwRecord is the first record of FtwHeader.
856
857 @param FtwHeader Pointer to the write record header
858 @param FtwRecord Pointer to the write record
859
860 @retval TRUE FtwRecord is the first Record of the FtwHeader
861 @retval FALSE FtwRecord is not the first Record of the FtwHeader
862
863 **/
864 BOOLEAN
865 IsFirstRecordOfWrites (
866 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
867 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
868 )
869 {
870 UINT8 *Head;
871 UINT8 *Ptr;
872
873 Head = (UINT8 *) FtwHeader;
874 Ptr = (UINT8 *) FtwRecord;
875
876 Head += sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
877 return (BOOLEAN) (Head == Ptr);
878 }
879
880 /**
881 To check if FtwRecord is the last record of FtwHeader. Because the
882 FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be
883 determined if it is the last record of FtwHeader.
884
885 @param FtwHeader Pointer to the write record header
886 @param FtwRecord Pointer to the write record
887
888 @retval TRUE FtwRecord is the last Record of the FtwHeader
889 @retval FALSE FtwRecord is not the last Record of the FtwHeader
890
891 **/
892 BOOLEAN
893 IsLastRecordOfWrites (
894 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
895 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord
896 )
897 {
898 UINT8 *Head;
899 UINT8 *Ptr;
900
901 Head = (UINT8 *) FtwHeader;
902 Ptr = (UINT8 *) FtwRecord;
903
904 Head += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);
905 return (BOOLEAN) (Head == Ptr);
906 }
907
908 /**
909 To check if FtwRecord is the first record of FtwHeader.
910
911 @param FtwHeader Pointer to the write record header
912 @param FtwRecord Pointer to retrieve the previous write record
913
914 @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return.
915 @retval EFI_SUCCESS The previous write record is found.
916
917 **/
918 EFI_STATUS
919 GetPreviousRecordOfWrites (
920 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,
921 IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord
922 )
923 {
924 UINT8 *Ptr;
925
926 if (IsFirstRecordOfWrites (FtwHeader, *FtwRecord)) {
927 *FtwRecord = NULL;
928 return EFI_ACCESS_DENIED;
929 }
930
931 Ptr = (UINT8 *) (*FtwRecord);
932 Ptr -= RECORD_SIZE (FtwHeader->PrivateDataSize);
933 *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;
934 return EFI_SUCCESS;
935 }
936
937 /**
938 Allocate private data for FTW driver and initialize it.
939
940 @param[out] FtwData Pointer to the FTW device structure
941
942 @retval EFI_SUCCESS Initialize the FTW device successfully.
943 @retval EFI_OUT_OF_RESOURCES Allocate memory error
944 @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
945
946 **/
947 EFI_STATUS
948 InitFtwDevice (
949 OUT EFI_FTW_DEVICE **FtwData
950 )
951 {
952 EFI_FTW_DEVICE *FtwDevice;
953
954 //
955 // Allocate private data of this driver,
956 // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
957 //
958 FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
959 if (FtwDevice == NULL) {
960 return EFI_OUT_OF_RESOURCES;
961 }
962
963 //
964 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
965 //
966 FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
967 FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
968 if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
969 DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
970 FreePool (FtwDevice);
971 return EFI_INVALID_PARAMETER;
972 }
973
974 FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
975 FtwDevice->FtwFvBlock = NULL;
976 FtwDevice->FtwBackupFvb = NULL;
977 FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
978 FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
979
980 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
981 if (FtwDevice->WorkSpaceAddress == 0) {
982 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
983 }
984
985 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
986 if (FtwDevice->SpareAreaAddress == 0) {
987 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
988 }
989
990 *FtwData = FtwDevice;
991 return EFI_SUCCESS;
992 }
993
994
995 /**
996 Find the proper Firmware Volume Block protocol for FTW operation.
997
998 @param[in, out] FtwDevice Pointer to the FTW device structure
999
1000 @retval EFI_SUCCESS Find the FVB protocol successfully.
1001 @retval EFI_NOT_FOUND No proper FVB protocol was found.
1002 @retval EFI_ABORTED Some data can not be got or be invalid.
1003
1004 **/
1005 EFI_STATUS
1006 FindFvbForFtw (
1007 IN OUT EFI_FTW_DEVICE *FtwDevice
1008 )
1009 {
1010 EFI_STATUS Status;
1011 EFI_HANDLE *HandleBuffer;
1012 UINTN HandleCount;
1013 UINTN Index;
1014 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
1015 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1016 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1017 EFI_FVB_ATTRIBUTES_2 Attributes;
1018 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
1019 UINT32 LbaIndex;
1020
1021 //
1022 // Get all FVB handle.
1023 //
1024 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
1025 if (EFI_ERROR (Status)) {
1026 return EFI_NOT_FOUND;
1027 }
1028
1029 //
1030 // Get the FVB to access variable store
1031 //
1032 Fvb = NULL;
1033 for (Index = 0; Index < HandleCount; Index += 1) {
1034 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
1035 if (EFI_ERROR (Status)) {
1036 Status = EFI_NOT_FOUND;
1037 break;
1038 }
1039
1040 //
1041 // Ensure this FVB protocol support Write operation.
1042 //
1043 Status = Fvb->GetAttributes (Fvb, &Attributes);
1044 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
1045 continue;
1046 }
1047 //
1048 // Compare the address and select the right one
1049 //
1050 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
1051 if (EFI_ERROR (Status)) {
1052 continue;
1053 }
1054
1055 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
1056 if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
1057 ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
1058 ) {
1059 FtwDevice->FtwFvBlock = Fvb;
1060 //
1061 // To get the LBA of work space
1062 //
1063 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
1064 //
1065 // Now, one FV has one type of BlockLength
1066 //
1067 FvbMapEntry = &FwVolHeader->BlockMap[0];
1068 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
1069 if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
1070 && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
1071 FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
1072 //
1073 // Get the Work space size and Base(Offset)
1074 //
1075 FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
1076 FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
1077 break;
1078 }
1079 }
1080 }
1081 }
1082
1083 if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
1084 ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
1085 ) {
1086 FtwDevice->FtwBackupFvb = Fvb;
1087 //
1088 // To get the LBA of spare
1089 //
1090 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
1091 //
1092 // Now, one FV has one type of BlockLength
1093 //
1094 FvbMapEntry = &FwVolHeader->BlockMap[0];
1095 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
1096 if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
1097 && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
1098 //
1099 // Get the NumberOfSpareBlock and BlockSize
1100 //
1101 FtwDevice->FtwSpareLba = LbaIndex - 1;
1102 FtwDevice->BlockSize = FvbMapEntry->Length;
1103 FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;
1104 //
1105 // Check the range of spare area to make sure that it's in FV range
1106 //
1107 if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {
1108 DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
1109 FreePool (HandleBuffer);
1110 ASSERT (FALSE);
1111 return EFI_ABORTED;
1112 }
1113 break;
1114 }
1115 }
1116 }
1117 }
1118 }
1119 FreePool (HandleBuffer);
1120
1121 if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
1122 (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
1123 return EFI_ABORTED;
1124 }
1125
1126 return EFI_SUCCESS;
1127 }
1128
1129
1130 /**
1131 Initialization for Fault Tolerant Write protocol.
1132
1133 @param[in, out] FtwDevice Pointer to the FTW device structure
1134
1135 @retval EFI_SUCCESS Initialize the FTW protocol successfully.
1136 @retval EFI_NOT_FOUND No proper FVB protocol was found.
1137
1138 **/
1139 EFI_STATUS
1140 InitFtwProtocol (
1141 IN OUT EFI_FTW_DEVICE *FtwDevice
1142 )
1143 {
1144 EFI_STATUS Status;
1145 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1146 UINTN Length;
1147 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
1148 UINTN Offset;
1149 EFI_HANDLE FvbHandle;
1150
1151 //
1152 // Find the right SMM Fvb protocol instance for FTW.
1153 //
1154 Status = FindFvbForFtw (FtwDevice);
1155 if (EFI_ERROR (Status)) {
1156 return EFI_NOT_FOUND;
1157 }
1158
1159 //
1160 // Calculate the start LBA of working block. Working block is an area which
1161 // contains working space in its last block and has the same size as spare
1162 // block, unless there are not enough blocks before the block that contains
1163 // working space.
1164 //
1165 FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;
1166 ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0);
1167
1168 //
1169 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
1170 //
1171 FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
1172 FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
1173
1174 FtwDevice->FtwLastWriteHeader = NULL;
1175 FtwDevice->FtwLastWriteRecord = NULL;
1176
1177 //
1178 // Refresh the working space data from working block
1179 //
1180 Status = WorkSpaceRefresh (FtwDevice);
1181 ASSERT_EFI_ERROR (Status);
1182 //
1183 // If the working block workspace is not valid, try the spare block
1184 //
1185 if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
1186 //
1187 // Read from spare block
1188 //
1189 Length = FtwDevice->FtwWorkSpaceSize;
1190 Status = FtwDevice->FtwBackupFvb->Read (
1191 FtwDevice->FtwBackupFvb,
1192 FtwDevice->FtwSpareLba,
1193 FtwDevice->FtwWorkSpaceBase,
1194 &Length,
1195 FtwDevice->FtwWorkSpace
1196 );
1197 ASSERT_EFI_ERROR (Status);
1198
1199 //
1200 // If spare block is valid, then replace working block content.
1201 //
1202 if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
1203 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
1204 DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in InitFtwProtocol() - %r\n", Status));
1205 FtwAbort (&FtwDevice->FtwInstance);
1206 //
1207 // Refresh work space.
1208 //
1209 Status = WorkSpaceRefresh (FtwDevice);
1210 ASSERT_EFI_ERROR (Status);
1211 } else {
1212 DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));
1213 //
1214 // If both are invalid, then initialize work space.
1215 //
1216 SetMem (
1217 FtwDevice->FtwWorkSpace,
1218 FtwDevice->FtwWorkSpaceSize,
1219 FTW_ERASED_BYTE
1220 );
1221 InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
1222 //
1223 // Initialize the work space
1224 //
1225 Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
1226 ASSERT_EFI_ERROR (Status);
1227 }
1228 }
1229 //
1230 // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
1231 // (! SpareComplete) THEN call Abort().
1232 //
1233 if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
1234 (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
1235 IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
1236 ) {
1237 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
1238 FtwAbort (&FtwDevice->FtwInstance);
1239 }
1240 //
1241 // If Header is incompleted and the last record has completed, then
1242 // call Abort() to set the Header->Complete FLAG.
1243 //
1244 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
1245 (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
1246 IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
1247 ) {
1248 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
1249 FtwAbort (&FtwDevice->FtwInstance);
1250 }
1251 //
1252 // To check the workspace buffer following last Write header/records is EMPTY or not.
1253 // If it's not EMPTY, FTW also need to call reclaim().
1254 //
1255 FtwHeader = FtwDevice->FtwLastWriteHeader;
1256 Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
1257 if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
1258 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
1259 }
1260
1261 if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
1262 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
1263 ASSERT_EFI_ERROR (Status);
1264 }
1265
1266 //
1267 // Restart if it's boot block
1268 //
1269 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
1270 (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
1271 ) {
1272 if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
1273 Status = FlushSpareBlockToBootBlock (FtwDevice);
1274 DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
1275 ASSERT_EFI_ERROR (Status);
1276 FtwAbort (&FtwDevice->FtwInstance);
1277 } else {
1278 //
1279 // if (SpareCompleted) THEN Restart to fault tolerant write.
1280 //
1281 FvbHandle = NULL;
1282 FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);
1283 if (FvbHandle != NULL) {
1284 Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
1285 DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
1286 ASSERT_EFI_ERROR (Status);
1287 }
1288 FtwAbort (&FtwDevice->FtwInstance);
1289 }
1290 }
1291 //
1292 // Hook the protocol API
1293 //
1294 FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
1295 FtwDevice->FtwInstance.Allocate = FtwAllocate;
1296 FtwDevice->FtwInstance.Write = FtwWrite;
1297 FtwDevice->FtwInstance.Restart = FtwRestart;
1298 FtwDevice->FtwInstance.Abort = FtwAbort;
1299 FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
1300
1301 return EFI_SUCCESS;
1302 }
1303