\r
Internal functions to operate Working Block Space.\r
\r
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
**/\r
\r
\r
#include "FaultTolerantWrite.h"\r
\r
-/**\r
- Check to see if it is a valid work space.\r
-\r
+EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = {ZERO_GUID, 0, 0, 0, 0, {0, 0, 0}, 0};\r
\r
- @param WorkingHeader Pointer of working block header\r
-\r
- @retval TRUE The work space is valid.\r
- @retval FALSE The work space is invalid.\r
+/**\r
+ Initialize a local work space header.\r
\r
+ Since Signature and WriteQueueSize have been known, Crc can be calculated out,\r
+ then the work space header will be fixed.\r
**/\r
-BOOLEAN\r
-IsValidWorkSpace (\r
- IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
+VOID\r
+InitializeLocalWorkSpaceHeader (\r
+ VOID\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;\r
-\r
- if (WorkingHeader == NULL) {\r
- return FALSE;\r
- }\r
\r
- if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {\r
- DEBUG ((EFI_D_ERROR, "Ftw: Work block header valid bit check error\n"));\r
- return FALSE;\r
- }\r
//\r
- // Check signature with gEfiSystemNvDataFvGuid\r
+ // Check signature with gEdkiiWorkingBlockSignatureGuid.\r
//\r
- if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
- DEBUG ((EFI_D_ERROR, "Ftw: Work block header signature check error\n"));\r
- return FALSE;\r
+ if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {\r
+ //\r
+ // The local work space header has been initialized.\r
+ //\r
+ return;\r
}\r
+\r
+ SetMem (\r
+ &mWorkingBlockHeader,\r
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
+ FTW_ERASED_BYTE\r
+ );\r
+\r
//\r
- // Check the CRC of header\r
+ // Here using gEdkiiWorkingBlockSignatureGuid as the signature.\r
//\r
CopyMem (\r
- &WorkingBlockHeader,\r
- WorkingHeader,\r
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
+ &mWorkingBlockHeader.Signature,\r
+ &gEdkiiWorkingBlockSignatureGuid,\r
+ sizeof (EFI_GUID)\r
);\r
+ mWorkingBlockHeader.WriteQueueSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
\r
//\r
- // Filter out the Crc and State fields\r
+ // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.\r
//\r
- SetMem (\r
- &WorkingBlockHeader.Crc,\r
- sizeof (UINT32),\r
- FTW_ERASED_BYTE\r
- );\r
- WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;\r
- WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
\r
//\r
// Calculate the Crc of woking block header\r
//\r
Status = gBS->CalculateCrc32 (\r
- (UINT8 *) &WorkingBlockHeader,\r
+ &mWorkingBlockHeader,\r
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
- &WorkingBlockHeader.Crc\r
+ &mWorkingBlockHeader.Crc\r
);\r
- if (EFI_ERROR (Status)) {\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;\r
+ mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;\r
+}\r
+\r
+/**\r
+ Check to see if it is a valid work space.\r
+\r
+\r
+ @param WorkingHeader Pointer of working block header\r
+\r
+ @retval TRUE The work space is valid.\r
+ @retval FALSE The work space is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidWorkSpace (\r
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
+ )\r
+{\r
+ if (WorkingHeader == NULL) {\r
return FALSE;\r
}\r
\r
- if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {\r
- DEBUG ((EFI_D_ERROR, "Ftw: Work block header CRC check error\n"));\r
- return FALSE;\r
+ if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {\r
+ return TRUE;\r
}\r
\r
- return TRUE;\r
+ DEBUG ((EFI_D_INFO, "Ftw: Work block header check mismatch\n"));\r
+ return FALSE;\r
}\r
\r
/**\r
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
)\r
{\r
- EFI_STATUS Status;\r
-\r
if (WorkingHeader == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- //\r
- // Here using gEfiSystemNvDataFvGuid as the signature.\r
- //\r
- CopyMem (\r
- &WorkingHeader->Signature,\r
- &gEfiSystemNvDataFvGuid,\r
- sizeof (EFI_GUID)\r
- );\r
- WorkingHeader->WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
\r
- //\r
- // Crc is calculated with all the fields except Crc and STATE\r
- //\r
- WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
- WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
+ CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
\r
- SetMem (\r
- &WorkingHeader->Crc,\r
- sizeof (UINT32),\r
- FTW_ERASED_BYTE\r
- );\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read work space data from work block or spare block.\r
+\r
+ @param FvBlock FVB Protocol interface to access the block.\r
+ @param BlockSize The size of the block.\r
+ @param Lba Lba of the block.\r
+ @param Offset The offset within the block.\r
+ @param Length The number of bytes to read from the block.\r
+ @param Buffer The data is read.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_ABORTED The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadWorkSpaceData (\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+ IN UINTN BlockSize,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN Offset,\r
+ IN UINTN Length,\r
+ OUT UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *Ptr;\r
+ UINTN MyLength;\r
\r
//\r
- // Calculate the CRC value\r
+ // Calculate the real Offset and Lba to write.\r
//\r
- Status = gBS->CalculateCrc32 (\r
- (UINT8 *) WorkingHeader,\r
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
- &WorkingHeader->Crc\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_ABORTED;\r
+ while (Offset >= BlockSize) {\r
+ Offset -= BlockSize;\r
+ Lba++;\r
}\r
+\r
+ Ptr = Buffer;\r
+ while (Length > 0) {\r
+ if ((Offset + Length) > BlockSize) {\r
+ MyLength = BlockSize - Offset;\r
+ } else {\r
+ MyLength = Length;\r
+ }\r
+\r
+ Status = FvBlock->Read (\r
+ FvBlock,\r
+ Lba,\r
+ Offset,\r
+ &MyLength,\r
+ Ptr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_ABORTED;\r
+ }\r
+ Offset = 0;\r
+ Length -= MyLength;\r
+ Ptr += MyLength;\r
+ Lba++;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write work space data to work block.\r
+\r
+ @param FvBlock FVB Protocol interface to access the block.\r
+ @param BlockSize The size of the block.\r
+ @param Lba Lba of the block.\r
+ @param Offset The offset within the block to place the data.\r
+ @param Length The number of bytes to write to the block.\r
+ @param Buffer The data to write.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_ABORTED The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+WriteWorkSpaceData (\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+ IN UINTN BlockSize,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN Offset,\r
+ IN UINTN Length,\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *Ptr;\r
+ UINTN MyLength;\r
+\r
//\r
- // Restore the WorkingBlockValid flag to VALID state\r
+ // Calculate the real Offset and Lba to write.\r
//\r
- WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;\r
- WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
+ while (Offset >= BlockSize) {\r
+ Offset -= BlockSize;\r
+ Lba++;\r
+ }\r
\r
+ Ptr = Buffer;\r
+ while (Length > 0) {\r
+ if ((Offset + Length) > BlockSize) {\r
+ MyLength = BlockSize - Offset;\r
+ } else {\r
+ MyLength = Length;\r
+ }\r
+\r
+ Status = FvBlock->Write (\r
+ FvBlock,\r
+ Lba,\r
+ Offset,\r
+ &MyLength,\r
+ Ptr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_ABORTED;\r
+ }\r
+ Offset = 0;\r
+ Length -= MyLength;\r
+ Ptr += MyLength;\r
+ Lba++;\r
+ }\r
return EFI_SUCCESS;\r
}\r
\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN Length;\r
UINTN RemainingSpaceSize;\r
\r
//\r
//\r
// Read from working block\r
//\r
- Length = FtwDevice->FtwWorkSpaceSize;\r
- Status = FtwDevice->FtwFvBlock->Read (\r
- FtwDevice->FtwFvBlock,\r
- FtwDevice->FtwWorkSpaceLba,\r
- FtwDevice->FtwWorkSpaceBase,\r
- &Length,\r
- FtwDevice->FtwWorkSpace\r
- );\r
+ Status = ReadWorkSpaceData (\r
+ FtwDevice->FtwFvBlock,\r
+ FtwDevice->WorkBlockSize,\r
+ FtwDevice->FtwWorkSpaceLba,\r
+ FtwDevice->FtwWorkSpaceBase,\r
+ FtwDevice->FtwWorkSpaceSize,\r
+ FtwDevice->FtwWorkSpace\r
+ );\r
if (EFI_ERROR (Status)) {\r
return EFI_ABORTED;\r
}\r
//\r
// Read from working block again\r
//\r
- Length = FtwDevice->FtwWorkSpaceSize;\r
- Status = FtwDevice->FtwFvBlock->Read (\r
- FtwDevice->FtwFvBlock,\r
- FtwDevice->FtwWorkSpaceLba,\r
- FtwDevice->FtwWorkSpaceBase,\r
- &Length,\r
- FtwDevice->FtwWorkSpace\r
- );\r
+ Status = ReadWorkSpaceData (\r
+ FtwDevice->FtwFvBlock,\r
+ FtwDevice->WorkBlockSize,\r
+ FtwDevice->FtwWorkSpaceLba,\r
+ FtwDevice->FtwWorkSpaceBase,\r
+ FtwDevice->FtwWorkSpaceSize,\r
+ FtwDevice->FtwWorkSpace\r
+ );\r
if (EFI_ERROR (Status)) {\r
return EFI_ABORTED;\r
}\r
UINT8 *Ptr;\r
EFI_LBA WorkSpaceLbaOffset;\r
\r
- DEBUG ((EFI_D_ERROR, "Ftw: start to reclaim work space\n"));\r
+ DEBUG ((EFI_D_INFO, "Ftw: start to reclaim work space\n"));\r
\r
WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
\r
//\r
// Read all original data from working block to a memory buffer\r
//\r
- TempBufferSize = FtwDevice->SpareAreaLength;\r
+ TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;\r
TempBuffer = AllocateZeroPool (TempBufferSize);\r
if (TempBuffer == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
Ptr = TempBuffer;\r
- for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwDevice->BlockSize;\r
+ for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {\r
+ Length = FtwDevice->WorkBlockSize;\r
Status = FtwDevice->FtwFvBlock->Read (\r
FtwDevice->FtwFvBlock,\r
FtwDevice->FtwWorkBlockLba + Index,\r
// Clean up the workspace, remove all the completed records.\r
//\r
Ptr = TempBuffer +\r
- (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
+ (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +\r
FtwDevice->FtwWorkSpaceBase;\r
\r
//\r
CopyMem (\r
Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
FtwDevice->FtwLastWriteHeader,\r
- WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
+ FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
);\r
}\r
}\r
// Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
//\r
WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (TempBuffer +\r
- (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
+ (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +\r
FtwDevice->FtwWorkSpaceBase);\r
WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
\r
Ptr = SpareBuffer;\r
for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwDevice->BlockSize;\r
+ Length = FtwDevice->SpareBlockSize;\r
Status = FtwDevice->FtwBackupFvb->Read (\r
FtwDevice->FtwBackupFvb,\r
FtwDevice->FtwSpareLba + Index,\r
// Write the memory buffer to spare block\r
//\r
Status = FtwEraseSpareBlock (FtwDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (TempBuffer);\r
+ FreePool (SpareBuffer);\r
+ return EFI_ABORTED;\r
+ }\r
Ptr = TempBuffer;\r
- for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwDevice->BlockSize;\r
+ for (Index = 0; TempBufferSize > 0; Index += 1) {\r
+ if (TempBufferSize > FtwDevice->SpareBlockSize) {\r
+ Length = FtwDevice->SpareBlockSize;\r
+ } else {\r
+ Length = TempBufferSize;\r
+ }\r
Status = FtwDevice->FtwBackupFvb->Write (\r
FtwDevice->FtwBackupFvb,\r
FtwDevice->FtwSpareLba + Index,\r
}\r
\r
Ptr += Length;\r
+ TempBufferSize -= Length;\r
}\r
//\r
// Free TempBuffer\r
//\r
Status = FtwUpdateFvState (\r
FtwDevice->FtwBackupFvb,\r
- FtwDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
- FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
+ FtwDevice->SpareBlockSize,\r
+ FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,\r
+ FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),\r
WORKING_BLOCK_VALID\r
);\r
if (EFI_ERROR (Status)) {\r
//\r
Status = FtwUpdateFvState (\r
FtwDevice->FtwFvBlock,\r
+ FtwDevice->WorkBlockSize,\r
FtwDevice->FtwWorkSpaceLba,\r
FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
WORKING_BLOCK_INVALID\r
// Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
//\r
Status = FtwEraseSpareBlock (FtwDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (SpareBuffer);\r
+ return EFI_ABORTED;\r
+ }\r
Ptr = SpareBuffer;\r
for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwDevice->BlockSize;\r
+ Length = FtwDevice->SpareBlockSize;\r
Status = FtwDevice->FtwBackupFvb->Write (\r
FtwDevice->FtwBackupFvb,\r
FtwDevice->FtwSpareLba + Index,\r
\r
FreePool (SpareBuffer);\r
\r
- DEBUG ((EFI_D_ERROR, "Ftw: reclaim work space successfully\n"));\r
+ DEBUG ((EFI_D_INFO, "Ftw: reclaim work space successfully\n"));\r
\r
return EFI_SUCCESS;\r
}\r