3 Internal functions to operate Working Block Space.
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 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 TRUE The work space is valid.
26 @retval FALSE The work space is invalid.
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
169 UINTN RemainingSpaceSize
;
172 // Initialize WorkSpace as FTW_ERASED_BYTE
175 FtwDevice
->FtwWorkSpace
,
176 FtwDevice
->FtwWorkSpaceSize
,
181 // Read from working block
183 Length
= FtwDevice
->FtwWorkSpaceSize
;
184 Status
= FtwDevice
->FtwFvBlock
->Read (
185 FtwDevice
->FtwFvBlock
,
186 FtwDevice
->FtwWorkSpaceLba
,
187 FtwDevice
->FtwWorkSpaceBase
,
189 FtwDevice
->FtwWorkSpace
191 if (EFI_ERROR (Status
)) {
195 // Refresh the FtwLastWriteHeader
197 Status
= FtwGetLastWriteHeader (
198 FtwDevice
->FtwWorkSpaceHeader
,
199 FtwDevice
->FtwWorkSpaceSize
,
200 &FtwDevice
->FtwLastWriteHeader
202 RemainingSpaceSize
= FtwDevice
->FtwWorkSpaceSize
- ((UINTN
) FtwDevice
->FtwLastWriteHeader
- (UINTN
) FtwDevice
->FtwWorkSpace
);
203 DEBUG ((EFI_D_INFO
, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize
));
205 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
206 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
207 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
208 // it needs to reclaim work space.
210 if (EFI_ERROR (Status
) || RemainingSpaceSize
< sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD
)) {
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
239 if (EFI_ERROR (Status
)) {
244 // Refresh the FtwLastWriteRecord
246 Status
= FtwGetLastWriteRecord (
247 FtwDevice
->FtwLastWriteHeader
,
248 &FtwDevice
->FtwLastWriteRecord
250 if (EFI_ERROR (Status
)) {
258 Reclaim the work space on the working block.
260 @param FtwDevice Point to private data of FTW driver
261 @param PreserveRecord Whether to preserve the working record is needed
263 @retval EFI_SUCCESS The function completed successfully
264 @retval EFI_OUT_OF_RESOURCES Allocate memory error
265 @retval EFI_ABORTED The function could not complete successfully
269 FtwReclaimWorkSpace (
270 IN EFI_FTW_DEVICE
*FtwDevice
,
271 IN BOOLEAN PreserveRecord
276 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
278 UINTN TempBufferSize
;
279 UINTN SpareBufferSize
;
281 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
284 EFI_LBA WorkSpaceLbaOffset
;
286 DEBUG ((EFI_D_ERROR
, "Ftw: start to reclaim work space\n"));
288 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
291 // Read all original data from working block to a memory buffer
293 TempBufferSize
= FtwDevice
->SpareAreaLength
;
294 TempBuffer
= AllocateZeroPool (TempBufferSize
);
295 if (TempBuffer
== NULL
) {
296 return EFI_OUT_OF_RESOURCES
;
300 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
301 Length
= FtwDevice
->BlockSize
;
302 Status
= FtwDevice
->FtwFvBlock
->Read (
303 FtwDevice
->FtwFvBlock
,
304 FtwDevice
->FtwWorkBlockLba
+ Index
,
309 if (EFI_ERROR (Status
)) {
310 FreePool (TempBuffer
);
317 // Clean up the workspace, remove all the completed records.
320 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->BlockSize
+
321 FtwDevice
->FtwWorkSpaceBase
;
324 // Clear the content of buffer that will save the new work space data
326 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
329 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
333 FtwDevice
->FtwWorkSpaceHeader
,
334 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
336 if (PreserveRecord
) {
338 // Get the last record following the header,
340 Status
= FtwGetLastWriteHeader (
341 FtwDevice
->FtwWorkSpaceHeader
,
342 FtwDevice
->FtwWorkSpaceSize
,
343 &FtwDevice
->FtwLastWriteHeader
345 Header
= FtwDevice
->FtwLastWriteHeader
;
346 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
348 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
349 FtwDevice
->FtwLastWriteHeader
,
350 WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
356 FtwDevice
->FtwWorkSpace
,
358 FtwDevice
->FtwWorkSpaceSize
361 FtwGetLastWriteHeader (
362 FtwDevice
->FtwWorkSpaceHeader
,
363 FtwDevice
->FtwWorkSpaceSize
,
364 &FtwDevice
->FtwLastWriteHeader
367 FtwGetLastWriteRecord (
368 FtwDevice
->FtwLastWriteHeader
,
369 &FtwDevice
->FtwLastWriteRecord
373 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
375 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) (TempBuffer
+
376 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->BlockSize
+
377 FtwDevice
->FtwWorkSpaceBase
);
378 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
379 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
382 // Try to keep the content of spare block
383 // Save spare block into a spare backup memory buffer (Sparebuffer)
385 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
386 SpareBuffer
= AllocatePool (SpareBufferSize
);
387 if (SpareBuffer
== NULL
) {
388 FreePool (TempBuffer
);
389 return EFI_OUT_OF_RESOURCES
;
393 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
394 Length
= FtwDevice
->BlockSize
;
395 Status
= FtwDevice
->FtwBackupFvb
->Read (
396 FtwDevice
->FtwBackupFvb
,
397 FtwDevice
->FtwSpareLba
+ Index
,
402 if (EFI_ERROR (Status
)) {
403 FreePool (TempBuffer
);
404 FreePool (SpareBuffer
);
411 // Write the memory buffer to spare block
413 Status
= FtwEraseSpareBlock (FtwDevice
);
415 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
416 Length
= FtwDevice
->BlockSize
;
417 Status
= FtwDevice
->FtwBackupFvb
->Write (
418 FtwDevice
->FtwBackupFvb
,
419 FtwDevice
->FtwSpareLba
+ Index
,
424 if (EFI_ERROR (Status
)) {
425 FreePool (TempBuffer
);
426 FreePool (SpareBuffer
);
435 FreePool (TempBuffer
);
438 // Set the WorkingBlockValid in spare block
440 Status
= FtwUpdateFvState (
441 FtwDevice
->FtwBackupFvb
,
442 FtwDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
443 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
446 if (EFI_ERROR (Status
)) {
447 FreePool (SpareBuffer
);
451 // Before erase the working block, set WorkingBlockInvalid in working block.
453 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
454 // WorkingBlockInvalid);
456 Status
= FtwUpdateFvState (
457 FtwDevice
->FtwFvBlock
,
458 FtwDevice
->FtwWorkSpaceLba
,
459 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
460 WORKING_BLOCK_INVALID
462 if (EFI_ERROR (Status
)) {
463 FreePool (SpareBuffer
);
467 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
470 // Write the spare block to working block
472 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
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 (FtwDevice
);
482 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
483 Length
= FtwDevice
->BlockSize
;
484 Status
= FtwDevice
->FtwBackupFvb
->Write (
485 FtwDevice
->FtwBackupFvb
,
486 FtwDevice
->FtwSpareLba
+ Index
,
491 if (EFI_ERROR (Status
)) {
492 FreePool (SpareBuffer
);
499 FreePool (SpareBuffer
);
501 DEBUG ((EFI_D_ERROR
, "Ftw: reclaim work space successfully\n"));