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