3 Internal functions to operate Working Block Space.
5 Copyright (c) 2006 - 2013, 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"
19 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader
= {ZERO_GUID
, 0, 0, 0, 0, {0, 0, 0}, 0};
22 Initialize a local work space header.
24 Since Signature and WriteQueueSize have been known, Crc can be calculated out,
25 then the work space header will be fixed.
28 InitializeLocalWorkSpaceHeader (
35 // Check signature with gEdkiiWorkingBlockSignatureGuid.
37 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, &mWorkingBlockHeader
.Signature
)) {
39 // The local work space header has been initialized.
46 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
51 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
54 &mWorkingBlockHeader
.Signature
,
55 &gEdkiiWorkingBlockSignatureGuid
,
58 mWorkingBlockHeader
.WriteQueueSize
= (UINT64
) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize
) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
61 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
65 // Calculate the Crc of woking block header
67 Status
= gBS
->CalculateCrc32 (
69 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
70 &mWorkingBlockHeader
.Crc
72 ASSERT_EFI_ERROR (Status
);
74 mWorkingBlockHeader
.WorkingBlockValid
= FTW_VALID_STATE
;
75 mWorkingBlockHeader
.WorkingBlockInvalid
= FTW_INVALID_STATE
;
79 Check to see if it is a valid work space.
82 @param WorkingHeader Pointer of working block header
84 @retval TRUE The work space is valid.
85 @retval FALSE The work space is invalid.
90 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
93 if (WorkingHeader
== NULL
) {
97 if (CompareMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)) == 0) {
101 DEBUG ((EFI_D_ERROR
, "Ftw: Work block header check error\n"));
106 Initialize a work space when there is no work space.
108 @param WorkingHeader Pointer of working block header
110 @retval EFI_SUCCESS The function completed successfully
111 @retval EFI_ABORTED The function could not complete successfully.
115 InitWorkSpaceHeader (
116 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
119 if (WorkingHeader
== NULL
) {
120 return EFI_INVALID_PARAMETER
;
123 CopyMem (WorkingHeader
, &mWorkingBlockHeader
, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
));
129 Read from working block to refresh the work space in memory.
131 @param FtwDevice Point to private data of FTW driver
133 @retval EFI_SUCCESS The function completed successfully
134 @retval EFI_ABORTED The function could not complete successfully.
139 IN EFI_FTW_DEVICE
*FtwDevice
144 UINTN RemainingSpaceSize
;
147 // Initialize WorkSpace as FTW_ERASED_BYTE
150 FtwDevice
->FtwWorkSpace
,
151 FtwDevice
->FtwWorkSpaceSize
,
156 // Read from working block
158 Length
= FtwDevice
->FtwWorkSpaceSize
;
159 Status
= FtwDevice
->FtwFvBlock
->Read (
160 FtwDevice
->FtwFvBlock
,
161 FtwDevice
->FtwWorkSpaceLba
,
162 FtwDevice
->FtwWorkSpaceBase
,
164 FtwDevice
->FtwWorkSpace
166 if (EFI_ERROR (Status
)) {
170 // Refresh the FtwLastWriteHeader
172 Status
= FtwGetLastWriteHeader (
173 FtwDevice
->FtwWorkSpaceHeader
,
174 FtwDevice
->FtwWorkSpaceSize
,
175 &FtwDevice
->FtwLastWriteHeader
177 RemainingSpaceSize
= FtwDevice
->FtwWorkSpaceSize
- ((UINTN
) FtwDevice
->FtwLastWriteHeader
- (UINTN
) FtwDevice
->FtwWorkSpace
);
178 DEBUG ((EFI_D_INFO
, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize
));
180 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
181 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
182 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
183 // it needs to reclaim work space.
185 if (EFI_ERROR (Status
) || RemainingSpaceSize
< sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD
)) {
187 // reclaim work space in working block.
189 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
190 if (EFI_ERROR (Status
)) {
191 DEBUG ((EFI_D_ERROR
, "Ftw: Reclaim workspace - %r\n", Status
));
195 // Read from working block again
197 Length
= FtwDevice
->FtwWorkSpaceSize
;
198 Status
= FtwDevice
->FtwFvBlock
->Read (
199 FtwDevice
->FtwFvBlock
,
200 FtwDevice
->FtwWorkSpaceLba
,
201 FtwDevice
->FtwWorkSpaceBase
,
203 FtwDevice
->FtwWorkSpace
205 if (EFI_ERROR (Status
)) {
209 Status
= FtwGetLastWriteHeader (
210 FtwDevice
->FtwWorkSpaceHeader
,
211 FtwDevice
->FtwWorkSpaceSize
,
212 &FtwDevice
->FtwLastWriteHeader
214 if (EFI_ERROR (Status
)) {
219 // Refresh the FtwLastWriteRecord
221 Status
= FtwGetLastWriteRecord (
222 FtwDevice
->FtwLastWriteHeader
,
223 &FtwDevice
->FtwLastWriteRecord
225 if (EFI_ERROR (Status
)) {
233 Reclaim the work space on the working block.
235 @param FtwDevice Point to private data of FTW driver
236 @param PreserveRecord Whether to preserve the working record is needed
238 @retval EFI_SUCCESS The function completed successfully
239 @retval EFI_OUT_OF_RESOURCES Allocate memory error
240 @retval EFI_ABORTED The function could not complete successfully
244 FtwReclaimWorkSpace (
245 IN EFI_FTW_DEVICE
*FtwDevice
,
246 IN BOOLEAN PreserveRecord
251 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
253 UINTN TempBufferSize
;
254 UINTN SpareBufferSize
;
256 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingBlockHeader
;
259 EFI_LBA WorkSpaceLbaOffset
;
261 DEBUG ((EFI_D_INFO
, "Ftw: start to reclaim work space\n"));
263 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
266 // Read all original data from working block to a memory buffer
268 TempBufferSize
= FtwDevice
->SpareAreaLength
;
269 TempBuffer
= AllocateZeroPool (TempBufferSize
);
270 if (TempBuffer
== NULL
) {
271 return EFI_OUT_OF_RESOURCES
;
275 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
276 Length
= FtwDevice
->BlockSize
;
277 Status
= FtwDevice
->FtwFvBlock
->Read (
278 FtwDevice
->FtwFvBlock
,
279 FtwDevice
->FtwWorkBlockLba
+ Index
,
284 if (EFI_ERROR (Status
)) {
285 FreePool (TempBuffer
);
292 // Clean up the workspace, remove all the completed records.
295 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->BlockSize
+
296 FtwDevice
->FtwWorkSpaceBase
;
299 // Clear the content of buffer that will save the new work space data
301 SetMem (Ptr
, FtwDevice
->FtwWorkSpaceSize
, FTW_ERASED_BYTE
);
304 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
308 FtwDevice
->FtwWorkSpaceHeader
,
309 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
)
311 if (PreserveRecord
) {
313 // Get the last record following the header,
315 Status
= FtwGetLastWriteHeader (
316 FtwDevice
->FtwWorkSpaceHeader
,
317 FtwDevice
->FtwWorkSpaceSize
,
318 &FtwDevice
->FtwLastWriteHeader
320 Header
= FtwDevice
->FtwLastWriteHeader
;
321 if (!EFI_ERROR (Status
) && (Header
!= NULL
) && (Header
->Complete
!= FTW_VALID_STATE
) && (Header
->HeaderAllocated
== FTW_VALID_STATE
)) {
323 Ptr
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
),
324 FtwDevice
->FtwLastWriteHeader
,
325 FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
, Header
->PrivateDataSize
)
331 FtwDevice
->FtwWorkSpace
,
333 FtwDevice
->FtwWorkSpaceSize
336 FtwGetLastWriteHeader (
337 FtwDevice
->FtwWorkSpaceHeader
,
338 FtwDevice
->FtwWorkSpaceSize
,
339 &FtwDevice
->FtwLastWriteHeader
342 FtwGetLastWriteRecord (
343 FtwDevice
->FtwLastWriteHeader
,
344 &FtwDevice
->FtwLastWriteRecord
348 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
350 WorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) (TempBuffer
+
351 (UINTN
) WorkSpaceLbaOffset
* FtwDevice
->BlockSize
+
352 FtwDevice
->FtwWorkSpaceBase
);
353 WorkingBlockHeader
->WorkingBlockValid
= FTW_INVALID_STATE
;
354 WorkingBlockHeader
->WorkingBlockInvalid
= FTW_INVALID_STATE
;
357 // Try to keep the content of spare block
358 // Save spare block into a spare backup memory buffer (Sparebuffer)
360 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
361 SpareBuffer
= AllocatePool (SpareBufferSize
);
362 if (SpareBuffer
== NULL
) {
363 FreePool (TempBuffer
);
364 return EFI_OUT_OF_RESOURCES
;
368 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
369 Length
= FtwDevice
->BlockSize
;
370 Status
= FtwDevice
->FtwBackupFvb
->Read (
371 FtwDevice
->FtwBackupFvb
,
372 FtwDevice
->FtwSpareLba
+ Index
,
377 if (EFI_ERROR (Status
)) {
378 FreePool (TempBuffer
);
379 FreePool (SpareBuffer
);
386 // Write the memory buffer to spare block
388 Status
= FtwEraseSpareBlock (FtwDevice
);
390 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
391 Length
= FtwDevice
->BlockSize
;
392 Status
= FtwDevice
->FtwBackupFvb
->Write (
393 FtwDevice
->FtwBackupFvb
,
394 FtwDevice
->FtwSpareLba
+ Index
,
399 if (EFI_ERROR (Status
)) {
400 FreePool (TempBuffer
);
401 FreePool (SpareBuffer
);
410 FreePool (TempBuffer
);
413 // Set the WorkingBlockValid in spare block
415 Status
= FtwUpdateFvState (
416 FtwDevice
->FtwBackupFvb
,
417 FtwDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
418 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
421 if (EFI_ERROR (Status
)) {
422 FreePool (SpareBuffer
);
426 // Before erase the working block, set WorkingBlockInvalid in working block.
428 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
429 // WorkingBlockInvalid);
431 Status
= FtwUpdateFvState (
432 FtwDevice
->FtwFvBlock
,
433 FtwDevice
->FtwWorkSpaceLba
,
434 FtwDevice
->FtwWorkSpaceBase
+ sizeof (EFI_GUID
) + sizeof (UINT32
),
435 WORKING_BLOCK_INVALID
437 if (EFI_ERROR (Status
)) {
438 FreePool (SpareBuffer
);
442 FtwDevice
->FtwWorkSpaceHeader
->WorkingBlockInvalid
= FTW_VALID_STATE
;
445 // Write the spare block to working block
447 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
448 if (EFI_ERROR (Status
)) {
449 FreePool (SpareBuffer
);
453 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
455 Status
= FtwEraseSpareBlock (FtwDevice
);
457 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
458 Length
= FtwDevice
->BlockSize
;
459 Status
= FtwDevice
->FtwBackupFvb
->Write (
460 FtwDevice
->FtwBackupFvb
,
461 FtwDevice
->FtwSpareLba
+ Index
,
466 if (EFI_ERROR (Status
)) {
467 FreePool (SpareBuffer
);
474 FreePool (SpareBuffer
);
476 DEBUG ((EFI_D_INFO
, "Ftw: reclaim work space successfully\n"));