Adjust directory structures.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / FtwLite.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13 Module Name:
14
15 FtwLite.c
16
17 Abstract:
18
19 This is a simple fault tolerant write driver, based on PlatformFd library.
20 And it only supports write BufferSize <= SpareAreaLength.
21
22 This boot service only protocol provides fault tolerant write capability for
23 block devices. The protocol has internal non-volatile intermediate storage
24 of the data and private information. It should be able to recover
25 automatically from a critical fault, such as power failure.
26
27 Notes:
28
29 The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
30 This work space is a memory copy of the work space on the Woring Block,
31 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
32
33 --*/
34
35 #include <FtwLite.h>
36
37 //
38 // In write function, we should check the target range to prevent the user
39 // from writing Spare block and Working space directly.
40 //
41 //
42 // Fault Tolerant Write Protocol API
43 //
44 EFI_STATUS
45 EFIAPI
46 FtwLiteWrite (
47 IN EFI_FTW_LITE_PROTOCOL *This,
48 IN EFI_HANDLE FvbHandle,
49 IN EFI_LBA Lba,
50 IN UINTN Offset,
51 IN OUT UINTN *NumBytes,
52 IN VOID *Buffer
53 )
54 /*++
55
56 Routine Description:
57 Starts a target block update. This function will record data about write
58 in fault tolerant storage and will complete the write in a recoverable
59 manner, ensuring at all times that either the original contents or
60 the modified contents are available.
61
62 Arguments:
63 This - Calling context
64 FvbHandle - The handle of FVB protocol that provides services for
65 reading, writing, and erasing the target block.
66 Lba - The logical block address of the target block.
67 Offset - The offset within the target block to place the data.
68 NumBytes - The number of bytes to write to the target block.
69 Buffer - The data to write.
70
71 Returns:
72 EFI_SUCCESS - The function completed successfully
73 EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not
74 a valid action.
75 EFI_ACCESS_DENIED - No writes have been allocated.
76 EFI_NOT_FOUND - Cannot find FVB by handle.
77 EFI_OUT_OF_RESOURCES - Cannot allocate memory.
78 EFI_ABORTED - The function could not complete successfully.
79
80 --*/
81 {
82 EFI_STATUS Status;
83 EFI_FTW_LITE_DEVICE *FtwLiteDevice;
84 EFI_FTW_LITE_RECORD *Record;
85 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
86 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
87 UINTN MyLength;
88 UINTN MyOffset;
89 UINTN MyBufferSize;
90 UINT8 *MyBuffer;
91 UINTN SpareBufferSize;
92 UINT8 *SpareBuffer;
93 UINTN Index;
94 UINT8 *Ptr;
95 EFI_DEV_PATH_PTR DevPtr;
96
97 //
98 // Refresh work space and get last record
99 //
100 FtwLiteDevice = FTW_LITE_CONTEXT_FROM_THIS (This);
101 Status = WorkSpaceRefresh (FtwLiteDevice);
102 if (EFI_ERROR (Status)) {
103 return EFI_ABORTED;
104 }
105
106 Record = FtwLiteDevice->FtwLastRecord;
107
108 //
109 // Check the flags of last write record
110 //
111 if ((Record->WriteAllocated == FTW_VALID_STATE) || (Record->SpareCompleted == FTW_VALID_STATE)) {
112 return EFI_ACCESS_DENIED;
113 }
114 //
115 // IF former record has completed, THEN use next record
116 //
117 if (Record->WriteCompleted == FTW_VALID_STATE) {
118 Record++;
119 FtwLiteDevice->FtwLastRecord = Record;
120 }
121
122 MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
123
124 //
125 // Check if the input data can fit within the target block
126 //
127 if ((Offset +*NumBytes) > FtwLiteDevice->SpareAreaLength) {
128 return EFI_BAD_BUFFER_SIZE;
129 }
130 //
131 // Check if there is enough free space for allocate a record
132 //
133 if ((MyOffset + WRITE_TOTAL_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) {
134 Status = FtwReclaimWorkSpace (FtwLiteDevice);
135 if (EFI_ERROR (Status)) {
136 DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim work space - %r", Status));
137 return EFI_ABORTED;
138 }
139 }
140 //
141 // Get the FVB protocol by handle
142 //
143 Status = FtwGetFvbByHandle (FvbHandle, &Fvb);
144 if (EFI_ERROR (Status)) {
145 return EFI_NOT_FOUND;
146 }
147 //
148 // Allocate a write record in workspace.
149 // Update Header->WriteAllocated as VALID
150 //
151 Status = FtwUpdateFvState (
152 FtwLiteDevice->FtwFvBlock,
153 FtwLiteDevice->FtwWorkSpaceLba,
154 FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
155 WRITE_ALLOCATED
156 );
157
158 if (EFI_ERROR (Status)) {
159 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Allocate record - %r\n", Status));
160 return EFI_ABORTED;
161 }
162
163 Record->WriteAllocated = FTW_VALID_STATE;
164
165 //
166 // Prepare data of write record, filling DevPath with memory mapped address.
167 //
168 DevPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath;
169 DevPtr.MemMap->Header.Type = HARDWARE_DEVICE_PATH;
170 DevPtr.MemMap->Header.SubType = HW_MEMMAP_DP;
171 SetDevicePathNodeLength (&DevPtr.MemMap->Header, sizeof (MEMMAP_DEVICE_PATH));
172
173 Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
174 if (EFI_ERROR (Status)) {
175 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Get FVB physical address - %r\n", Status));
176 return EFI_ABORTED;
177 }
178
179 DevPtr.MemMap->MemoryType = EfiMemoryMappedIO;
180 DevPtr.MemMap->StartingAddress = FvbPhysicalAddress;
181 DevPtr.MemMap->EndingAddress = FvbPhysicalAddress +*NumBytes;
182 //
183 // ignored!
184 //
185 Record->Lba = Lba;
186 Record->Offset = Offset;
187 Record->NumBytes = *NumBytes;
188
189 //
190 // Write the record to the work space.
191 //
192 MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
193 MyLength = FTW_LITE_RECORD_SIZE;
194
195 Status = FtwLiteDevice->FtwFvBlock->Write (
196 FtwLiteDevice->FtwFvBlock,
197 FtwLiteDevice->FtwWorkSpaceLba,
198 FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
199 &MyLength,
200 (UINT8 *) Record
201 );
202 if (EFI_ERROR (Status)) {
203 return EFI_ABORTED;
204 }
205 //
206 // Record has been written to working block, then write data.
207 //
208 //
209 // Allocate a memory buffer
210 //
211 MyBufferSize = FtwLiteDevice->SpareAreaLength;
212 MyBuffer = AllocatePool (MyBufferSize);
213 if (MyBuffer == NULL) {
214 return EFI_OUT_OF_RESOURCES;
215 }
216 //
217 // Starting at Lba, if the number of the rest blocks on Fvb is less
218 // than NumberOfSpareBlock.
219 //
220 //
221 // Read all original data from target block to memory buffer
222 //
223 if (IsInWorkingBlock (FtwLiteDevice, Fvb, Lba)) {
224 //
225 // If target block falls into working block, we must follow the process of
226 // updating working block.
227 //
228 Ptr = MyBuffer;
229 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
230 MyLength = FtwLiteDevice->SizeOfSpareBlock;
231 Status = FtwLiteDevice->FtwFvBlock->Read (
232 FtwLiteDevice->FtwFvBlock,
233 FtwLiteDevice->FtwWorkBlockLba + Index,
234 0,
235 &MyLength,
236 Ptr
237 );
238 if (EFI_ERROR (Status)) {
239 FreePool (MyBuffer);
240 return EFI_ABORTED;
241 }
242
243 Ptr += MyLength;
244 }
245 //
246 // Update Offset by adding the offset from the start LBA of working block to
247 // the target LBA. The target block can not span working block!
248 //
249 Offset = (((UINTN) (Lba - FtwLiteDevice->FtwWorkBlockLba)) * FtwLiteDevice->SizeOfSpareBlock + Offset);
250 ASSERT ((Offset +*NumBytes) <= FtwLiteDevice->SpareAreaLength);
251
252 } else {
253
254 Ptr = MyBuffer;
255 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
256 MyLength = FtwLiteDevice->SizeOfSpareBlock;
257 Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
258 if (EFI_ERROR (Status)) {
259 FreePool (MyBuffer);
260 return EFI_ABORTED;
261 }
262
263 Ptr += MyLength;
264 }
265 }
266 //
267 // Overwrite the updating range data with
268 // the input buffer content
269 //
270 CopyMem (MyBuffer + Offset, Buffer, *NumBytes);
271
272 //
273 // Try to keep the content of spare block
274 // Save spare block into a spare backup memory buffer (Sparebuffer)
275 //
276 SpareBufferSize = FtwLiteDevice->SpareAreaLength;
277 SpareBuffer = AllocatePool (SpareBufferSize);
278 if (SpareBuffer == NULL) {
279 FreePool (MyBuffer);
280 return EFI_OUT_OF_RESOURCES;
281 }
282
283 Ptr = SpareBuffer;
284 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
285 MyLength = FtwLiteDevice->SizeOfSpareBlock;
286 Status = FtwLiteDevice->FtwBackupFvb->Read (
287 FtwLiteDevice->FtwBackupFvb,
288 FtwLiteDevice->FtwSpareLba + Index,
289 0,
290 &MyLength,
291 Ptr
292 );
293 if (EFI_ERROR (Status)) {
294 FreePool (MyBuffer);
295 FreePool (SpareBuffer);
296 return EFI_ABORTED;
297 }
298
299 Ptr += MyLength;
300 }
301 //
302 // Write the memory buffer to spare block
303 // Don't forget to erase Flash first.
304 //
305 Status = FtwEraseSpareBlock (FtwLiteDevice);
306 Ptr = MyBuffer;
307 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
308 MyLength = FtwLiteDevice->SizeOfSpareBlock;
309 Status = FtwLiteDevice->FtwBackupFvb->Write (
310 FtwLiteDevice->FtwBackupFvb,
311 FtwLiteDevice->FtwSpareLba + Index,
312 0,
313 &MyLength,
314 Ptr
315 );
316 if (EFI_ERROR (Status)) {
317 FreePool (MyBuffer);
318 FreePool (SpareBuffer);
319 return EFI_ABORTED;
320 }
321
322 Ptr += MyLength;
323 }
324 //
325 // Free MyBuffer
326 //
327 FreePool (MyBuffer);
328
329 //
330 // Set the SpareCompleteD in the FTW record,
331 //
332 MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
333 Status = FtwUpdateFvState (
334 FtwLiteDevice->FtwFvBlock,
335 FtwLiteDevice->FtwWorkSpaceLba,
336 FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
337 SPARE_COMPLETED
338 );
339 if (EFI_ERROR (Status)) {
340 FreePool (SpareBuffer);
341 return EFI_ABORTED;
342 }
343
344 Record->SpareCompleted = FTW_VALID_STATE;
345
346 //
347 // Since the content has already backuped in spare block, the write is
348 // guaranteed to be completed with fault tolerant manner.
349 //
350 Status = FtwWriteRecord (FtwLiteDevice, Fvb);
351 if (EFI_ERROR (Status)) {
352 FreePool (SpareBuffer);
353 return EFI_ABORTED;
354 }
355
356 Record++;
357 FtwLiteDevice->FtwLastRecord = Record;
358
359 //
360 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
361 //
362 Status = FtwEraseSpareBlock (FtwLiteDevice);
363 Ptr = SpareBuffer;
364 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
365 MyLength = FtwLiteDevice->SizeOfSpareBlock;
366 Status = FtwLiteDevice->FtwBackupFvb->Write (
367 FtwLiteDevice->FtwBackupFvb,
368 FtwLiteDevice->FtwSpareLba + Index,
369 0,
370 &MyLength,
371 Ptr
372 );
373 if (EFI_ERROR (Status)) {
374 FreePool (SpareBuffer);
375 return EFI_ABORTED;
376 }
377
378 Ptr += MyLength;
379 }
380 //
381 // All success.
382 //
383 FreePool (SpareBuffer);
384
385 DEBUG (
386 (EFI_D_FTW_LITE,
387 "FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
388 Lba,
389 Offset,
390 *NumBytes)
391 );
392
393 return EFI_SUCCESS;
394 }
395
396
397 EFI_STATUS
398 FtwWriteRecord (
399 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
400 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
401 )
402 /*++
403
404 Routine Description:
405 Write a record with fault tolerant mannaer.
406 Since the content has already backuped in spare block, the write is
407 guaranteed to be completed with fault tolerant manner.
408
409 Arguments:
410 FtwLiteDevice - The private data of FTW_LITE driver
411 Fvb - The FVB protocol that provides services for
412 reading, writing, and erasing the target block.
413
414 Returns:
415 EFI_SUCCESS - The function completed successfully
416 EFI_ABORTED - The function could not complete successfully
417
418 --*/
419 {
420 EFI_STATUS Status;
421 EFI_FTW_LITE_RECORD *Record;
422 EFI_LBA WorkSpaceLbaOffset;
423 UINTN Offset;
424
425 //
426 // Spare Complete but Destination not complete,
427 // Recover the targt block with the spare block.
428 //
429 Record = FtwLiteDevice->FtwLastRecord;
430
431 //
432 // IF target block is working block, THEN Flush Spare Block To Working Block;
433 // ELSE IF target block is boot block, THEN Flush Spare Block To boot Block;
434 // ELSE flush spare block to normal target block.ENDIF
435 //
436 if (IsInWorkingBlock (FtwLiteDevice, Fvb, Record->Lba)) {
437 //
438 // If target block is working block, Attention:
439 // it's required to set SPARE_COMPLETED to spare block.
440 //
441 WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
442 Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
443 Status = FtwUpdateFvState (
444 FtwLiteDevice->FtwBackupFvb,
445 FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
446 FtwLiteDevice->FtwWorkSpaceBase + Offset,
447 SPARE_COMPLETED
448 );
449 ASSERT_EFI_ERROR (Status);
450
451 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
452 } else if (IsBootBlock (FtwLiteDevice, Fvb, Record->Lba)) {
453 //
454 // Update boot block
455 //
456 Status = FlushSpareBlockToBootBlock (FtwLiteDevice);
457 } else {
458 //
459 // Update blocks other than working block or boot block
460 //
461 Status = FlushSpareBlockToTargetBlock (FtwLiteDevice, Fvb, Record->Lba);
462 }
463
464 ASSERT_EFI_ERROR (Status);
465
466 //
467 // Set WriteCompleted flag in record
468 //
469 Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
470 Status = FtwUpdateFvState (
471 FtwLiteDevice->FtwFvBlock,
472 FtwLiteDevice->FtwWorkSpaceLba,
473 FtwLiteDevice->FtwWorkSpaceBase + Offset,
474 WRITE_COMPLETED
475 );
476 ASSERT_EFI_ERROR (Status);
477
478 Record->WriteCompleted = FTW_VALID_STATE;
479 return EFI_SUCCESS;
480 }
481
482
483 EFI_STATUS
484 FtwRestart (
485 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
486 )
487 /*++
488
489 Routine Description:
490 Restarts a previously interrupted write. The caller must provide the
491 block protocol needed to complete the interrupted write.
492
493 Arguments:
494 FtwLiteDevice - The private data of FTW_LITE driver
495 FvbHandle - The handle of FVB protocol that provides services for
496 reading, writing, and erasing the target block.
497
498 Returns:
499 EFI_SUCCESS - The function completed successfully
500 EFI_ACCESS_DENIED - No pending writes exist
501 EFI_NOT_FOUND - FVB protocol not found by the handle
502 EFI_ABORTED - The function could not complete successfully
503
504 --*/
505 {
506 EFI_STATUS Status;
507 EFI_FTW_LITE_RECORD *Record;
508 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
509 EFI_DEV_PATH_PTR DevPathPtr;
510
511 //
512 // Spare Completed but Destination not complete,
513 // Recover the targt block with the spare block.
514 //
515 Record = FtwLiteDevice->FtwLastRecord;
516
517 //
518 // Only support memory mapped FVB device path by now.
519 //
520 DevPathPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath;
521 if (!((DevPathPtr.MemMap->Header.Type == HARDWARE_DEVICE_PATH) && (DevPathPtr.MemMap->Header.SubType == HW_MEMMAP_DP))
522 ) {
523 DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Device Path is not memory mapped\n"));
524 return EFI_ABORTED;
525 }
526
527 Status = GetFvbByAddress (DevPathPtr.MemMap->StartingAddress, &Fvb);
528 if (EFI_ERROR (Status)) {
529 return EFI_NOT_FOUND;
530 }
531 //
532 // Since the content has already backuped in spare block, the write is
533 // guaranteed to be completed with fault tolerant manner.
534 //
535 Status = FtwWriteRecord (FtwLiteDevice, Fvb);
536 DEBUG ((EFI_D_FTW_INFO, "FtwLite: Restart() - %r\n", Status));
537
538 Record++;
539 FtwLiteDevice->FtwLastRecord = Record;
540
541 //
542 // Erase Spare block
543 // This is restart, no need to keep spareblock content.
544 //
545 FtwEraseSpareBlock (FtwLiteDevice);
546
547 return Status;
548 }
549
550
551 EFI_STATUS
552 FtwAbort (
553 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
554 )
555 /*++
556
557 Routine Description:
558 Aborts all previous allocated writes.
559
560 Arguments:
561 FtwLiteDevice - The private data of FTW_LITE driver
562
563 Returns:
564 EFI_SUCCESS - The function completed successfully
565 EFI_ABORTED - The function could not complete successfully.
566 EFI_NOT_FOUND - No allocated writes exist.
567
568 --*/
569 {
570 EFI_STATUS Status;
571 UINTN Offset;
572
573 if (FtwLiteDevice->FtwLastRecord->WriteCompleted == FTW_VALID_STATE) {
574 return EFI_NOT_FOUND;
575 }
576 //
577 // Update the complete state of the header as VALID and abort.
578 //
579 Offset = (UINT8 *) FtwLiteDevice->FtwLastRecord - FtwLiteDevice->FtwWorkSpace;
580 Status = FtwUpdateFvState (
581 FtwLiteDevice->FtwFvBlock,
582 FtwLiteDevice->FtwWorkSpaceLba,
583 FtwLiteDevice->FtwWorkSpaceBase + Offset,
584 WRITE_COMPLETED
585 );
586 if (EFI_ERROR (Status)) {
587 return EFI_ABORTED;
588 }
589
590 FtwLiteDevice->FtwLastRecord->WriteCompleted = FTW_VALID_STATE;
591
592 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
593
594 //
595 // Erase the spare block
596 //
597 Status = FtwEraseSpareBlock (FtwLiteDevice);
598
599 DEBUG ((EFI_D_FTW_INFO, "FtwLite: Abort() success \n"));
600 return EFI_SUCCESS;
601 }
602
603 EFI_STATUS
604 EFIAPI
605 InitializeFtwLite (
606 IN EFI_HANDLE ImageHandle,
607 IN EFI_SYSTEM_TABLE *SystemTable
608 )
609 /*++
610 Routine Description:
611 This function is the entry point of the Fault Tolerant Write driver.
612
613 Arguments:
614 ImageHandle - EFI_HANDLE: A handle for the image that is initializing
615 this driver
616 SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table
617
618 Returns:
619 EFI_SUCCESS - FTW has finished the initialization
620 EFI_ABORTED - FTW initialization error
621
622 --*/
623 {
624 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
625 UINTN Index;
626 EFI_HANDLE *HandleBuffer;
627 UINTN HandleCount;
628 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
629 EFI_PHYSICAL_ADDRESS BaseAddress;
630 EFI_FTW_LITE_DEVICE *FtwLiteDevice;
631 EFI_FTW_LITE_RECORD *Record;
632 UINTN Length;
633 EFI_STATUS Status;
634 UINTN Offset;
635 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
636 UINT32 LbaIndex;
637
638 //
639 // Allocate Private data of this driver,
640 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
641 //
642 FtwLiteDevice = NULL;
643 FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);
644 if (FtwLiteDevice != NULL) {
645 Status = EFI_SUCCESS;
646 } else {
647 Status = EFI_OUT_OF_RESOURCES;
648 }
649
650 ASSERT_EFI_ERROR (Status);
651
652 ZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE));
653 FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE;
654
655 //
656 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
657 //
658 FtwLiteDevice->FtwWorkSpace = (UINT8 *) (FtwLiteDevice + 1);
659 FtwLiteDevice->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE;
660 SetMem (
661 FtwLiteDevice->FtwWorkSpace,
662 FtwLiteDevice->FtwWorkSpaceSize,
663 FTW_ERASED_BYTE
664 );
665 FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace;
666
667 FtwLiteDevice->FtwLastRecord = NULL;
668
669 FtwLiteDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
670 FtwLiteDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
671
672 FtwLiteDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
673 FtwLiteDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
674
675 ASSERT ((FtwLiteDevice->WorkSpaceLength != 0) && (FtwLiteDevice->SpareAreaLength != 0));
676
677 //
678 // Locate FVB protocol
679 //
680 Status = gBS->LocateHandleBuffer (
681 ByProtocol,
682 &gEfiFirmwareVolumeBlockProtocolGuid,
683 NULL,
684 &HandleCount,
685 &HandleBuffer
686 );
687 ASSERT_EFI_ERROR (Status);
688
689 ASSERT (HandleCount > 0);
690
691 FtwLiteDevice->FtwFvBlock = NULL;
692 FtwLiteDevice->FtwBackupFvb = NULL;
693 FtwLiteDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
694 FtwLiteDevice->FtwSpareLba = (EFI_LBA) (-1);
695 for (Index = 0; Index < HandleCount; Index += 1) {
696 Status = gBS->HandleProtocol (
697 HandleBuffer[Index],
698 &gEfiFirmwareVolumeBlockProtocolGuid,
699 (VOID **) &Fvb
700 );
701 ASSERT_EFI_ERROR (Status);
702
703 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
704 if (EFI_ERROR (Status)) {
705 continue;
706 }
707
708 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);
709
710 if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) &&
711 (FtwLiteDevice->WorkSpaceAddress <= (BaseAddress + FwVolHeader->FvLength))
712 ) {
713 FtwLiteDevice->FtwFvBlock = Fvb;
714 //
715 // To get the LBA of work space
716 //
717 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
718 //
719 // FV may have multiple types of BlockLength
720 //
721 FvbMapEntry = &FwVolHeader->BlockMap[0];
722 while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {
723 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
724 if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex)) {
725 FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;
726 //
727 // Get the Work space size and Base(Offset)
728 //
729 FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength;
730 FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
731 break;
732 }
733 }
734 //
735 // end for
736 //
737 FvbMapEntry++;
738 }
739 //
740 // end while
741 //
742 }
743 }
744
745 if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&
746 (FtwLiteDevice->SpareAreaAddress <= (BaseAddress + FwVolHeader->FvLength))
747 ) {
748 FtwLiteDevice->FtwBackupFvb = Fvb;
749 //
750 // To get the LBA of spare
751 //
752 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
753 //
754 // FV may have multiple types of BlockLength
755 //
756 FvbMapEntry = &FwVolHeader->BlockMap[0];
757 while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {
758 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
759 if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex)) {
760 //
761 // Get the NumberOfSpareBlock and SizeOfSpareBlock
762 //
763 FtwLiteDevice->FtwSpareLba = LbaIndex - 1;
764 FtwLiteDevice->SizeOfSpareBlock = FvbMapEntry->Length;
765 FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->SizeOfSpareBlock;
766 //
767 // Check the range of spare area to make sure that it's in FV range
768 //
769 ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks);
770 break;
771 }
772 }
773
774 FvbMapEntry++;
775 }
776 //
777 // end while
778 //
779 }
780 }
781 }
782 //
783 // Calculate the start LBA of working block. Working block is an area which
784 // contains working space in its last block and has the same size as spare
785 // block, unless there are not enough blocks before the block that contains
786 // working space.
787 //
788 FtwLiteDevice->FtwWorkBlockLba = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->NumberOfSpareBlock + 1;
789 if ((INT64) (FtwLiteDevice->FtwWorkBlockLba) < 0) {
790 FtwLiteDevice->FtwWorkBlockLba = 0;
791 }
792
793 if ((FtwLiteDevice->FtwFvBlock == NULL) ||
794 (FtwLiteDevice->FtwBackupFvb == NULL) ||
795 (FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||
796 (FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))
797 ) {
798 DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));
799 ASSERT_EFI_ERROR (Status);
800 }
801 //
802 // Refresh workspace data from working block
803 //
804 Status = WorkSpaceRefresh (FtwLiteDevice);
805 ASSERT_EFI_ERROR (Status);
806
807 //
808 // If the working block workspace is not valid, try the spare block
809 //
810 if (!IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
811 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace invalid, read from backup\n"));
812 //
813 // Read from spare block
814 //
815 Length = FtwLiteDevice->FtwWorkSpaceSize;
816 Status = FtwLiteDevice->FtwBackupFvb->Read (
817 FtwLiteDevice->FtwBackupFvb,
818 FtwLiteDevice->FtwSpareLba,
819 FtwLiteDevice->FtwWorkSpaceBase,
820 &Length,
821 FtwLiteDevice->FtwWorkSpace
822 );
823 ASSERT_EFI_ERROR (Status);
824
825 //
826 // If spare block is valid, then replace working block content.
827 //
828 if (IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
829 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
830 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart working block in Init() - %r\n", Status));
831 ASSERT_EFI_ERROR (Status);
832
833 FtwAbort (FtwLiteDevice);
834 //
835 // Refresh work space.
836 //
837 Status = WorkSpaceRefresh (FtwLiteDevice);
838 if (EFI_ERROR (Status)) {
839 return EFI_ABORTED;
840 }
841 } else {
842 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Both are invalid, init workspace\n"));
843 //
844 // If both are invalid, then initialize work space.
845 //
846 SetMem (
847 FtwLiteDevice->FtwWorkSpace,
848 FtwLiteDevice->FtwWorkSpaceSize,
849 FTW_ERASED_BYTE
850 );
851 InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);
852 //
853 // Write to work space on the working block
854 //
855 Length = FtwLiteDevice->FtwWorkSpaceSize;
856 Status = FtwLiteDevice->FtwFvBlock->Write (
857 FtwLiteDevice->FtwFvBlock,
858 FtwLiteDevice->FtwWorkSpaceLba,
859 FtwLiteDevice->FtwWorkSpaceBase,
860 &Length,
861 FtwLiteDevice->FtwWorkSpace
862 );
863 if (EFI_ERROR (Status)) {
864 return EFI_ABORTED;
865 }
866 }
867 }
868 //
869 // Hook the protocol API
870 //
871 FtwLiteDevice->FtwLiteInstance.Write = FtwLiteWrite;
872
873 //
874 // Install protocol interface
875 //
876 Status = gBS->InstallProtocolInterface (
877 &FtwLiteDevice->Handle,
878 &gEfiFaultTolerantWriteLiteProtocolGuid,
879 EFI_NATIVE_INTERFACE,
880 &FtwLiteDevice->FtwLiteInstance
881 );
882 if (EFI_ERROR (Status)) {
883 return EFI_ABORTED;
884 }
885 //
886 // If (!SpareCompleted) THEN Abort to rollback.
887 //
888 if ((FtwLiteDevice->FtwLastRecord->WriteAllocated == FTW_VALID_STATE) &&
889 (FtwLiteDevice->FtwLastRecord->SpareCompleted != FTW_VALID_STATE)
890 ) {
891 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
892 FtwAbort (FtwLiteDevice);
893 }
894 //
895 // if (SpareCompleted) THEN Restart to fault tolerant write.
896 //
897 if ((FtwLiteDevice->FtwLastRecord->SpareCompleted == FTW_VALID_STATE) &&
898 (FtwLiteDevice->FtwLastRecord->WriteCompleted != FTW_VALID_STATE)
899 ) {
900
901 Status = FtwRestart (FtwLiteDevice);
902 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart last write - %r\n", Status));
903 if (EFI_ERROR (Status)) {
904 return Status;
905 }
906 }
907 //
908 // To check the workspace buffer behind last records is EMPTY or not.
909 // If it's not EMPTY, FTW_LITE also need to call reclaim().
910 //
911 Record = FtwLiteDevice->FtwLastRecord;
912 Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
913 if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
914 Offset += WRITE_TOTAL_SIZE;
915 }
916
917 if (!IsErasedFlashBuffer (
918 FTW_ERASE_POLARITY,
919 FtwLiteDevice->FtwWorkSpace + Offset,
920 FtwLiteDevice->FtwWorkSpaceSize - Offset
921 )) {
922 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n"));
923 Status = FtwReclaimWorkSpace (FtwLiteDevice);
924 if (EFI_ERROR (Status)) {
925 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status));
926 return EFI_ABORTED;
927 }
928 }
929
930 return EFI_SUCCESS;
931 }