]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
retire gEfiAlternateFvBlockGuid. All platform FvbRuntimeDxe drivers will not produce...
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FaultTolerantWrite.c
1 /** @file
2
3 This is a simple fault tolerant write driver.
4
5 This boot service protocol only provides fault tolerant write capability for
6 block devices. The protocol has internal non-volatile intermediate storage
7 of the data and private information. It should be able to recover
8 automatically from a critical fault, such as power failure.
9
10 The implementation uses an FTW (Fault Tolerant Write) Work Space.
11 This work space is a memory copy of the work space on the Working Block,
12 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
13
14 The work space stores each write record as EFI_FTW_RECORD structure.
15 The spare block stores the write buffer before write to the target block.
16
17 The write record has three states to specify the different phase of write operation.
18 1) WRITE_ALLOCATED is that the record is allocated in write space.
19 The information of write operation is stored in write record structure.
20 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
21 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
22
23 This driver operates the data as the whole size of spare block.
24 It first read the SpareAreaLength data from the target block into the spare memory buffer.
25 Then copy the write buffer data into the spare memory buffer.
26 Then write the spare memory buffer into the spare block.
27 Final copy the data from the spare block to the target block.
28
29 To make this drive work well, the following conditions must be satisfied:
30 1. The write NumBytes data must be fit within Spare area.
31 Offset + NumBytes <= SpareAreaLength
32 2. The whole flash range has the same block size.
33 3. Working block is an area which contains working space in its last block and has the same size as spare block.
34 4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
35 5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
36 6. Any write data area (SpareAreaLength Area) which the data will be written into must be
37 in the single one Firmware Volume Block range which FVB protocol is produced on.
38 7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
39 The spare area must be enough large to store the write data before write them into the target range.
40 If one of them is not satisfied, FtwWrite may fail.
41 Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
42
43 Copyright (c) 2006 - 2009, Intel Corporation
44 All rights reserved. This program and the accompanying materials
45 are licensed and made available under the terms and conditions of the BSD License
46 which accompanies this distribution. The full text of the license may be found at
47 http://opensource.org/licenses/bsd-license.php
48
49 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
50 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
51
52 **/
53
54 #include "FaultTolerantWrite.h"
55
56 EFI_EVENT mFvbRegistration = NULL;
57
58 //
59 // Fault Tolerant Write Protocol API
60 //
61 /**
62 Query the largest block that may be updated in a fault tolerant manner.
63
64
65 @param This The pointer to this protocol instance.
66 @param BlockSize A pointer to a caller allocated UINTN that is updated to
67 indicate the size of the largest block that can be updated.
68
69 @return EFI_SUCCESS The function completed successfully
70
71 **/
72 EFI_STATUS
73 EFIAPI
74 FtwGetMaxBlockSize (
75 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
76 OUT UINTN *BlockSize
77 )
78 {
79 EFI_FTW_DEVICE *FtwDevice;
80
81 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
82 return EFI_UNSUPPORTED;
83 }
84
85 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
86
87 *BlockSize = FtwDevice->SpareAreaLength;
88
89 return EFI_SUCCESS;
90 }
91
92 /**
93 Allocates space for the protocol to maintain information about writes.
94 Since writes must be completed in a fault tolerant manner and multiple
95 updates will require more resources to be successful, this function
96 enables the protocol to ensure that enough space exists to track
97 information about the upcoming writes.
98
99 All writes must be completed or aborted before another fault tolerant write can occur.
100
101 @param This The pointer to this protocol instance.
102 @param CallerId The GUID identifying the write.
103 @param PrivateDataSize The size of the caller's private data
104 that must be recorded for each write.
105 @param NumberOfWrites The number of fault tolerant block writes
106 that will need to occur.
107
108 @return EFI_SUCCESS The function completed successfully
109 @retval EFI_ABORTED The function could not complete successfully.
110 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
111
112 **/
113 EFI_STATUS
114 EFIAPI
115 FtwAllocate (
116 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
117 IN EFI_GUID *CallerId,
118 IN UINTN PrivateDataSize,
119 IN UINTN NumberOfWrites
120 )
121 {
122 EFI_STATUS Status;
123 UINTN Length;
124 UINTN Offset;
125 EFI_FTW_DEVICE *FtwDevice;
126 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
127
128 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
129
130 Status = WorkSpaceRefresh (FtwDevice);
131 if (EFI_ERROR (Status)) {
132 return EFI_ABORTED;
133 }
134 //
135 // Check if there is enough space for the coming allocation
136 //
137 if (WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
138 DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
139 return EFI_BUFFER_TOO_SMALL;
140 }
141 //
142 // Find the last write header and record.
143 // If the FtwHeader is complete, skip the completed last write header/records
144 //
145 FtwHeader = FtwDevice->FtwLastWriteHeader;
146
147 //
148 // Previous write has not completed, access denied.
149 //
150 if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
151 return EFI_ACCESS_DENIED;
152 }
153 //
154 // If workspace is not enough, then reclaim workspace
155 //
156 Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
157 if (Offset + WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
158 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
159 if (EFI_ERROR (Status)) {
160 return EFI_ABORTED;
161 }
162
163 FtwHeader = FtwDevice->FtwLastWriteHeader;
164 }
165 //
166 // Prepare FTW write header,
167 // overwrite the buffer and write to workspace.
168 //
169 FtwHeader->WritesAllocated = FTW_INVALID_STATE;
170 FtwHeader->Complete = FTW_INVALID_STATE;
171 CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
172 FtwHeader->NumberOfWrites = NumberOfWrites;
173 FtwHeader->PrivateDataSize = PrivateDataSize;
174 FtwHeader->HeaderAllocated = FTW_VALID_STATE;
175
176 Length = sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
177 Status = FtwDevice->FtwFvBlock->Write (
178 FtwDevice->FtwFvBlock,
179 FtwDevice->FtwWorkSpaceLba,
180 FtwDevice->FtwWorkSpaceBase + Offset,
181 &Length,
182 (UINT8 *) FtwHeader
183 );
184 if (EFI_ERROR (Status)) {
185 return EFI_ABORTED;
186 }
187 //
188 // Update Header->WriteAllocated as VALID
189 //
190 Status = FtwUpdateFvState (
191 FtwDevice->FtwFvBlock,
192 FtwDevice->FtwWorkSpaceLba,
193 FtwDevice->FtwWorkSpaceBase + Offset,
194 WRITES_ALLOCATED
195 );
196 if (EFI_ERROR (Status)) {
197 return EFI_ABORTED;
198 }
199
200 DEBUG (
201 (EFI_D_ERROR,
202 "Ftw: Allocate() success, Caller:%g, # %d\n",
203 CallerId,
204 NumberOfWrites)
205 );
206
207 return EFI_SUCCESS;
208 }
209
210
211 /**
212 Write a record with fault tolerant mannaer.
213 Since the content has already backuped in spare block, the write is
214 guaranteed to be completed with fault tolerant manner.
215
216 @param This The pointer to this protocol instance.
217 @param Fvb The FVB protocol that provides services for
218 reading, writing, and erasing the target block.
219
220 @retval EFI_SUCCESS The function completed successfully
221 @retval EFI_ABORTED The function could not complete successfully
222
223 **/
224 EFI_STATUS
225 FtwWriteRecord (
226 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
227 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
228 )
229 {
230 EFI_STATUS Status;
231 EFI_FTW_DEVICE *FtwDevice;
232 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
233 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
234 UINTN Offset;
235
236 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
237
238 //
239 // Spare Complete but Destination not complete,
240 // Recover the targt block with the spare block.
241 //
242 Header = FtwDevice->FtwLastWriteHeader;
243 Record = FtwDevice->FtwLastWriteRecord;
244
245 //
246 // IF target block is working block, THEN Flush Spare Block To Working Block;
247 // ELSE flush spare block to target block, which may be boot block after all.
248 //
249 if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {
250 //
251 // If target block is working block,
252 // it also need to set SPARE_COMPLETED to spare block.
253 //
254 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
255 Status = FtwUpdateFvState (
256 FtwDevice->FtwBackupFvb,
257 FtwDevice->FtwWorkSpaceLba,
258 FtwDevice->FtwWorkSpaceBase + Offset,
259 SPARE_COMPLETED
260 );
261 if (EFI_ERROR (Status)) {
262 return EFI_ABORTED;
263 }
264
265 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
266 } else if (IsBootBlock (FtwDevice, Fvb, Record->Lba)) {
267 //
268 // Update boot block
269 //
270 Status = FlushSpareBlockToBootBlock (FtwDevice);
271 } else {
272 //
273 // Update blocks other than working block or boot block
274 //
275 Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba);
276 }
277
278 if (EFI_ERROR (Status)) {
279 return EFI_ABORTED;
280 }
281 //
282 // Record the DestionationComplete in record
283 //
284 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
285 Status = FtwUpdateFvState (
286 FtwDevice->FtwFvBlock,
287 FtwDevice->FtwWorkSpaceLba,
288 FtwDevice->FtwWorkSpaceBase + Offset,
289 DEST_COMPLETED
290 );
291 if (EFI_ERROR (Status)) {
292 return EFI_ABORTED;
293 }
294
295 Record->DestinationComplete = FTW_VALID_STATE;
296
297 //
298 // If this is the last Write in these write sequence,
299 // set the complete flag of write header.
300 //
301 if (IsLastRecordOfWrites (Header, Record)) {
302 Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;
303 Status = FtwUpdateFvState (
304 FtwDevice->FtwFvBlock,
305 FtwDevice->FtwWorkSpaceLba,
306 FtwDevice->FtwWorkSpaceBase + Offset,
307 WRITES_COMPLETED
308 );
309 Header->Complete = FTW_VALID_STATE;
310 if (EFI_ERROR (Status)) {
311 return EFI_ABORTED;
312 }
313 }
314
315 return EFI_SUCCESS;
316 }
317
318 /**
319 Starts a target block update. This function will record data about write
320 in fault tolerant storage and will complete the write in a recoverable
321 manner, ensuring at all times that either the original contents or
322 the modified contents are available.
323
324 @param This The pointer to this protocol instance.
325 @param Lba The logical block address of the target block.
326 @param Offset The offset within the target block to place the data.
327 @param Length The number of bytes to write to the target block.
328 @param PrivateData A pointer to private data that the caller requires to
329 complete any pending writes in the event of a fault.
330 @param FvBlockHandle The handle of FVB protocol that provides services for
331 reading, writing, and erasing the target block.
332 @param Buffer The data to write.
333
334 @retval EFI_SUCCESS The function completed successfully
335 @retval EFI_ABORTED The function could not complete successfully.
336 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
337 Offset + *NumBytes > SpareAreaLength.
338 @retval EFI_ACCESS_DENIED No writes have been allocated.
339 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
340 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
341
342 **/
343 EFI_STATUS
344 EFIAPI
345 FtwWrite (
346 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
347 IN EFI_LBA Lba,
348 IN UINTN Offset,
349 IN UINTN Length,
350 IN VOID *PrivateData,
351 IN EFI_HANDLE FvBlockHandle,
352 IN VOID *Buffer
353 )
354 {
355 EFI_STATUS Status;
356 EFI_FTW_DEVICE *FtwDevice;
357 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
358 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
359 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
360 UINTN MyLength;
361 UINTN MyOffset;
362 UINTN MyBufferSize;
363 UINT8 *MyBuffer;
364 UINTN SpareBufferSize;
365 UINT8 *SpareBuffer;
366 UINTN Index;
367 UINT8 *Ptr;
368 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
369
370 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
371
372 Status = WorkSpaceRefresh (FtwDevice);
373 if (EFI_ERROR (Status)) {
374 return EFI_ABORTED;
375 }
376
377 Header = FtwDevice->FtwLastWriteHeader;
378 Record = FtwDevice->FtwLastWriteRecord;
379
380 if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {
381 if (PrivateData == NULL) {
382 //
383 // Ftw Write Header is not allocated.
384 // No additional private data, the private data size is zero. Number of record can be set to 1.
385 //
386 Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);
387 if (EFI_ERROR (Status)) {
388 return Status;
389 }
390 } else {
391 //
392 // Ftw Write Header is not allocated
393 // Additional private data is not NULL, the private data size can't be determined.
394 //
395 DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));
396 DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));
397 return EFI_NOT_READY;
398 }
399 }
400
401 //
402 // If Record is out of the range of Header, return access denied.
403 //
404 if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {
405 return EFI_ACCESS_DENIED;
406 }
407
408 //
409 // Check the COMPLETE flag of last write header
410 //
411 if (Header->Complete == FTW_VALID_STATE) {
412 return EFI_ACCESS_DENIED;
413 }
414
415 if (Record->DestinationComplete == FTW_VALID_STATE) {
416 return EFI_ACCESS_DENIED;
417 }
418
419 if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {
420 return EFI_NOT_READY;
421 }
422 //
423 // Check if the input data can fit within the target block
424 //
425 if ((Offset + Length) > FtwDevice->SpareAreaLength) {
426 return EFI_BAD_BUFFER_SIZE;
427 }
428 //
429 // Get the FVB protocol by handle
430 //
431 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
432 if (EFI_ERROR (Status)) {
433 return EFI_NOT_FOUND;
434 }
435
436 Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
437 if (EFI_ERROR (Status)) {
438 DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));
439 return EFI_ABORTED;
440 }
441
442 //
443 // Set BootBlockUpdate FLAG if it's updating boot block.
444 //
445 if (IsBootBlock (FtwDevice, Fvb, Lba)) {
446 Record->BootBlockUpdate = FTW_VALID_STATE;
447 }
448 //
449 // Write the record to the work space.
450 //
451 Record->Lba = Lba;
452 Record->Offset = Offset;
453 Record->Length = Length;
454 Record->FvBaseAddress = FvbPhysicalAddress;
455 if (PrivateData != NULL) {
456 CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize);
457 }
458
459 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
460 MyLength = RECORD_SIZE (Header->PrivateDataSize);
461
462 Status = FtwDevice->FtwFvBlock->Write (
463 FtwDevice->FtwFvBlock,
464 FtwDevice->FtwWorkSpaceLba,
465 FtwDevice->FtwWorkSpaceBase + MyOffset,
466 &MyLength,
467 (UINT8 *) Record
468 );
469 if (EFI_ERROR (Status)) {
470 return EFI_ABORTED;
471 }
472 //
473 // Record has written to working block, then do the data.
474 //
475 //
476 // Allocate a memory buffer
477 //
478 MyBufferSize = FtwDevice->SpareAreaLength;
479 MyBuffer = AllocatePool (MyBufferSize);
480 if (MyBuffer == NULL) {
481 return EFI_OUT_OF_RESOURCES;
482 }
483 //
484 // Read all original data from target block to memory buffer
485 //
486 Ptr = MyBuffer;
487 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
488 MyLength = FtwDevice->BlockSize;
489 Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
490 if (EFI_ERROR (Status)) {
491 FreePool (MyBuffer);
492 return EFI_ABORTED;
493 }
494
495 Ptr += MyLength;
496 }
497 //
498 // Overwrite the updating range data with
499 // the input buffer content
500 //
501 CopyMem (MyBuffer + Offset, Buffer, Length);
502
503 //
504 // Try to keep the content of spare block
505 // Save spare block into a spare backup memory buffer (Sparebuffer)
506 //
507 SpareBufferSize = FtwDevice->SpareAreaLength;
508 SpareBuffer = AllocatePool (SpareBufferSize);
509 if (SpareBuffer == NULL) {
510 FreePool (MyBuffer);
511 return EFI_OUT_OF_RESOURCES;
512 }
513
514 Ptr = SpareBuffer;
515 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
516 MyLength = FtwDevice->BlockSize;
517 Status = FtwDevice->FtwBackupFvb->Read (
518 FtwDevice->FtwBackupFvb,
519 FtwDevice->FtwSpareLba + Index,
520 0,
521 &MyLength,
522 Ptr
523 );
524 if (EFI_ERROR (Status)) {
525 FreePool (MyBuffer);
526 FreePool (SpareBuffer);
527 return EFI_ABORTED;
528 }
529
530 Ptr += MyLength;
531 }
532 //
533 // Write the memory buffer to spare block
534 //
535 Status = FtwEraseSpareBlock (FtwDevice);
536 Ptr = MyBuffer;
537 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
538 MyLength = FtwDevice->BlockSize;
539 Status = FtwDevice->FtwBackupFvb->Write (
540 FtwDevice->FtwBackupFvb,
541 FtwDevice->FtwSpareLba + Index,
542 0,
543 &MyLength,
544 Ptr
545 );
546 if (EFI_ERROR (Status)) {
547 FreePool (MyBuffer);
548 FreePool (SpareBuffer);
549 return EFI_ABORTED;
550 }
551
552 Ptr += MyLength;
553 }
554 //
555 // Free MyBuffer
556 //
557 FreePool (MyBuffer);
558
559 //
560 // Set the SpareComplete in the FTW record,
561 //
562 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;
563 Status = FtwUpdateFvState (
564 FtwDevice->FtwFvBlock,
565 FtwDevice->FtwWorkSpaceLba,
566 FtwDevice->FtwWorkSpaceBase + MyOffset,
567 SPARE_COMPLETED
568 );
569 if (EFI_ERROR (Status)) {
570 FreePool (SpareBuffer);
571 return EFI_ABORTED;
572 }
573
574 Record->SpareComplete = FTW_VALID_STATE;
575
576 //
577 // Since the content has already backuped in spare block, the write is
578 // guaranteed to be completed with fault tolerant manner.
579 //
580 Status = FtwWriteRecord (This, Fvb);
581 if (EFI_ERROR (Status)) {
582 FreePool (SpareBuffer);
583 return EFI_ABORTED;
584 }
585 //
586 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
587 //
588 Status = FtwEraseSpareBlock (FtwDevice);
589 Ptr = SpareBuffer;
590 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
591 MyLength = FtwDevice->BlockSize;
592 Status = FtwDevice->FtwBackupFvb->Write (
593 FtwDevice->FtwBackupFvb,
594 FtwDevice->FtwSpareLba + Index,
595 0,
596 &MyLength,
597 Ptr
598 );
599 if (EFI_ERROR (Status)) {
600 FreePool (SpareBuffer);
601 return EFI_ABORTED;
602 }
603
604 Ptr += MyLength;
605 }
606 //
607 // All success.
608 //
609 FreePool (SpareBuffer);
610
611 DEBUG (
612 (EFI_D_ERROR,
613 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
614 Lba,
615 Offset,
616 Length)
617 );
618
619 return EFI_SUCCESS;
620 }
621
622 /**
623 Restarts a previously interrupted write. The caller must provide the
624 block protocol needed to complete the interrupted write.
625
626 @param This The pointer to this protocol instance.
627 @param FvBlockHandle The handle of FVB protocol that provides services for
628 reading, writing, and erasing the target block.
629
630 @retval EFI_SUCCESS The function completed successfully
631 @retval EFI_ACCESS_DENIED No pending writes exist
632 @retval EFI_NOT_FOUND FVB protocol not found by the handle
633 @retval EFI_ABORTED The function could not complete successfully
634
635 **/
636 EFI_STATUS
637 EFIAPI
638 FtwRestart (
639 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
640 IN EFI_HANDLE FvBlockHandle
641 )
642 {
643 EFI_STATUS Status;
644 EFI_FTW_DEVICE *FtwDevice;
645 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
646 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
647 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
648
649 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
650
651 Status = WorkSpaceRefresh (FtwDevice);
652 if (EFI_ERROR (Status)) {
653 return EFI_ABORTED;
654 }
655
656 Header = FtwDevice->FtwLastWriteHeader;
657 Record = FtwDevice->FtwLastWriteRecord;
658
659 //
660 // Spare Complete but Destination not complete,
661 // Recover the targt block with the spare block.
662 //
663 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);
664 if (EFI_ERROR (Status)) {
665 return EFI_NOT_FOUND;
666 }
667
668 //
669 // Check the COMPLETE flag of last write header
670 //
671 if (Header->Complete == FTW_VALID_STATE) {
672 return EFI_ACCESS_DENIED;
673 }
674
675 //
676 // Check the flags of last write record
677 //
678 if (Record->DestinationComplete == FTW_VALID_STATE) {
679 return EFI_ACCESS_DENIED;
680 }
681
682 if ((Record->SpareComplete != FTW_VALID_STATE)) {
683 return EFI_ABORTED;
684 }
685
686 //
687 // Since the content has already backuped in spare block, the write is
688 // guaranteed to be completed with fault tolerant manner.
689 //
690 Status = FtwWriteRecord (This, Fvb);
691 if (EFI_ERROR (Status)) {
692 return EFI_ABORTED;
693 }
694
695 //
696 // Erase Spare block
697 // This is restart, no need to keep spareblock content.
698 //
699 FtwEraseSpareBlock (FtwDevice);
700
701 DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));
702 return EFI_SUCCESS;
703 }
704
705 /**
706 Aborts all previous allocated writes.
707
708 @param This The pointer to this protocol instance.
709
710 @retval EFI_SUCCESS The function completed successfully
711 @retval EFI_ABORTED The function could not complete successfully.
712 @retval EFI_NOT_FOUND No allocated writes exist.
713
714 **/
715 EFI_STATUS
716 EFIAPI
717 FtwAbort (
718 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This
719 )
720 {
721 EFI_STATUS Status;
722 UINTN Offset;
723 EFI_FTW_DEVICE *FtwDevice;
724
725 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
726
727 Status = WorkSpaceRefresh (FtwDevice);
728 if (EFI_ERROR (Status)) {
729 return EFI_ABORTED;
730 }
731
732 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {
733 return EFI_NOT_FOUND;
734 }
735 //
736 // Update the complete state of the header as VALID and abort.
737 //
738 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;
739 Status = FtwUpdateFvState (
740 FtwDevice->FtwFvBlock,
741 FtwDevice->FtwWorkSpaceLba,
742 FtwDevice->FtwWorkSpaceBase + Offset,
743 WRITES_COMPLETED
744 );
745 if (EFI_ERROR (Status)) {
746 return EFI_ABORTED;
747 }
748
749 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;
750
751 DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));
752 return EFI_SUCCESS;
753 }
754
755 /**
756 Starts a target block update. This records information about the write
757 in fault tolerant storage and will complete the write in a recoverable
758 manner, ensuring at all times that either the original contents or
759 the modified contents are available.
760
761 @param This The pointer to this protocol instance.
762 @param CallerId The GUID identifying the last write.
763 @param Lba The logical block address of the last write.
764 @param Offset The offset within the block of the last write.
765 @param Length The length of the last write.
766 @param PrivateDataSize bytes from the private data
767 stored for this write.
768 @param PrivateData A pointer to a buffer. The function will copy
769 @param Complete A Boolean value with TRUE indicating
770 that the write was completed.
771
772 @retval EFI_SUCCESS The function completed successfully
773 @retval EFI_ABORTED The function could not complete successfully
774 @retval EFI_NOT_FOUND No allocated writes exist
775 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
776
777 **/
778 EFI_STATUS
779 EFIAPI
780 FtwGetLastWrite (
781 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,
782 OUT EFI_GUID *CallerId,
783 OUT EFI_LBA *Lba,
784 OUT UINTN *Offset,
785 OUT UINTN *Length,
786 IN OUT UINTN *PrivateDataSize,
787 OUT VOID *PrivateData,
788 OUT BOOLEAN *Complete
789 )
790 {
791 EFI_STATUS Status;
792 EFI_FTW_DEVICE *FtwDevice;
793 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
794 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;
795
796 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {
797 return EFI_UNSUPPORTED;
798 }
799
800 FtwDevice = FTW_CONTEXT_FROM_THIS (This);
801
802 Status = WorkSpaceRefresh (FtwDevice);
803 if (EFI_ERROR (Status)) {
804 return EFI_ABORTED;
805 }
806
807 Header = FtwDevice->FtwLastWriteHeader;
808 Record = FtwDevice->FtwLastWriteRecord;
809
810 //
811 // If Header is incompleted and the last record has completed, then
812 // call Abort() to set the Header->Complete FLAG.
813 //
814 if ((Header->Complete != FTW_VALID_STATE) &&
815 (Record->DestinationComplete == FTW_VALID_STATE) &&
816 IsLastRecordOfWrites (Header, Record)
817 ) {
818
819 Status = FtwAbort (This);
820 *Complete = TRUE;
821 return EFI_NOT_FOUND;
822 }
823 //
824 // If there is no write header/record, return not found.
825 //
826 if (Header->HeaderAllocated != FTW_VALID_STATE) {
827 *Complete = TRUE;
828 return EFI_NOT_FOUND;
829 }
830 //
831 // If this record SpareComplete has not set, then it can not restart.
832 //
833 if (Record->SpareComplete != FTW_VALID_STATE) {
834 Status = GetPreviousRecordOfWrites (Header, &Record);
835 if (EFI_ERROR (Status)) {
836 FtwAbort (This);
837 *Complete = TRUE;
838 return EFI_NOT_FOUND;
839 }
840 }
841
842 //
843 // Fill all the requested values
844 //
845 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));
846 *Lba = Record->Lba;
847 *Offset = Record->Offset;
848 *Length = Record->Length;
849 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);
850
851 if (*PrivateDataSize < Header->PrivateDataSize) {
852 *PrivateDataSize = Header->PrivateDataSize;
853 PrivateData = NULL;
854 Status = EFI_BUFFER_TOO_SMALL;
855 } else {
856 *PrivateDataSize = Header->PrivateDataSize;
857 CopyMem (PrivateData, Record + 1, *PrivateDataSize);
858 Status = EFI_SUCCESS;
859 }
860
861 DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));
862
863 return Status;
864 }
865
866 VOID
867 EFIAPI
868 FvbNotificationEvent (
869 IN EFI_EVENT Event,
870 IN VOID *Context
871 )
872 {
873 EFI_STATUS Status;
874 EFI_HANDLE *HandleBuffer;
875 UINTN HandleCount;
876 UINTN Index;
877 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
878 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
879 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
880 EFI_FVB_ATTRIBUTES_2 Attributes;
881 EFI_FTW_DEVICE *FtwDevice;
882 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
883 UINT32 LbaIndex;
884 UINTN Length;
885 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
886 UINTN Offset;
887 EFI_HANDLE FvbHandle;
888
889 FtwDevice = (EFI_FTW_DEVICE *)Context;
890 FvbHandle = NULL;
891 Fvb = NULL;
892
893 //
894 // Locate all handles of Fvb protocol
895 //
896 Status = gBS->LocateHandleBuffer (
897 ByProtocol,
898 &gEfiFirmwareVolumeBlockProtocolGuid,
899 NULL,
900 &HandleCount,
901 &HandleBuffer
902 );
903 if (EFI_ERROR (Status)) {
904 return;
905 }
906
907 //
908 // Get the FVB to access variable store
909 //
910 for (Index = 0; Index < HandleCount; Index += 1) {
911 Status = gBS->HandleProtocol (
912 HandleBuffer[Index],
913 &gEfiFirmwareVolumeBlockProtocolGuid,
914 (VOID **) &Fvb
915 );
916 if (EFI_ERROR (Status)) {
917 Status = EFI_NOT_FOUND;
918 break;
919 }
920
921 //
922 // Ensure this FVB protocol supported Write operation.
923 //
924 Status = Fvb->GetAttributes (Fvb, &Attributes);
925 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
926 continue;
927 }
928 //
929 // Compare the address and select the right one
930 //
931 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
932 if (EFI_ERROR (Status)) {
933 continue;
934 }
935
936 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
937 if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
938 ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
939 ) {
940 FtwDevice->FtwFvBlock = Fvb;
941 //
942 // To get the LBA of work space
943 //
944 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
945 //
946 // Now, one FV has one type of BlockLength
947 //
948 FvbMapEntry = &FwVolHeader->BlockMap[0];
949 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
950 if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
951 && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
952 FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
953 //
954 // Get the Work space size and Base(Offset)
955 //
956 FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
957 FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
958 break;
959 }
960 }
961 }
962 }
963
964 if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
965 ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
966 ) {
967 FtwDevice->FtwBackupFvb = Fvb;
968 //
969 // To get the LBA of spare
970 //
971 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
972 //
973 // Now, one FV has one type of BlockLength
974 //
975 FvbMapEntry = &FwVolHeader->BlockMap[0];
976 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
977 if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
978 && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
979 //
980 // Get the NumberOfSpareBlock and BlockSize
981 //
982 FtwDevice->FtwSpareLba = LbaIndex - 1;
983 FtwDevice->BlockSize = FvbMapEntry->Length;
984 FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;
985 //
986 // Check the range of spare area to make sure that it's in FV range
987 //
988 if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {
989 DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
990 ASSERT (FALSE);
991 return;
992 }
993 break;
994 }
995 }
996 }
997 }
998 }
999
1000 if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
1001 (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
1002 return;
1003 }
1004
1005 DEBUG ((EFI_D_INFO, "Ftw: Working and spare FVB is ready\n"));
1006 //
1007 // Calculate the start LBA of working block. Working block is an area which
1008 // contains working space in its last block and has the same size as spare
1009 // block, unless there are not enough blocks before the block that contains
1010 // working space.
1011 //
1012 FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;
1013 ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0);
1014
1015 //
1016 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
1017 //
1018 FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
1019 FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
1020
1021 FtwDevice->FtwLastWriteHeader = NULL;
1022 FtwDevice->FtwLastWriteRecord = NULL;
1023
1024 //
1025 // Refresh the working space data from working block
1026 //
1027 Status = WorkSpaceRefresh (FtwDevice);
1028 ASSERT_EFI_ERROR (Status);
1029 //
1030 // If the working block workspace is not valid, try the spare block
1031 //
1032 if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
1033 //
1034 // Read from spare block
1035 //
1036 Length = FtwDevice->FtwWorkSpaceSize;
1037 Status = FtwDevice->FtwBackupFvb->Read (
1038 FtwDevice->FtwBackupFvb,
1039 FtwDevice->FtwSpareLba,
1040 FtwDevice->FtwWorkSpaceBase,
1041 &Length,
1042 FtwDevice->FtwWorkSpace
1043 );
1044 ASSERT_EFI_ERROR (Status);
1045
1046 //
1047 // If spare block is valid, then replace working block content.
1048 //
1049 if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
1050 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
1051 DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in Init() - %r\n", Status));
1052 FtwAbort (&FtwDevice->FtwInstance);
1053 //
1054 // Refresh work space.
1055 //
1056 Status = WorkSpaceRefresh (FtwDevice);
1057 ASSERT_EFI_ERROR (Status);
1058 } else {
1059 DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));
1060 //
1061 // If both are invalid, then initialize work space.
1062 //
1063 SetMem (
1064 FtwDevice->FtwWorkSpace,
1065 FtwDevice->FtwWorkSpaceSize,
1066 FTW_ERASED_BYTE
1067 );
1068 InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
1069 //
1070 // Initialize the work space
1071 //
1072 Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
1073 ASSERT_EFI_ERROR (Status);
1074 }
1075 }
1076 //
1077 // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
1078 // (! SpareComplete) THEN call Abort().
1079 //
1080 if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
1081 (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
1082 IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
1083 ) {
1084 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
1085 FtwAbort (&FtwDevice->FtwInstance);
1086 }
1087 //
1088 // If Header is incompleted and the last record has completed, then
1089 // call Abort() to set the Header->Complete FLAG.
1090 //
1091 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
1092 (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
1093 IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
1094 ) {
1095 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
1096 FtwAbort (&FtwDevice->FtwInstance);
1097 }
1098 //
1099 // To check the workspace buffer following last Write header/records is EMPTY or not.
1100 // If it's not EMPTY, FTW also need to call reclaim().
1101 //
1102 FtwHeader = FtwDevice->FtwLastWriteHeader;
1103 Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
1104 if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
1105 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
1106 }
1107
1108 if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
1109 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
1110 ASSERT_EFI_ERROR (Status);
1111 }
1112
1113 //
1114 // Restart if it's boot block
1115 //
1116 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
1117 (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
1118 ) {
1119 if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
1120 Status = FlushSpareBlockToBootBlock (FtwDevice);
1121 DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
1122 ASSERT_EFI_ERROR (Status);
1123 FtwAbort (&FtwDevice->FtwInstance);
1124 } else {
1125 //
1126 // if (SpareCompleted) THEN Restart to fault tolerant write.
1127 //
1128 FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);
1129 if (FvbHandle != NULL) {
1130 Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
1131 DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
1132 ASSERT_EFI_ERROR (Status);
1133 }
1134 FtwAbort (&FtwDevice->FtwInstance);
1135 }
1136 }
1137 //
1138 // Hook the protocol API
1139 //
1140 FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
1141 FtwDevice->FtwInstance.Allocate = FtwAllocate;
1142 FtwDevice->FtwInstance.Write = FtwWrite;
1143 FtwDevice->FtwInstance.Restart = FtwRestart;
1144 FtwDevice->FtwInstance.Abort = FtwAbort;
1145 FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
1146
1147 //
1148 // Install protocol interface
1149 //
1150 Status = gBS->InstallProtocolInterface (
1151 &FtwDevice->Handle,
1152 &gEfiFaultTolerantWriteProtocolGuid,
1153 EFI_NATIVE_INTERFACE,
1154 &FtwDevice->FtwInstance
1155 );
1156
1157 ASSERT_EFI_ERROR (Status);
1158
1159 //
1160 // Close the notify event to avoid install FaultTolerantWriteProtocol again.
1161 //
1162 Status = gBS->CloseEvent (Event);
1163 ASSERT_EFI_ERROR (Status);
1164
1165 return;
1166 }
1167
1168 /**
1169 This function is the entry point of the Fault Tolerant Write driver.
1170
1171 @param ImageHandle A handle for the image that is initializing this driver
1172 @param SystemTable A pointer to the EFI system table
1173
1174 @return EFI_SUCCESS FTW has finished the initialization
1175 @retval EFI_NOT_FOUND Locate FVB protocol error
1176 @retval EFI_OUT_OF_RESOURCES Allocate memory error
1177 @retval EFI_VOLUME_CORRUPTED Firmware volume is error
1178 @retval EFI_ABORTED FTW initialization error
1179
1180 **/
1181 EFI_STATUS
1182 EFIAPI
1183 InitializeFaultTolerantWrite (
1184 IN EFI_HANDLE ImageHandle,
1185 IN EFI_SYSTEM_TABLE *SystemTable
1186 )
1187 {
1188 EFI_FTW_DEVICE *FtwDevice;
1189
1190 //
1191 // Allocate Private data of this driver,
1192 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
1193 //
1194 FtwDevice = NULL;
1195 FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
1196 if (FtwDevice == NULL) {
1197 return EFI_OUT_OF_RESOURCES;
1198 }
1199
1200 ZeroMem (FtwDevice, sizeof (EFI_FTW_DEVICE));
1201 FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
1202
1203 //
1204 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
1205 //
1206
1207 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
1208 FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
1209
1210 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
1211 FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
1212
1213 if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
1214 DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
1215 FreePool (FtwDevice);
1216 return EFI_OUT_OF_RESOURCES;
1217 }
1218 FtwDevice->FtwFvBlock = NULL;
1219 FtwDevice->FtwBackupFvb = NULL;
1220 FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
1221 FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
1222
1223 //
1224 // Register FvbNotificationEvent () notify function.
1225 //
1226 EfiCreateProtocolNotifyEvent (
1227 &gEfiFirmwareVolumeBlockProtocolGuid,
1228 TPL_CALLBACK,
1229 FvbNotificationEvent,
1230 (VOID *)FtwDevice,
1231 &mFvbRegistration
1232 );
1233
1234 return EFI_SUCCESS;
1235 }