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
171 // Initialize WorkSpace as FTW_ERASED_BYTE
174 FtwDevice
->FtwWorkSpace
,
175 FtwDevice
->FtwWorkSpaceSize
,
180 // Read from working block
182 Length
= FtwDevice
->FtwWorkSpaceSize
;
183 Status
= FtwDevice
->FtwFvBlock
->Read (
184 FtwDevice
->FtwFvBlock
,
185 FtwDevice
->FtwWorkSpaceLba
,
186 FtwDevice
->FtwWorkSpaceBase
,
188 FtwDevice
->FtwWorkSpace
190 if (EFI_ERROR (Status
)) {
194 // Refresh the FtwLastWriteHeader
196 Status
= FtwGetLastWriteHeader (
197 FtwDevice
->FtwWorkSpaceHeader
,
198 FtwDevice
->FtwWorkSpaceSize
,
199 &FtwDevice
->FtwLastWriteHeader
201 if (EFI_ERROR (Status
)) {
203 // reclaim work space in working block.
205 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
206 if (EFI_ERROR (Status
)) {
207 DEBUG ((EFI_D_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
211 // Read from working block again
213 Length
= FtwDevice
->FtwWorkSpaceSize
;
214 Status
= FtwDevice
->FtwFvBlock
->Read (
215 FtwDevice
->FtwFvBlock
,
216 FtwDevice
->FtwWorkSpaceLba
,
217 FtwDevice
->FtwWorkSpaceBase
,
219 FtwDevice
->FtwWorkSpace
221 if (EFI_ERROR (Status
)) {
225 Status
= FtwGetLastWriteHeader (
226 FtwDevice
->FtwWorkSpaceHeader
,
227 FtwDevice
->FtwWorkSpaceSize
,
228 &FtwDevice
->FtwLastWriteHeader
230 if (EFI_ERROR (Status
)) {
235 // Refresh the FtwLastWriteRecord
237 Status
= FtwGetLastWriteRecord (
238 FtwDevice
->FtwLastWriteHeader
,
239 &FtwDevice
->FtwLastWriteRecord
241 if (EFI_ERROR (Status
)) {
249 Reclaim the work space on the working block.
251 @param FtwDevice Point to private data of FTW driver
252 @param PreserveRecord Whether to preserve the working record is needed
254 @retval EFI_SUCCESS The function completed successfully
255 @retval EFI_OUT_OF_RESOURCES Allocate memory error
256 @retval EFI_ABORTED The function could not complete successfully
260 FtwReclaimWorkSpace (
261 IN EFI_FTW_DEVICE
*FtwDevice
,
262 IN BOOLEAN PreserveRecord
267 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
269 UINTN TempBufferSize
;
270 UINTN SpareBufferSize
;
272 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
275 EFI_LBA WorkSpaceLbaOffset
;
277 DEBUG ((EFI_D_ERROR
, "Ftw: start to reclaim work space\n"));
279 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
282 // Read all original data from working block to a memory buffer
284 TempBufferSize
= FtwDevice
->SpareAreaLength
;
285 TempBuffer
= AllocateZeroPool (TempBufferSize
);
286 if (TempBuffer
== NULL
) {
287 return EFI_OUT_OF_RESOURCES
;
291 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
292 Length
= FtwDevice
->BlockSize
;
293 Status
= FtwDevice
->FtwFvBlock
->Read (
294 FtwDevice
->FtwFvBlock
,
295 FtwDevice
->FtwWorkBlockLba
+ Index
,
300 if (EFI_ERROR (Status
)) {
301 FreePool (TempBuffer
);
308 // Clean up the workspace, remove all the completed records.
311 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->BlockSize
+
312 FtwDevice
->FtwWorkSpaceBase
;
315 // Clear the content of buffer that will save the new work space data
317 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
320 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
324 FtwDevice
->FtwWorkSpaceHeader
,
325 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
327 if (PreserveRecord
) {
329 // Get the last record following the header,
331 Status
= FtwGetLastWriteHeader (
332 FtwDevice
->FtwWorkSpaceHeader
,
333 FtwDevice
->FtwWorkSpaceSize
,
334 &FtwDevice
->FtwLastWriteHeader
336 Header
= FtwDevice
->FtwLastWriteHeader
;
337 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
339 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
340 FtwDevice
->FtwLastWriteHeader
,
341 WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
347 FtwDevice
->FtwWorkSpace
,
349 FtwDevice
->FtwWorkSpaceSize
352 FtwGetLastWriteHeader (
353 FtwDevice
->FtwWorkSpaceHeader
,
354 FtwDevice
->FtwWorkSpaceSize
,
355 &FtwDevice
->FtwLastWriteHeader
358 FtwGetLastWriteRecord (
359 FtwDevice
->FtwLastWriteHeader
,
360 &FtwDevice
->FtwLastWriteRecord
364 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
366 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) (TempBuffer
+
367 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->BlockSize
+
368 FtwDevice
->FtwWorkSpaceBase
);
369 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
370 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
373 // Try to keep the content of spare block
374 // Save spare block into a spare backup memory buffer (Sparebuffer)
376 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
377 SpareBuffer
= AllocatePool (SpareBufferSize
);
378 if (SpareBuffer
== NULL
) {
379 FreePool (TempBuffer
);
380 return EFI_OUT_OF_RESOURCES
;
384 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
385 Length
= FtwDevice
->BlockSize
;
386 Status
= FtwDevice
->FtwBackupFvb
->Read (
387 FtwDevice
->FtwBackupFvb
,
388 FtwDevice
->FtwSpareLba
+ Index
,
393 if (EFI_ERROR (Status
)) {
394 FreePool (TempBuffer
);
395 FreePool (SpareBuffer
);
402 // Write the memory buffer to spare block
404 Status
= FtwEraseSpareBlock (FtwDevice
);
406 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
407 Length
= FtwDevice
->BlockSize
;
408 Status
= FtwDevice
->FtwBackupFvb
->Write (
409 FtwDevice
->FtwBackupFvb
,
410 FtwDevice
->FtwSpareLba
+ Index
,
415 if (EFI_ERROR (Status
)) {
416 FreePool (TempBuffer
);
417 FreePool (SpareBuffer
);
426 FreePool (TempBuffer
);
429 // Set the WorkingBlockValid in spare block
431 Status
= FtwUpdateFvState (
432 FtwDevice
->FtwBackupFvb
,
433 FtwDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
434 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
437 if (EFI_ERROR (Status
)) {
438 FreePool (SpareBuffer
);
442 // Before erase the working block, set WorkingBlockInvalid in working block.
444 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
445 // WorkingBlockInvalid);
447 Status
= FtwUpdateFvState (
448 FtwDevice
->FtwFvBlock
,
449 FtwDevice
->FtwWorkSpaceLba
,
450 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
451 WORKING_BLOCK_INVALID
453 if (EFI_ERROR (Status
)) {
454 FreePool (SpareBuffer
);
458 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
461 // Write the spare block to working block
463 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
464 if (EFI_ERROR (Status
)) {
465 FreePool (SpareBuffer
);
469 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
471 Status
= FtwEraseSpareBlock (FtwDevice
);
473 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
474 Length
= FtwDevice
->BlockSize
;
475 Status
= FtwDevice
->FtwBackupFvb
->Write (
476 FtwDevice
->FtwBackupFvb
,
477 FtwDevice
->FtwSpareLba
+ Index
,
482 if (EFI_ERROR (Status
)) {
483 FreePool (SpareBuffer
);
490 FreePool (SpareBuffer
);
492 DEBUG ((EFI_D_ERROR
, "Ftw: reclaim work space successfully\n"));