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