]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.c
0d20e88058d24f4dc4e8fa6cfb1e9fea071e7d90
[mirror_edk2.git] / EdkModulePkg / Universal / FirmwareVolume / FaultTolerantWriteLite / Dxe / FtwLite.c
1 /*++
2
3 Copyright (c) 2006, 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 gBS->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 gBS->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 gBS->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 gBS->FreePool (MyBuffer);
295 gBS->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 gBS->FreePool (MyBuffer);
318 gBS->FreePool (SpareBuffer);
319 return EFI_ABORTED;
320 }
321
322 Ptr += MyLength;
323 }
324 //
325 // Free MyBuffer
326 //
327 gBS->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 gBS->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 gBS->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 gBS->FreePool (SpareBuffer);
375 return EFI_ABORTED;
376 }
377
378 Ptr += MyLength;
379 }
380 //
381 // All success.
382 //
383 gBS->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_FLASH_MAP_ENTRY_DATA *FlashMapEntry;
636 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
637 UINT32 LbaIndex;
638 EFI_PEI_HOB_POINTERS GuidHob;
639
640 //
641 // Allocate Private data of this driver,
642 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
643 //
644 FtwLiteDevice = NULL;
645 FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);
646 if (FtwLiteDevice != NULL) {
647 Status = EFI_SUCCESS;
648 } else {
649 Status = EFI_OUT_OF_RESOURCES;
650 }
651
652 ASSERT_EFI_ERROR (Status);
653
654 ZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE));
655 FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE;
656
657 //
658 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
659 //
660 FtwLiteDevice->FtwWorkSpace = (UINT8 *) (FtwLiteDevice + 1);
661 FtwLiteDevice->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE;
662 SetMem (
663 FtwLiteDevice->FtwWorkSpace,
664 FtwLiteDevice->FtwWorkSpaceSize,
665 FTW_ERASED_BYTE
666 );
667 FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace;
668
669 FtwLiteDevice->FtwLastRecord = NULL;
670
671 FtwLiteDevice->SpareAreaLength = 0;
672 FtwLiteDevice->WorkSpaceLength = 0;
673
674 GuidHob.Raw = GetHobList ();
675 while (NULL != (GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw))) {
676 FlashMapEntry = (EFI_FLASH_MAP_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid);
677 //
678 // Get the FTW work space Flash Map SUB area
679 //
680 if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_STATE) && (FlashMapEntry->NumEntries == 1)) {
681 FtwLiteDevice->WorkSpaceAddress = FlashMapEntry->Entries[0].Base;
682 FtwLiteDevice->WorkSpaceLength = (UINTN) FlashMapEntry->Entries[0].Length;
683 }
684 //
685 // Get the FTW backup SUB area
686 //
687 if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_BACKUP) && (FlashMapEntry->NumEntries == 1)) {
688 FtwLiteDevice->SpareAreaAddress = FlashMapEntry->Entries[0].Base;
689 FtwLiteDevice->SpareAreaLength = (UINTN) FlashMapEntry->Entries[0].Length;
690 }
691
692 GuidHob.Raw = GET_NEXT_HOB (GuidHob);
693 }
694
695 ASSERT ((FtwLiteDevice->WorkSpaceLength != 0) && (FtwLiteDevice->SpareAreaLength != 0));
696
697 //
698 // Locate FVB protocol
699 //
700 Status = gBS->LocateHandleBuffer (
701 ByProtocol,
702 &gEfiFirmwareVolumeBlockProtocolGuid,
703 NULL,
704 &HandleCount,
705 &HandleBuffer
706 );
707 ASSERT_EFI_ERROR (Status);
708
709 ASSERT (HandleCount > 0);
710
711 FtwLiteDevice->FtwFvBlock = NULL;
712 FtwLiteDevice->FtwBackupFvb = NULL;
713 FtwLiteDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
714 FtwLiteDevice->FtwSpareLba = (EFI_LBA) (-1);
715 for (Index = 0; Index < HandleCount; Index += 1) {
716 Status = gBS->HandleProtocol (
717 HandleBuffer[Index],
718 &gEfiFirmwareVolumeBlockProtocolGuid,
719 (VOID **) &Fvb
720 );
721 ASSERT_EFI_ERROR (Status);
722
723 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
724 if (EFI_ERROR (Status)) {
725 continue;
726 }
727
728 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);
729
730 if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) &&
731 (FtwLiteDevice->WorkSpaceAddress <= (BaseAddress + FwVolHeader->FvLength))
732 ) {
733 FtwLiteDevice->FtwFvBlock = Fvb;
734 //
735 // To get the LBA of work space
736 //
737 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
738 //
739 // FV may have multiple types of BlockLength
740 //
741 FvbMapEntry = &FwVolHeader->FvBlockMap[0];
742 while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) {
743 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
744 if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) {
745 FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;
746 //
747 // Get the Work space size and Base(Offset)
748 //
749 FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength;
750 FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->BlockLength * (LbaIndex - 1)));
751 break;
752 }
753 }
754 //
755 // end for
756 //
757 FvbMapEntry++;
758 }
759 //
760 // end while
761 //
762 }
763 }
764
765 if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&
766 (FtwLiteDevice->SpareAreaAddress <= (BaseAddress + FwVolHeader->FvLength))
767 ) {
768 FtwLiteDevice->FtwBackupFvb = Fvb;
769 //
770 // To get the LBA of spare
771 //
772 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
773 //
774 // FV may have multiple types of BlockLength
775 //
776 FvbMapEntry = &FwVolHeader->FvBlockMap[0];
777 while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) {
778 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
779 if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) {
780 //
781 // Get the NumberOfSpareBlock and SizeOfSpareBlock
782 //
783 FtwLiteDevice->FtwSpareLba = LbaIndex - 1;
784 FtwLiteDevice->SizeOfSpareBlock = FvbMapEntry->BlockLength;
785 FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->SizeOfSpareBlock;
786 //
787 // Check the range of spare area to make sure that it's in FV range
788 //
789 ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks);
790 break;
791 }
792 }
793
794 FvbMapEntry++;
795 }
796 //
797 // end while
798 //
799 }
800 }
801 }
802 //
803 // Calculate the start LBA of working block. Working block is an area which
804 // contains working space in its last block and has the same size as spare
805 // block, unless there are not enough blocks before the block that contains
806 // working space.
807 //
808 FtwLiteDevice->FtwWorkBlockLba = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->NumberOfSpareBlock + 1;
809 if ((INT64) (FtwLiteDevice->FtwWorkBlockLba) < 0) {
810 FtwLiteDevice->FtwWorkBlockLba = 0;
811 }
812
813 if ((FtwLiteDevice->FtwFvBlock == NULL) ||
814 (FtwLiteDevice->FtwBackupFvb == NULL) ||
815 (FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||
816 (FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))
817 ) {
818 DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));
819 ASSERT_EFI_ERROR (Status);
820 }
821 //
822 // Refresh workspace data from working block
823 //
824 Status = WorkSpaceRefresh (FtwLiteDevice);
825 ASSERT_EFI_ERROR (Status);
826
827 //
828 // If the working block workspace is not valid, try the spare block
829 //
830 if (!IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
831 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace invalid, read from backup\n"));
832 //
833 // Read from spare block
834 //
835 Length = FtwLiteDevice->FtwWorkSpaceSize;
836 Status = FtwLiteDevice->FtwBackupFvb->Read (
837 FtwLiteDevice->FtwBackupFvb,
838 FtwLiteDevice->FtwSpareLba,
839 FtwLiteDevice->FtwWorkSpaceBase,
840 &Length,
841 FtwLiteDevice->FtwWorkSpace
842 );
843 ASSERT_EFI_ERROR (Status);
844
845 //
846 // If spare block is valid, then replace working block content.
847 //
848 if (IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
849 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
850 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart working block in Init() - %r\n", Status));
851 ASSERT_EFI_ERROR (Status);
852
853 FtwAbort (FtwLiteDevice);
854 //
855 // Refresh work space.
856 //
857 Status = WorkSpaceRefresh (FtwLiteDevice);
858 if (EFI_ERROR (Status)) {
859 return EFI_ABORTED;
860 }
861 } else {
862 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Both are invalid, init workspace\n"));
863 //
864 // If both are invalid, then initialize work space.
865 //
866 SetMem (
867 FtwLiteDevice->FtwWorkSpace,
868 FtwLiteDevice->FtwWorkSpaceSize,
869 FTW_ERASED_BYTE
870 );
871 InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);
872 //
873 // Write to work space on the working block
874 //
875 Length = FtwLiteDevice->FtwWorkSpaceSize;
876 Status = FtwLiteDevice->FtwFvBlock->Write (
877 FtwLiteDevice->FtwFvBlock,
878 FtwLiteDevice->FtwWorkSpaceLba,
879 FtwLiteDevice->FtwWorkSpaceBase,
880 &Length,
881 FtwLiteDevice->FtwWorkSpace
882 );
883 if (EFI_ERROR (Status)) {
884 return EFI_ABORTED;
885 }
886 }
887 }
888 //
889 // Hook the protocol API
890 //
891 FtwLiteDevice->FtwLiteInstance.Write = FtwLiteWrite;
892
893 //
894 // Install protocol interface
895 //
896 Status = gBS->InstallProtocolInterface (
897 &FtwLiteDevice->Handle,
898 &gEfiFaultTolerantWriteLiteProtocolGuid,
899 EFI_NATIVE_INTERFACE,
900 &FtwLiteDevice->FtwLiteInstance
901 );
902 if (EFI_ERROR (Status)) {
903 return EFI_ABORTED;
904 }
905 //
906 // If (!SpareCompleted) THEN Abort to rollback.
907 //
908 if ((FtwLiteDevice->FtwLastRecord->WriteAllocated == FTW_VALID_STATE) &&
909 (FtwLiteDevice->FtwLastRecord->SpareCompleted != FTW_VALID_STATE)
910 ) {
911 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
912 FtwAbort (FtwLiteDevice);
913 }
914 //
915 // if (SpareCompleted) THEN Restart to fault tolerant write.
916 //
917 if ((FtwLiteDevice->FtwLastRecord->SpareCompleted == FTW_VALID_STATE) &&
918 (FtwLiteDevice->FtwLastRecord->WriteCompleted != FTW_VALID_STATE)
919 ) {
920
921 Status = FtwRestart (FtwLiteDevice);
922 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart last write - %r\n", Status));
923 if (EFI_ERROR (Status)) {
924 return Status;
925 }
926 }
927 //
928 // To check the workspace buffer behind last records is EMPTY or not.
929 // If it's not EMPTY, FTW_LITE also need to call reclaim().
930 //
931 Record = FtwLiteDevice->FtwLastRecord;
932 Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
933 if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
934 Offset += WRITE_TOTAL_SIZE;
935 }
936
937 if (!IsErasedFlashBuffer (
938 FTW_ERASE_POLARITY,
939 FtwLiteDevice->FtwWorkSpace + Offset,
940 FtwLiteDevice->FtwWorkSpaceSize - Offset
941 )) {
942 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n"));
943 Status = FtwReclaimWorkSpace (FtwLiteDevice);
944 if (EFI_ERROR (Status)) {
945 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status));
946 return EFI_ABORTED;
947 }
948 }
949
950 return EFI_SUCCESS;
951 }