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