VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c

Last change on this file was 108794, checked in by vboxsync, 3 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette