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
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.
27 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
32 Check to see if it is a valid work space.
35 WorkingHeader - Pointer of working block header
38 EFI_SUCCESS - The function completed successfully
39 EFI_ABORTED - The function could not complete successfully.
44 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader
;
46 ASSERT (WorkingHeader
!= NULL
);
47 if (WorkingHeader
->WorkingBlockValid
!= FTW_VALID_STATE
) {
51 // Check signature with gEfiSystemNvDataFvGuid
53 if (!CompareGuid (&gEfiSystemNvDataFvGuid
, &WorkingHeader
->Signature
)) {
57 // Check the CRC of header
62 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
66 // Filter out the Crc and State fields
69 &WorkingBlockHeader
.Crc
,
73 WorkingBlockHeader
.WorkingBlockValid
= FTW_ERASE_POLARITY
;
74 WorkingBlockHeader
.WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
77 // Calculate the Crc of woking block header
79 Status
= gBS
->CalculateCrc32 (
80 (UINT8
*) &WorkingBlockHeader
,
81 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
82 &WorkingBlockHeader
.Crc
84 ASSERT_EFI_ERROR (Status
);
86 if (WorkingBlockHeader
.Crc
!= WorkingHeader
->Crc
) {
87 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Work block header CRC check error\n"));
96 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
101 Initialize a work space when there is no work space.
104 WorkingHeader - Pointer of working block header
107 EFI_SUCCESS - The function completed successfully
108 EFI_ABORTED - The function could not complete successfully.
114 ASSERT (WorkingHeader
!= NULL
);
117 // Here using gEfiSystemNvDataFvGuid as the signature.
120 &WorkingHeader
->Signature
,
121 &gEfiSystemNvDataFvGuid
,
124 WorkingHeader
->WriteQueueSize
= FTW_WORKING_QUEUE_SIZE
;
127 // Crc is calculated with all the fields except Crc and STATE
129 WorkingHeader
->WorkingBlockValid
= FTW_ERASE_POLARITY
;
130 WorkingHeader
->WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
131 SetMem (&WorkingHeader
->Crc
, sizeof (UINT32
), FTW_ERASED_BYTE
);
134 // Calculate the CRC value
136 Status
= gBS
->CalculateCrc32 (
137 (UINT8
*) WorkingHeader
,
138 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
141 ASSERT_EFI_ERROR (Status
);
144 // Restore the WorkingBlockValid flag to VALID state
146 WorkingHeader
->WorkingBlockValid
= FTW_VALID_STATE
;
147 WorkingHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
154 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
162 Update a bit of state on a block device. The location of the bit is
163 calculated by the (Lba, Offset, bit). Here bit is determined by the
164 the name of a certain bit.
167 FvBlock - FVB Protocol interface to access SrcBlock and DestBlock
169 Offset - Offset on the Lba
170 NewBit - New value that will override the old value if it can be change
173 EFI_SUCCESS - A state bit has been updated successfully
174 Others - Access block device error.
177 Assume all bits of State are inside the same BYTE.
179 EFI_ABORTED - Read block fail
187 // Read state from device, assume State is only one byte.
189 Length
= sizeof (UINT8
);
190 Status
= FvBlock
->Read (FvBlock
, Lba
, Offset
, &Length
, &State
);
191 if (EFI_ERROR (Status
)) {
195 State
^= FTW_POLARITY_REVERT
;
197 State
^= FTW_POLARITY_REVERT
;
200 // Write state back to device
202 Length
= sizeof (UINT8
);
203 Status
= FvBlock
->Write (FvBlock
, Lba
, Offset
, &Length
, &State
);
210 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
211 OUT EFI_FTW_LITE_RECORD
**FtwLastRecord
216 Get the last Write record pointer.
217 The last record is the record whose 'complete' state hasn't been set.
218 After all, this header may be a EMPTY header entry for next Allocate.
221 FtwLiteDevice - Private data of this driver
222 FtwLastRecord - Pointer to retrieve the last write record
225 EFI_SUCCESS - Get the last write record successfully
226 EFI_ABORTED - The FTW work space is damaged
230 EFI_FTW_LITE_RECORD
*Record
;
232 Record
= (EFI_FTW_LITE_RECORD
*) (FtwLiteDevice
->FtwWorkSpaceHeader
+ 1);
233 while (Record
->WriteCompleted
== FTW_VALID_STATE
) {
235 // If Offset exceed the FTW work space boudary, return error.
237 if ((UINTN
) ((UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
244 // Last write record is found
246 *FtwLastRecord
= Record
;
252 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
257 Read from working block to refresh the work space in memory.
260 FtwLiteDevice - Point to private data of FTW driver
263 EFI_SUCCESS - The function completed successfully
264 EFI_ABORTED - The function could not complete successfully.
271 EFI_FTW_LITE_RECORD
*Record
;
274 // Initialize WorkSpace as FTW_ERASED_BYTE
277 FtwLiteDevice
->FtwWorkSpace
,
278 FtwLiteDevice
->FtwWorkSpaceSize
,
283 // Read from working block
285 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
286 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
287 FtwLiteDevice
->FtwFvBlock
,
288 FtwLiteDevice
->FtwWorkSpaceLba
,
289 FtwLiteDevice
->FtwWorkSpaceBase
,
291 FtwLiteDevice
->FtwWorkSpace
293 if (EFI_ERROR (Status
)) {
297 // Refresh the FtwLastRecord
299 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
301 Record
= FtwLiteDevice
->FtwLastRecord
;
302 Offset
= (UINTN
) (UINT8
*) Record
- (UINTN
) FtwLiteDevice
->FtwWorkSpace
;
305 // IF work space has error or Record is out of the workspace limit, THEN
308 if (EFI_ERROR (Status
) || (Offset
+ WRITE_TOTAL_SIZE
>= FtwLiteDevice
->FtwWorkSpaceSize
)) {
310 // reclaim work space in working block.
312 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
313 if (EFI_ERROR (Status
)) {
314 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Reclaim workspace - %r\n", Status
));
324 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
325 IN OUT UINT8
*FtwSpaceBuffer
,
331 Reclaim the work space. Get rid of all the completed write records
332 and write records in the Fault Tolerant work space.
335 FtwLiteDevice - Point to private data of FTW driver
336 FtwSpaceBuffer - Buffer to contain the reclaimed clean data
337 BufferSize - Size of the FtwSpaceBuffer
340 EFI_SUCCESS - The function completed successfully
341 EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small
342 EFI_ABORTED - The function could not complete successfully.
347 EFI_FTW_LITE_RECORD
*Record
;
350 // To check if the buffer is large enough
352 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
353 if (BufferSize
< Length
) {
354 return EFI_BUFFER_TOO_SMALL
;
357 // Clear the content of buffer that will save the new work space data
359 SetMem (FtwSpaceBuffer
, Length
, FTW_ERASED_BYTE
);
362 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
366 FtwLiteDevice
->FtwWorkSpaceHeader
,
367 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
371 // Get the last record
373 Record
= FtwLiteDevice
->FtwLastRecord
;
374 if ((Record
!= NULL
) && (Record
->WriteAllocated
== FTW_VALID_STATE
) && (Record
->WriteCompleted
!= FTW_VALID_STATE
)) {
376 (UINT8
*) FtwSpaceBuffer
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
386 FtwReclaimWorkSpace (
387 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
392 Reclaim the work space on the working block.
395 FtwLiteDevice - Point to private data of FTW driver
398 EFI_SUCCESS - The function completed successfully
399 EFI_OUT_OF_RESOURCES - Allocate memory error
400 EFI_ABORTED - The function could not complete successfully
406 UINTN TempBufferSize
;
410 UINTN SpareBufferSize
;
412 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
414 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: start to reclaim work space\n"));
417 // Read all original data from working block to a memory buffer
419 TempBufferSize
= FtwLiteDevice
->SpareAreaLength
;
420 Status
= gBS
->AllocatePool (
423 (VOID
**) &TempBuffer
425 if (EFI_ERROR (Status
)) {
426 return EFI_OUT_OF_RESOURCES
;
429 ZeroMem (TempBuffer
, TempBufferSize
);
432 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
433 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
434 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
435 FtwLiteDevice
->FtwFvBlock
,
436 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
441 if (EFI_ERROR (Status
)) {
442 gBS
->FreePool (TempBuffer
);
449 // Clean up the workspace, remove all the completed records.
452 ((UINTN
) (FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
)) *
453 FtwLiteDevice
->SizeOfSpareBlock
+
454 FtwLiteDevice
->FtwWorkSpaceBase
;
455 Status
= CleanupWorkSpace (
458 FtwLiteDevice
->FtwWorkSpaceSize
462 FtwLiteDevice
->FtwWorkSpace
,
464 FtwLiteDevice
->FtwWorkSpaceSize
467 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
470 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
472 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) Ptr
;
473 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
474 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
477 // Try to keep the content of spare block
478 // Save spare block into a spare backup memory buffer (Sparebuffer)
480 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
481 SpareBuffer
= AllocatePool (SpareBufferSize
);
482 if (SpareBuffer
== NULL
) {
483 gBS
->FreePool (TempBuffer
);
484 return EFI_OUT_OF_RESOURCES
;
488 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
489 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
490 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
491 FtwLiteDevice
->FtwBackupFvb
,
492 FtwLiteDevice
->FtwSpareLba
+ Index
,
497 if (EFI_ERROR (Status
)) {
498 gBS
->FreePool (TempBuffer
);
499 gBS
->FreePool (SpareBuffer
);
506 // Write the memory buffer to spare block
508 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
510 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
511 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
512 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
513 FtwLiteDevice
->FtwBackupFvb
,
514 FtwLiteDevice
->FtwSpareLba
+ Index
,
519 if (EFI_ERROR (Status
)) {
520 gBS
->FreePool (TempBuffer
);
521 gBS
->FreePool (SpareBuffer
);
530 gBS
->FreePool (TempBuffer
);
533 // Write the spare block to working block
535 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
536 if (EFI_ERROR (Status
)) {
537 gBS
->FreePool (SpareBuffer
);
541 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
543 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
545 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
546 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
547 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
548 FtwLiteDevice
->FtwBackupFvb
,
549 FtwLiteDevice
->FtwSpareLba
+ Index
,
554 if (EFI_ERROR (Status
)) {
555 gBS
->FreePool (SpareBuffer
);
562 gBS
->FreePool (SpareBuffer
);
564 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: reclaim work space success\n"));