3 Internal functions to operate Working Block Space.
5 Copyright (c) 2006 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
26 Check to see if it is a valid work space.
29 WorkingHeader - Pointer of working block header
32 EFI_SUCCESS - The function completed successfully
33 EFI_ABORTED - The function could not complete successfully.
38 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader
;
40 ASSERT (WorkingHeader
!= NULL
);
41 if (WorkingHeader
->WorkingBlockValid
!= FTW_VALID_STATE
) {
45 // Check signature with gEfiSystemNvDataFvGuid
47 if (!CompareGuid (&gEfiSystemNvDataFvGuid
, &WorkingHeader
->Signature
)) {
51 // Check the CRC of header
56 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
60 // Filter out the Crc and State fields
63 &WorkingBlockHeader
.Crc
,
67 WorkingBlockHeader
.WorkingBlockValid
= FTW_ERASE_POLARITY
;
68 WorkingBlockHeader
.WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
71 // Calculate the Crc of woking block header
73 Status
= gBS
->CalculateCrc32 (
74 (UINT8
*) &WorkingBlockHeader
,
75 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
76 &WorkingBlockHeader
.Crc
78 ASSERT_EFI_ERROR (Status
);
80 if (WorkingBlockHeader
.Crc
!= WorkingHeader
->Crc
) {
81 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Work block header CRC check error\n"));
90 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
95 Initialize a work space when there is no work space.
98 WorkingHeader - Pointer of working block header
101 EFI_SUCCESS - The function completed successfully
102 EFI_ABORTED - The function could not complete successfully.
108 ASSERT (WorkingHeader
!= NULL
);
111 // Here using gEfiSystemNvDataFvGuid as the signature.
114 &WorkingHeader
->Signature
,
115 &gEfiSystemNvDataFvGuid
,
118 WorkingHeader
->WriteQueueSize
= FTW_WORKING_QUEUE_SIZE
;
121 // Crc is calculated with all the fields except Crc and STATE
123 WorkingHeader
->WorkingBlockValid
= FTW_ERASE_POLARITY
;
124 WorkingHeader
->WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
125 SetMem (&WorkingHeader
->Crc
, sizeof (UINT32
), FTW_ERASED_BYTE
);
128 // Calculate the CRC value
130 Status
= gBS
->CalculateCrc32 (
131 (UINT8
*) WorkingHeader
,
132 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
135 ASSERT_EFI_ERROR (Status
);
138 // Restore the WorkingBlockValid flag to VALID state
140 WorkingHeader
->WorkingBlockValid
= FTW_VALID_STATE
;
141 WorkingHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
148 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
156 Update a bit of state on a block device. The location of the bit is
157 calculated by the (Lba, Offset, bit). Here bit is determined by the
158 the name of a certain bit.
161 FvBlock - FVB Protocol interface to access SrcBlock and DestBlock
163 Offset - Offset on the Lba
164 NewBit - New value that will override the old value if it can be change
167 EFI_SUCCESS - A state bit has been updated successfully
168 Others - Access block device error.
171 Assume all bits of State are inside the same BYTE.
173 EFI_ABORTED - Read block fail
181 // Read state from device, assume State is only one byte.
183 Length
= sizeof (UINT8
);
184 Status
= FvBlock
->Read (FvBlock
, Lba
, Offset
, &Length
, &State
);
185 if (EFI_ERROR (Status
)) {
189 State
^= FTW_POLARITY_REVERT
;
190 State
= (UINT8
) (State
| NewBit
);
191 State
^= FTW_POLARITY_REVERT
;
194 // Write state back to device
196 Length
= sizeof (UINT8
);
197 Status
= FvBlock
->Write (FvBlock
, Lba
, Offset
, &Length
, &State
);
204 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
205 OUT EFI_FTW_LITE_RECORD
**FtwLastRecord
210 Get the last Write record pointer.
211 The last record is the record whose 'complete' state hasn't been set.
212 After all, this header may be a EMPTY header entry for next Allocate.
215 FtwLiteDevice - Private data of this driver
216 FtwLastRecord - Pointer to retrieve the last write record
219 EFI_SUCCESS - Get the last write record successfully
220 EFI_ABORTED - The FTW work space is damaged
224 EFI_FTW_LITE_RECORD
*Record
;
226 Record
= (EFI_FTW_LITE_RECORD
*) (FtwLiteDevice
->FtwWorkSpaceHeader
+ 1);
227 while (Record
->WriteCompleted
== FTW_VALID_STATE
) {
229 // If Offset exceed the FTW work space boudary, return error.
231 if ((UINTN
) ((UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
238 // Last write record is found
240 *FtwLastRecord
= Record
;
246 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
251 Read from working block to refresh the work space in memory.
254 FtwLiteDevice - Point to private data of FTW driver
257 EFI_SUCCESS - The function completed successfully
258 EFI_ABORTED - The function could not complete successfully.
265 EFI_FTW_LITE_RECORD
*Record
;
268 // Initialize WorkSpace as FTW_ERASED_BYTE
271 FtwLiteDevice
->FtwWorkSpace
,
272 FtwLiteDevice
->FtwWorkSpaceSize
,
277 // Read from working block
279 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
280 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
281 FtwLiteDevice
->FtwFvBlock
,
282 FtwLiteDevice
->FtwWorkSpaceLba
,
283 FtwLiteDevice
->FtwWorkSpaceBase
,
285 FtwLiteDevice
->FtwWorkSpace
287 if (EFI_ERROR (Status
)) {
291 // Refresh the FtwLastRecord
293 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
295 Record
= FtwLiteDevice
->FtwLastRecord
;
296 Offset
= (UINTN
) (UINT8
*) Record
- (UINTN
) FtwLiteDevice
->FtwWorkSpace
;
299 // IF work space has error or Record is out of the workspace limit, THEN
302 if (EFI_ERROR (Status
) || (Offset
+ WRITE_TOTAL_SIZE
>= FtwLiteDevice
->FtwWorkSpaceSize
)) {
304 // reclaim work space in working block.
306 Status
= FtwReclaimWorkSpace (FtwLiteDevice
);
307 if (EFI_ERROR (Status
)) {
308 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Reclaim workspace - %r\n", Status
));
318 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
319 IN OUT UINT8
*FtwSpaceBuffer
,
325 Reclaim the work space. Get rid of all the completed write records
326 and write records in the Fault Tolerant work space.
329 FtwLiteDevice - Point to private data of FTW driver
330 FtwSpaceBuffer - Buffer to contain the reclaimed clean data
331 BufferSize - Size of the FtwSpaceBuffer
334 EFI_SUCCESS - The function completed successfully
335 EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small
336 EFI_ABORTED - The function could not complete successfully.
341 EFI_FTW_LITE_RECORD
*Record
;
344 // To check if the buffer is large enough
346 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
347 if (BufferSize
< Length
) {
348 return EFI_BUFFER_TOO_SMALL
;
351 // Clear the content of buffer that will save the new work space data
353 SetMem (FtwSpaceBuffer
, Length
, FTW_ERASED_BYTE
);
356 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
360 FtwLiteDevice
->FtwWorkSpaceHeader
,
361 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
365 // Get the last record
367 Record
= FtwLiteDevice
->FtwLastRecord
;
368 if ((Record
!= NULL
) && (Record
->WriteAllocated
== FTW_VALID_STATE
) && (Record
->WriteCompleted
!= FTW_VALID_STATE
)) {
370 (UINT8
*) FtwSpaceBuffer
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
380 FtwReclaimWorkSpace (
381 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
386 Reclaim the work space on the working block.
389 FtwLiteDevice - Point to private data of FTW driver
392 EFI_SUCCESS - The function completed successfully
393 EFI_OUT_OF_RESOURCES - Allocate memory error
394 EFI_ABORTED - The function could not complete successfully
400 UINTN TempBufferSize
;
404 UINTN SpareBufferSize
;
406 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
408 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: start to reclaim work space\n"));
411 // Read all original data from working block to a memory buffer
413 TempBufferSize
= FtwLiteDevice
->SpareAreaLength
;
414 TempBuffer
= AllocateZeroPool (TempBufferSize
);
415 if (TempBuffer
!= NULL
) {
416 return EFI_OUT_OF_RESOURCES
;
420 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
421 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
422 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
423 FtwLiteDevice
->FtwFvBlock
,
424 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
429 if (EFI_ERROR (Status
)) {
430 FreePool (TempBuffer
);
437 // Clean up the workspace, remove all the completed records.
440 ((UINTN
) (FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
)) *
441 FtwLiteDevice
->SizeOfSpareBlock
+ FtwLiteDevice
->FtwWorkSpaceBase
;
443 Status
= CleanupWorkSpace (
446 FtwLiteDevice
->FtwWorkSpaceSize
450 FtwLiteDevice
->FtwWorkSpace
,
452 FtwLiteDevice
->FtwWorkSpaceSize
455 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
458 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
460 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) Ptr
;
461 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
462 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
465 // Try to keep the content of spare block
466 // Save spare block into a spare backup memory buffer (Sparebuffer)
468 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
469 SpareBuffer
= AllocatePool (SpareBufferSize
);
470 if (SpareBuffer
== NULL
) {
471 FreePool (TempBuffer
);
472 return EFI_OUT_OF_RESOURCES
;
476 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
477 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
478 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
479 FtwLiteDevice
->FtwBackupFvb
,
480 FtwLiteDevice
->FtwSpareLba
+ Index
,
485 if (EFI_ERROR (Status
)) {
486 FreePool (TempBuffer
);
487 FreePool (SpareBuffer
);
494 // Write the memory buffer to spare block
496 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
498 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
499 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
500 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
501 FtwLiteDevice
->FtwBackupFvb
,
502 FtwLiteDevice
->FtwSpareLba
+ Index
,
507 if (EFI_ERROR (Status
)) {
508 FreePool (TempBuffer
);
509 FreePool (SpareBuffer
);
518 FreePool (TempBuffer
);
521 // Write the spare block to working block
523 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
524 if (EFI_ERROR (Status
)) {
525 FreePool (SpareBuffer
);
529 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
531 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
533 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
534 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
535 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
536 FtwLiteDevice
->FtwBackupFvb
,
537 FtwLiteDevice
->FtwSpareLba
+ Index
,
542 if (EFI_ERROR (Status
)) {
543 FreePool (SpareBuffer
);
550 FreePool (SpareBuffer
);
552 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: reclaim work space success\n"));