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
) {
39 DEBUG ((EFI_D_ERROR
, "FtwLite: Work block header valid bit check error\n"));
43 // Check signature with gEfiSystemNvDataFvGuid
45 if (!CompareGuid (&gEfiSystemNvDataFvGuid
, &WorkingHeader
->Signature
)) {
46 DEBUG ((EFI_D_ERROR
, "FtwLite: Work block header signature check error\n"));
50 // Check the CRC of header
55 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
59 // Filter out the Crc and State fields
62 &WorkingBlockHeader
.Crc
,
66 WorkingBlockHeader
.WorkingBlockValid
= FTW_ERASE_POLARITY
;
67 WorkingBlockHeader
.WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
70 // Calculate the Crc of woking block header
72 Status
= gBS
->CalculateCrc32 (
73 (UINT8
*) &WorkingBlockHeader
,
74 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
75 &WorkingBlockHeader
.Crc
77 ASSERT_EFI_ERROR (Status
);
79 if (WorkingBlockHeader
.Crc
!= WorkingHeader
->Crc
) {
80 DEBUG ((EFI_D_ERROR
, "FtwLite: Work block header CRC check error\n"));
88 Initialize a work space when there is no work space.
91 @param WorkingHeader Pointer of working block header
93 @retval EFI_SUCCESS The function completed successfully
94 @retval EFI_ABORTED The function could not complete successfully.
99 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
104 ASSERT (WorkingHeader
!= NULL
);
107 // Here using gEfiSystemNvDataFvGuid as the signature.
110 &WorkingHeader
->Signature
,
111 &gEfiSystemNvDataFvGuid
,
114 WorkingHeader
->WriteQueueSize
= (UINT64
) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize
) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
117 // Crc is calculated with all the fields except Crc and STATE
119 WorkingHeader
->WorkingBlockValid
= FTW_ERASE_POLARITY
;
120 WorkingHeader
->WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
121 SetMem (&WorkingHeader
->Crc
, sizeof (UINT32
), FTW_ERASED_BYTE
);
124 // Calculate the CRC value
126 Status
= gBS
->CalculateCrc32 (
127 (UINT8
*) WorkingHeader
,
128 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
131 ASSERT_EFI_ERROR (Status
);
134 // Restore the WorkingBlockValid flag to VALID state
136 WorkingHeader
->WorkingBlockValid
= FTW_VALID_STATE
;
137 WorkingHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
143 Update a bit of state on a block device. The location of the bit is
144 calculated by the (Lba, Offset, bit). Here bit is determined by the
145 the name of a certain bit.
148 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock
149 @param Lba Lba of a block
150 @param Offset Offset on the Lba
151 @param NewBit New value that will override the old value if it can be change
153 @retval EFI_SUCCESS A state bit has been updated successfully
154 @retval Others Access block device error.
156 Assume all bits of State are inside the same BYTE.
157 @retval EFI_ABORTED Read block fail
162 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvBlock
,
173 // Read state from device, assume State is only one byte.
175 Length
= sizeof (UINT8
);
176 Status
= FvBlock
->Read (FvBlock
, Lba
, Offset
, &Length
, &State
);
177 if (EFI_ERROR (Status
)) {
181 State
^= FTW_POLARITY_REVERT
;
182 State
= (UINT8
) (State
| NewBit
);
183 State
^= FTW_POLARITY_REVERT
;
186 // Write state back to device
188 Length
= sizeof (UINT8
);
189 Status
= FvBlock
->Write (FvBlock
, Lba
, Offset
, &Length
, &State
);
195 Get the last Write record pointer.
196 The last record is the record whose 'complete' state hasn't been set.
197 After all, this header may be a EMPTY header entry for next Allocate.
200 @param FtwLiteDevice Private data of this driver
201 @param FtwLastRecord Pointer to retrieve the last write record
203 @retval EFI_SUCCESS Get the last write record successfully
204 @retval EFI_ABORTED The FTW work space is damaged
209 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
210 OUT EFI_FTW_LITE_RECORD
**FtwLastRecord
213 EFI_FTW_LITE_RECORD
*Record
;
215 *FtwLastRecord
= NULL
;
216 Record
= (EFI_FTW_LITE_RECORD
*) (FtwLiteDevice
->FtwWorkSpaceHeader
+ 1);
217 while (Record
->WriteCompleted
== FTW_VALID_STATE
) {
219 // If Offset exceed the FTW work space boudary, return error.
221 if ((UINTN
) ((UINT8
*) Record
- FtwLiteDevice
->FtwWorkSpace
) > FtwLiteDevice
->FtwWorkSpaceSize
) {
228 // Last write record is found
230 *FtwLastRecord
= Record
;
235 Read from working block to refresh the work space in memory.
238 @param FtwLiteDevice Point to private data of FTW driver
240 @retval EFI_SUCCESS The function completed successfully
241 @retval EFI_ABORTED The function could not complete successfully.
246 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
252 EFI_FTW_LITE_RECORD
*Record
;
255 // Initialize WorkSpace as FTW_ERASED_BYTE
258 FtwLiteDevice
->FtwWorkSpace
,
259 FtwLiteDevice
->FtwWorkSpaceSize
,
264 // Read from working block
266 Length
= FtwLiteDevice
->FtwWorkSpaceSize
;
267 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
268 FtwLiteDevice
->FtwFvBlock
,
269 FtwLiteDevice
->FtwWorkSpaceLba
,
270 FtwLiteDevice
->FtwWorkSpaceBase
,
272 FtwLiteDevice
->FtwWorkSpace
274 if (EFI_ERROR (Status
)) {
278 // Refresh the FtwLastRecord
280 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
282 Record
= FtwLiteDevice
->FtwLastRecord
;
283 Offset
= (UINTN
) (UINT8
*) Record
- (UINTN
) FtwLiteDevice
->FtwWorkSpace
;
286 // If work space has error or Record is out of the workspace limit, THEN
289 if (EFI_ERROR (Status
) || (Offset
+ FTW_LITE_RECORD_SIZE
>= FtwLiteDevice
->FtwWorkSpaceSize
)) {
291 // reclaim work space in working block.
293 Status
= FtwReclaimWorkSpace (FtwLiteDevice
, TRUE
);
294 if (EFI_ERROR (Status
)) {
295 DEBUG ((EFI_D_ERROR
, "FtwLite: Reclaim workspace - %r\n", Status
));
304 Reclaim the work space on the working block.
307 @param FtwLiteDevice Point to private data of FTW driver
308 @param PreserveRecord Whether get the last record or not
310 @retval EFI_SUCCESS The function completed successfully
311 @retval EFI_OUT_OF_RESOURCES Allocate memory error
312 @retval EFI_ABORTED The function could not complete successfully
316 FtwReclaimWorkSpace (
317 IN EFI_FTW_LITE_DEVICE
*FtwLiteDevice
,
318 IN BOOLEAN PreserveRecord
323 UINTN TempBufferSize
;
327 UINTN SpareBufferSize
;
329 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
330 EFI_FTW_LITE_RECORD
*Record
;
332 DEBUG ((EFI_D_ERROR
, "FtwLite: start to reclaim work space\n"));
335 // Read all original data from working block to a memory buffer
337 TempBufferSize
= FtwLiteDevice
->SpareAreaLength
;
338 TempBuffer
= AllocateZeroPool (TempBufferSize
);
339 if (TempBuffer
== NULL
) {
340 return EFI_OUT_OF_RESOURCES
;
344 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
345 Length
= FtwLiteDevice
->BlockSize
;
346 Status
= FtwLiteDevice
->FtwFvBlock
->Read (
347 FtwLiteDevice
->FtwFvBlock
,
348 FtwLiteDevice
->FtwWorkBlockLba
+ Index
,
353 if (EFI_ERROR (Status
)) {
354 FreePool (TempBuffer
);
361 // Clean up the workspace, remove all the completed records.
364 ((UINTN
) (FtwLiteDevice
->FtwWorkSpaceLba
- FtwLiteDevice
->FtwWorkBlockLba
)) *
365 FtwLiteDevice
->BlockSize
+ FtwLiteDevice
->FtwWorkSpaceBase
;
368 // Clear the content of buffer that will save the new work space data
370 SetMem (Ptr
, FtwLiteDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
373 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
377 FtwLiteDevice
->FtwWorkSpaceHeader
,
378 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
380 if (PreserveRecord
) {
382 // Get the last record
384 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
385 Record
= FtwLiteDevice
->FtwLastRecord
;
386 if (!EFI_ERROR (Status
) &&
388 Record
->WriteAllocated
== FTW_VALID_STATE
&&
389 Record
->WriteCompleted
!= FTW_VALID_STATE
) {
391 (UINT8
*) Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
399 FtwLiteDevice
->FtwWorkSpace
,
401 FtwLiteDevice
->FtwWorkSpaceSize
404 Status
= FtwGetLastRecord (FtwLiteDevice
, &FtwLiteDevice
->FtwLastRecord
);
407 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
409 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) Ptr
;
410 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
411 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
414 // Try to keep the content of spare block
415 // Save spare block into a spare backup memory buffer (Sparebuffer)
417 SpareBufferSize
= FtwLiteDevice
->SpareAreaLength
;
418 SpareBuffer
= AllocatePool (SpareBufferSize
);
419 if (SpareBuffer
== NULL
) {
420 FreePool (TempBuffer
);
421 return EFI_OUT_OF_RESOURCES
;
425 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
426 Length
= FtwLiteDevice
->BlockSize
;
427 Status
= FtwLiteDevice
->FtwBackupFvb
->Read (
428 FtwLiteDevice
->FtwBackupFvb
,
429 FtwLiteDevice
->FtwSpareLba
+ Index
,
434 if (EFI_ERROR (Status
)) {
435 FreePool (TempBuffer
);
436 FreePool (SpareBuffer
);
443 // Write the memory buffer to spare block
445 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
447 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
448 Length
= FtwLiteDevice
->BlockSize
;
449 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
450 FtwLiteDevice
->FtwBackupFvb
,
451 FtwLiteDevice
->FtwSpareLba
+ Index
,
456 if (EFI_ERROR (Status
)) {
457 FreePool (TempBuffer
);
458 FreePool (SpareBuffer
);
467 FreePool (TempBuffer
);
470 // Write the spare block to working block
472 Status
= FlushSpareBlockToWorkingBlock (FtwLiteDevice
);
473 if (EFI_ERROR (Status
)) {
474 FreePool (SpareBuffer
);
478 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
480 Status
= FtwEraseSpareBlock (FtwLiteDevice
);
482 for (Index
= 0; Index
< FtwLiteDevice
->NumberOfSpareBlock
; Index
+= 1) {
483 Length
= FtwLiteDevice
->BlockSize
;
484 Status
= FtwLiteDevice
->FtwBackupFvb
->Write (
485 FtwLiteDevice
->FtwBackupFvb
,
486 FtwLiteDevice
->FtwSpareLba
+ Index
,
491 if (EFI_ERROR (Status
)) {
492 FreePool (SpareBuffer
);
499 FreePool (SpareBuffer
);
501 DEBUG ((EFI_D_ERROR
, "FtwLite: reclaim work space success\n"));