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.
17 #include "FaultTolerantWrite.h"
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 if (WorkingHeader
== NULL
) {
41 if (WorkingHeader
->WorkingBlockValid
!= FTW_VALID_STATE
) {
42 DEBUG ((EFI_D_ERROR
, "Ftw: Work block header valid bit check error\n"));
46 // Check signature with gEfiSystemNvDataFvGuid
48 if (!CompareGuid (&gEfiSystemNvDataFvGuid
, &WorkingHeader
->Signature
)) {
49 DEBUG ((EFI_D_ERROR
, "Ftw: Work block header signature check error\n"));
53 // Check the CRC of header
58 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
62 // Filter out the Crc and State fields
65 &WorkingBlockHeader
.Crc
,
69 WorkingBlockHeader
.WorkingBlockValid
= FTW_ERASE_POLARITY
;
70 WorkingBlockHeader
.WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
73 // Calculate the Crc of woking block header
75 Status
= gBS
->CalculateCrc32 (
76 (UINT8
*) &WorkingBlockHeader
,
77 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
78 &WorkingBlockHeader
.Crc
80 if (EFI_ERROR (Status
)) {
84 if (WorkingBlockHeader
.Crc
!= WorkingHeader
->Crc
) {
85 DEBUG ((EFI_D_ERROR
, "Ftw: Work block header CRC check error\n"));
93 Initialize a work space when there is no work space.
95 @param WorkingHeader Pointer of working block header
97 @retval EFI_SUCCESS The function completed successfully
98 @retval EFI_ABORTED The function could not complete successfully.
102 InitWorkSpaceHeader (
103 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
108 if (WorkingHeader
== NULL
) {
109 return EFI_INVALID_PARAMETER
;
112 // Here using gEfiSystemNvDataFvGuid as the signature.
115 &WorkingHeader
->Signature
,
116 &gEfiSystemNvDataFvGuid
,
119 WorkingHeader
->WriteQueueSize
= (UINT64
) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize
) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
122 // Crc is calculated with all the fields except Crc and STATE
124 WorkingHeader
->WorkingBlockValid
= FTW_ERASE_POLARITY
;
125 WorkingHeader
->WorkingBlockInvalid
= FTW_ERASE_POLARITY
;
134 // Calculate the CRC value
136 Status
= gBS
->CalculateCrc32 (
137 (UINT8
*) WorkingHeader
,
138 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
141 if (EFI_ERROR (Status
)) {
145 // Restore the WorkingBlockValid flag to VALID state
147 WorkingHeader
->WorkingBlockValid
= FTW_VALID_STATE
;
148 WorkingHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
154 Read from working block to refresh the work space in memory.
156 @param FtwDevice Point to private data of FTW driver
158 @retval EFI_SUCCESS The function completed successfully
159 @retval EFI_ABORTED The function could not complete successfully.
164 IN EFI_FTW_DEVICE
*FtwDevice
170 EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwHeader
;
173 // Initialize WorkSpace as FTW_ERASED_BYTE
176 FtwDevice
->FtwWorkSpace
,
177 FtwDevice
->FtwWorkSpaceSize
,
182 // Read from working block
184 Length
= FtwDevice
->FtwWorkSpaceSize
;
185 Status
= FtwDevice
->FtwFvBlock
->Read (
186 FtwDevice
->FtwFvBlock
,
187 FtwDevice
->FtwWorkSpaceLba
,
188 FtwDevice
->FtwWorkSpaceBase
,
190 FtwDevice
->FtwWorkSpace
192 if (EFI_ERROR (Status
)) {
196 // Refresh the FtwLastWriteHeader
198 Status
= FtwGetLastWriteHeader (
199 FtwDevice
->FtwWorkSpaceHeader
,
200 FtwDevice
->FtwWorkSpaceSize
,
201 &FtwDevice
->FtwLastWriteHeader
204 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
205 Offset
= (UINTN
) (UINT8
*) FtwHeader
- (UINTN
) FtwDevice
->FtwWorkSpace
;
208 // if the Header is out of the workspace limit, call reclaim.
210 if (EFI_ERROR (Status
) && (Offset
>= FtwDevice
->FtwWorkSpaceSize
)) {
212 // reclaim work space in working block.
214 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
215 if (EFI_ERROR (Status
)) {
216 DEBUG ((EFI_D_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
220 // Read from working block again
222 Length
= FtwDevice
->FtwWorkSpaceSize
;
223 Status
= FtwDevice
->FtwFvBlock
->Read (
224 FtwDevice
->FtwFvBlock
,
225 FtwDevice
->FtwWorkSpaceLba
,
226 FtwDevice
->FtwWorkSpaceBase
,
228 FtwDevice
->FtwWorkSpace
230 if (EFI_ERROR (Status
)) {
234 Status
= FtwGetLastWriteHeader (
235 FtwDevice
->FtwWorkSpaceHeader
,
236 FtwDevice
->FtwWorkSpaceSize
,
237 &FtwDevice
->FtwLastWriteHeader
241 // Refresh the FtwLastWriteRecord
243 Status
= FtwGetLastWriteRecord (
244 FtwDevice
->FtwLastWriteHeader
,
245 &FtwDevice
->FtwLastWriteRecord
247 if (EFI_ERROR (Status
)) {
255 Reclaim the work space on the working block.
257 @param FtwDevice Point to private data of FTW driver
258 @param PreserveRecord Whether to preserve the working record is needed
260 @retval EFI_SUCCESS The function completed successfully
261 @retval EFI_OUT_OF_RESOURCES Allocate memory error
262 @retval EFI_ABORTED The function could not complete successfully
266 FtwReclaimWorkSpace (
267 IN EFI_FTW_DEVICE
*FtwDevice
,
268 IN BOOLEAN PreserveRecord
273 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
275 UINTN TempBufferSize
;
276 UINTN SpareBufferSize
;
278 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
282 DEBUG ((EFI_D_ERROR
, "Ftw: start to reclaim work space\n"));
285 // Read all original data from working block to a memory buffer
287 TempBufferSize
= FtwDevice
->SpareAreaLength
;
288 TempBuffer
= AllocateZeroPool (TempBufferSize
);
289 if (TempBuffer
== NULL
) {
290 return EFI_OUT_OF_RESOURCES
;
294 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
295 Length
= FtwDevice
->BlockSize
;
296 Status
= FtwDevice
->FtwFvBlock
->Read (
297 FtwDevice
->FtwFvBlock
,
298 FtwDevice
->FtwWorkBlockLba
+ Index
,
303 if (EFI_ERROR (Status
)) {
304 FreePool (TempBuffer
);
311 // Clean up the workspace, remove all the completed records.
314 ((UINTN
) (FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
)) * FtwDevice
->BlockSize
+
315 FtwDevice
->FtwWorkSpaceBase
;
318 // Clear the content of buffer that will save the new work space data
320 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
323 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
327 FtwDevice
->FtwWorkSpaceHeader
,
328 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
330 if (PreserveRecord
) {
332 // Get the last record following the header,
334 Status
= FtwGetLastWriteHeader (
335 FtwDevice
->FtwWorkSpaceHeader
,
336 FtwDevice
->FtwWorkSpaceSize
,
337 &FtwDevice
->FtwLastWriteHeader
339 Header
= FtwDevice
->FtwLastWriteHeader
;
340 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
)) {
342 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
343 FtwDevice
->FtwLastWriteHeader
,
344 WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
350 FtwDevice
->FtwWorkSpace
,
352 FtwDevice
->FtwWorkSpaceSize
355 FtwGetLastWriteHeader (
356 FtwDevice
->FtwWorkSpaceHeader
,
357 FtwDevice
->FtwWorkSpaceSize
,
358 &FtwDevice
->FtwLastWriteHeader
362 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
364 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) (TempBuffer
+ FtwDevice
->FtwWorkSpaceBase
);
365 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
366 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
369 // Try to keep the content of spare block
370 // Save spare block into a spare backup memory buffer (Sparebuffer)
372 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
373 SpareBuffer
= AllocatePool (SpareBufferSize
);
374 if (SpareBuffer
== NULL
) {
375 FreePool (TempBuffer
);
376 return EFI_OUT_OF_RESOURCES
;
380 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
381 Length
= FtwDevice
->BlockSize
;
382 Status
= FtwDevice
->FtwBackupFvb
->Read (
383 FtwDevice
->FtwBackupFvb
,
384 FtwDevice
->FtwSpareLba
+ Index
,
389 if (EFI_ERROR (Status
)) {
390 FreePool (TempBuffer
);
391 FreePool (SpareBuffer
);
398 // Write the memory buffer to spare block
400 Status
= FtwEraseSpareBlock (FtwDevice
);
402 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
403 Length
= FtwDevice
->BlockSize
;
404 Status
= FtwDevice
->FtwBackupFvb
->Write (
405 FtwDevice
->FtwBackupFvb
,
406 FtwDevice
->FtwSpareLba
+ Index
,
411 if (EFI_ERROR (Status
)) {
412 FreePool (TempBuffer
);
413 FreePool (SpareBuffer
);
422 FreePool (TempBuffer
);
425 // Set the WorkingBlockValid in spare block
427 Status
= FtwUpdateFvState (
428 FtwDevice
->FtwBackupFvb
,
429 FtwDevice
->FtwWorkSpaceLba
,
430 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
433 if (EFI_ERROR (Status
)) {
434 FreePool (SpareBuffer
);
438 // Before erase the working block, set WorkingBlockInvalid in working block.
440 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
441 // WorkingBlockInvalid);
443 Status
= FtwUpdateFvState (
444 FtwDevice
->FtwFvBlock
,
445 FtwDevice
->FtwWorkSpaceLba
,
446 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
447 WORKING_BLOCK_INVALID
449 if (EFI_ERROR (Status
)) {
450 FreePool (SpareBuffer
);
454 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
457 // Write the spare block to working block
459 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
460 if (EFI_ERROR (Status
)) {
461 FreePool (SpareBuffer
);
465 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
467 Status
= FtwEraseSpareBlock (FtwDevice
);
469 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
470 Length
= FtwDevice
->BlockSize
;
471 Status
= FtwDevice
->FtwBackupFvb
->Write (
472 FtwDevice
->FtwBackupFvb
,
473 FtwDevice
->FtwSpareLba
+ Index
,
478 if (EFI_ERROR (Status
)) {
479 FreePool (SpareBuffer
);
486 FreePool (SpareBuffer
);
488 DEBUG ((EFI_D_ERROR
, "Ftw: reclaim work space successfully\n"));