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.
20 Check to see if it is a valid work space.
23 @param WorkingHeader Pointer of working block header
25 @retval EFI_SUCCESS The function completed successfully
26 @retval EFI_ABORTED The function could not complete successfully.
31 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
35 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader
;
37 ASSERT (WorkingHeader
!= NULL
);
38 if (WorkingHeader
->WorkingBlockValid
!= FTW_VALID_STATE
) {
42 // Check signature with gEfiSystemNvDataFvGuid
44 if (!CompareGuid (&gEfiSystemNvDataFvGuid
, &WorkingHeader
->Signature
)) {
48 // Check the CRC of header
53 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
57 // Filter out the Crc and State fields
60 &WorkingBlockHeader
.Crc
,
64 WorkingBlockHeader
.WorkingBlockValid
= FTW_ERASE_POLARITY
;
65 WorkingBlockHeader
.WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
68 // Calculate the Crc of woking block header
70 Status
= gBS
->CalculateCrc32 (
71 (UINT8
*) &WorkingBlockHeader
,
72 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
73 &WorkingBlockHeader
.Crc
75 ASSERT_EFI_ERROR (Status
);
77 if (WorkingBlockHeader
.Crc
!= WorkingHeader
->Crc
) {
78 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Work block header CRC check error\n"));
86 Initialize a work space when there is no work space.
89 @param WorkingHeader Pointer of working block header
91 @retval EFI_SUCCESS The function completed successfully
92 @retval EFI_ABORTED The function could not complete successfully.
97 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
102 ASSERT (WorkingHeader
!= NULL
);
105 // Here using gEfiSystemNvDataFvGuid as the signature.
108 &WorkingHeader
->Signature
,
109 &gEfiSystemNvDataFvGuid
,
112 WorkingHeader
->WriteQueueSize
= FTW_WORKING_QUEUE_SIZE
;
115 // Crc is calculated with all the fields except Crc and STATE
117 WorkingHeader
->WorkingBlockValid
= FTW_ERASE_POLARITY
;
118 WorkingHeader
->WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
119 SetMem (&WorkingHeader
->Crc
, sizeof (UINT32
), FTW_ERASED_BYTE
);
122 // Calculate the CRC value
124 Status
= gBS
->CalculateCrc32 (
125 (UINT8
*) WorkingHeader
,
126 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
129 ASSERT_EFI_ERROR (Status
);
132 // Restore the WorkingBlockValid flag to VALID state
134 WorkingHeader
->WorkingBlockValid
= FTW_VALID_STATE
;
135 WorkingHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
141 Update a bit of state on a block device. The location of the bit is
142 calculated by the (Lba, Offset, bit). Here bit is determined by the
143 the name of a certain bit.
146 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
147 @param Lba Lba of a block
148 @param Offset Offset on the Lba
149 @param NewBit New value that will override the old value if it can be change
151 @retval EFI_SUCCESS A state bit has been updated successfully
152 @retval Others Access block device error.
154 Assume all bits of State are inside the same BYTE.
155 @retval EFI_ABORTED Read block fail
160 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
171 // Read state from device, assume State is only one byte.
173 Length
= sizeof (UINT8
);
174 Status
= FvBlock
->Read (FvBlock
, Lba
, Offset
, &Length
, &State
);
175 if (EFI_ERROR (Status
)) {
179 State
^= FTW_POLARITY_REVERT
;
180 State
= (UINT8
) (State
| NewBit
);
181 State
^= FTW_POLARITY_REVERT
;
184 // Write state back to device
186 Length
= sizeof (UINT8
);
187 Status
= FvBlock
->Write (FvBlock
, Lba
, Offset
, &Length
, &State
);
193 Get the last Write record pointer.
194 The last record is the record whose 'complete' state hasn't been set.
195 After all, this header may be a EMPTY header entry for next Allocate.
198 @param FtwLiteDevice Private data of this driver
199 @param FtwLastRecord Pointer to retrieve the last write record
201 @retval EFI_SUCCESS Get the last write record successfully
202 @retval EFI_ABORTED The FTW work space is damaged
207 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
208 OUT EFI_FTW_LITE_RECORD
**FtwLastRecord
211 EFI_FTW_LITE_RECORD
*Record
;
213 *FtwLastRecord
= NULL
;
214 Record
= (EFI_FTW_LITE_RECORD
*) (FtwLiteDevice
->FtwWorkSpaceHeader
+ 1);
215 while (Record
->WriteCompleted
== FTW_VALID_STATE
) {
217 // If Offset exceed the FTW work space boudary, return error.
219 if ((UINTN
) ((UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
226 // Last write record is found
228 *FtwLastRecord
= Record
;
233 Read from working block to refresh the work space in memory.
236 @param FtwLiteDevice Point to private data of FTW driver
238 @retval EFI_SUCCESS The function completed successfully
239 @retval EFI_ABORTED The function could not complete successfully.
244 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
250 EFI_FTW_LITE_RECORD
*Record
;
253 // Initialize WorkSpace as FTW_ERASED_BYTE
256 FtwLiteDevice
->FtwWorkSpace
,
257 FtwLiteDevice
->FtwWorkSpaceSize
,
262 // Read from working block
264 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
265 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
266 FtwLiteDevice
->FtwFvBlock
,
267 FtwLiteDevice
->FtwWorkSpaceLba
,
268 FtwLiteDevice
->FtwWorkSpaceBase
,
270 FtwLiteDevice
->FtwWorkSpace
272 if (EFI_ERROR (Status
)) {
276 // Refresh the FtwLastRecord
278 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
280 Record
= FtwLiteDevice
->FtwLastRecord
;
281 Offset
= (UINTN
) (UINT8
*) Record
- (UINTN
) FtwLiteDevice
->FtwWorkSpace
;
284 // If work space has error or Record is out of the workspace limit, THEN
287 if (EFI_ERROR (Status
) || (Offset
+ WRITE_TOTAL_SIZE
>= FtwLiteDevice
->FtwWorkSpaceSize
)) {
289 // reclaim work space in working block.
291 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
292 if (EFI_ERROR (Status
)) {
293 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: Reclaim workspace - %r\n", Status
));
302 Reclaim the work space on the working block.
305 @param FtwLiteDevice Point to private data of FTW driver
306 @param PreserveRecord Whether get the last record or not
308 @retval EFI_SUCCESS The function completed successfully
309 @retval EFI_OUT_OF_RESOURCES Allocate memory error
310 @retval EFI_ABORTED The function could not complete successfully
314 FtwReclaimWorkSpace (
315 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
316 IN BOOLEAN PreserveRecord
321 UINTN TempBufferSize
;
325 UINTN SpareBufferSize
;
327 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
328 EFI_FTW_LITE_RECORD
*Record
;
330 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: start to reclaim work space\n"));
333 // Read all original data from working block to a memory buffer
335 TempBufferSize
= FtwLiteDevice
->SpareAreaLength
;
336 TempBuffer
= AllocateZeroPool (TempBufferSize
);
337 if (TempBuffer
== NULL
) {
338 return EFI_OUT_OF_RESOURCES
;
342 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
343 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
344 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
345 FtwLiteDevice
->FtwFvBlock
,
346 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
351 if (EFI_ERROR (Status
)) {
352 FreePool (TempBuffer
);
359 // Clean up the workspace, remove all the completed records.
362 ((UINTN
) (FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
)) *
363 FtwLiteDevice
->SizeOfSpareBlock
+ FtwLiteDevice
->FtwWorkSpaceBase
;
366 // Clear the content of buffer that will save the new work space data
368 SetMem (Ptr
, FtwLiteDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
371 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
375 FtwLiteDevice
->FtwWorkSpaceHeader
,
376 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
378 if (PreserveRecord
) {
380 // Get the last record
382 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
383 Record
= FtwLiteDevice
->FtwLastRecord
;
384 if (!EFI_ERROR (Status
) &&
386 Record
->WriteAllocated
== FTW_VALID_STATE
&&
387 Record
->WriteCompleted
!= FTW_VALID_STATE
) {
389 (UINT8
*) Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
397 FtwLiteDevice
->FtwWorkSpace
,
399 FtwLiteDevice
->FtwWorkSpaceSize
402 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
405 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
407 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) Ptr
;
408 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
409 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
412 // Try to keep the content of spare block
413 // Save spare block into a spare backup memory buffer (Sparebuffer)
415 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
416 SpareBuffer
= AllocatePool (SpareBufferSize
);
417 if (SpareBuffer
== NULL
) {
418 FreePool (TempBuffer
);
419 return EFI_OUT_OF_RESOURCES
;
423 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
424 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
425 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
426 FtwLiteDevice
->FtwBackupFvb
,
427 FtwLiteDevice
->FtwSpareLba
+ Index
,
432 if (EFI_ERROR (Status
)) {
433 FreePool (TempBuffer
);
434 FreePool (SpareBuffer
);
441 // Write the memory buffer to spare block
443 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
445 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
446 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
447 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
448 FtwLiteDevice
->FtwBackupFvb
,
449 FtwLiteDevice
->FtwSpareLba
+ Index
,
454 if (EFI_ERROR (Status
)) {
455 FreePool (TempBuffer
);
456 FreePool (SpareBuffer
);
465 FreePool (TempBuffer
);
468 // Write the spare block to working block
470 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
471 if (EFI_ERROR (Status
)) {
472 FreePool (SpareBuffer
);
476 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
478 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
480 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
481 Length
= FtwLiteDevice
->SizeOfSpareBlock
;
482 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
483 FtwLiteDevice
->FtwBackupFvb
,
484 FtwLiteDevice
->FtwSpareLba
+ Index
,
489 if (EFI_ERROR (Status
)) {
490 FreePool (SpareBuffer
);
497 FreePool (SpareBuffer
);
499 DEBUG ((EFI_D_FTW_LITE
, "FtwLite: reclaim work space success\n"));