-/*++\r
+/** @file\r
\r
-Copyright (c) 2006 - 2007, Intel Corporation \r
-All rights reserved. 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
-Module Name:\r
-\r
- FtwLite.c\r
-\r
-Abstract:\r
-\r
- This is a simple fault tolerant write driver, based on PlatformFd library.\r
+ This is a simple fault tolerant write driver.\r
And it only supports write BufferSize <= SpareAreaLength.\r
\r
- This boot service only protocol provides fault tolerant write capability for \r
+ This boot service protocol only provides fault tolerant write capability for \r
block devices. The protocol has internal non-volatile intermediate storage \r
of the data and private information. It should be able to recover \r
automatically from a critical fault, such as power failure. \r
\r
-Notes:\r
-\r
The implementation uses an FTW Lite (Fault Tolerant Write) Work Space. \r
- This work space is a memory copy of the work space on the Woring Block,\r
+ This work space is a memory copy of the work space on the Working Block,\r
the size of the work space is the FTW_WORK_SPACE_SIZE bytes.\r
+ \r
+ The work space stores each write record as EFI_FTW_LITE_RECORD structure.\r
+ The spare block stores the write buffer before write to the target block.\r
+ \r
+ The write record has three states to specify the different phase of write operation.\r
+ 1) WRITE_ALLOCATED is that the record is allocated in write space.\r
+ The information of write operation is stored in write record structure.\r
+ 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.\r
+ 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.\r
+\r
+ This driver operates the data as the whole size of spare block. It also assumes that \r
+ working block is an area which contains working space in its last block and has the same size as spare block.\r
+ It first read the SpareAreaLength data from the target block into the spare memory buffer.\r
+ Then copy the write buffer data into the spare memory buffer.\r
+ Then write the spare memory buffer into the spare block.\r
+ Final copy the data from the spare block to the target block.\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation \r
+All rights reserved. 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
-#include <FtwLite.h>\r
-\r
-//\r
-// In write function, we should check the target range to prevent the user\r
-// from writing Spare block and Working space directly.\r
-//\r
-//\r
-// Fault Tolerant Write Protocol API\r
-//\r
+**/\r
+\r
+#include "FtwLite.h"\r
+\r
+/**\r
+ Starts a target block update. This function will record data about write\r
+ in fault tolerant storage and will complete the write in a recoverable\r
+ manner, ensuring at all times that either the original contents or\r
+ the modified contents are available.\r
+\r
+ @param This The pointer to this protocol instance. \r
+ @param FvbHandle The handle of FVB protocol that provides services for\r
+ reading, writing, and erasing the target block.\r
+ @param Lba The logical block address of the target block.\r
+ @param Offset The offset within the target block to place the data.\r
+ @param NumBytes The number of bytes to write to the target 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
+ @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block. \r
+ Offset + *NumBytes > SpareAreaLength.\r
+ @retval EFI_ACCESS_DENIED No writes have been allocated. \r
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.\r
+ @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
FtwLiteWrite (\r
IN OUT UINTN *NumBytes,\r
IN VOID *Buffer\r
)\r
-/*++\r
-\r
-Routine Description:\r
- Starts a target block update. This function will record data about write \r
- in fault tolerant storage and will complete the write in a recoverable \r
- manner, ensuring at all times that either the original contents or \r
- the modified contents are available.\r
-\r
-Arguments:\r
- This - Calling context\r
- FvbHandle - The handle of FVB protocol that provides services for \r
- reading, writing, and erasing the target block.\r
- Lba - The logical block address of the target block. \r
- Offset - The offset within the target block to place the data.\r
- NumBytes - The number of bytes to write to the target block.\r
- Buffer - The data to write.\r
-\r
-Returns:\r
- EFI_SUCCESS - The function completed successfully\r
- EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not \r
- a valid action.\r
- EFI_ACCESS_DENIED - No writes have been allocated.\r
- EFI_NOT_FOUND - Cannot find FVB by handle.\r
- EFI_OUT_OF_RESOURCES - Cannot allocate memory.\r
- EFI_ABORTED - The function could not complete successfully.\r
-\r
---*/\r
{\r
EFI_STATUS Status;\r
EFI_FTW_LITE_DEVICE *FtwLiteDevice;\r
//\r
// Check if there is enough free space for allocate a record\r
//\r
- if ((MyOffset + WRITE_TOTAL_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) {\r
- Status = FtwReclaimWorkSpace (FtwLiteDevice);\r
+ if ((MyOffset + FTW_LITE_RECORD_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) {\r
+ Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim work space - %r", Status));\r
return EFI_ABORTED;\r
FreePool (MyBuffer);\r
\r
//\r
- // Set the SpareCompleteD in the FTW record,\r
+ // Set the SpareComplete in the FTW record,\r
//\r
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;\r
Status = FtwUpdateFvState (\r
}\r
\r
\r
+/**\r
+ Write a record with fault tolerant manner.\r
+ Since the content has already backuped in spare block, the write is\r
+ guaranteed to be completed with fault tolerant manner.\r
+\r
+\r
+ @param FtwLiteDevice The private data of FTW_LITE driver\r
+ @param Fvb The FVB protocol that provides services for\r
+ reading, writing, and erasing the target block.\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
FtwWriteRecord (\r
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb\r
)\r
-/*++\r
-\r
-Routine Description:\r
- Write a record with fault tolerant mannaer.\r
- Since the content has already backuped in spare block, the write is \r
- guaranteed to be completed with fault tolerant manner.\r
- \r
-Arguments:\r
- FtwLiteDevice - The private data of FTW_LITE driver\r
- Fvb - The FVB protocol that provides services for \r
- reading, writing, and erasing the target block.\r
-\r
-Returns:\r
- EFI_SUCCESS - The function completed successfully\r
- EFI_ABORTED - The function could not complete successfully\r
-\r
---*/\r
{\r
EFI_STATUS Status;\r
EFI_FTW_LITE_RECORD *Record;\r
\r
//\r
// IF target block is working block, THEN Flush Spare Block To Working Block;\r
- // ELSE IF target block is boot block, THEN Flush Spare Block To boot Block;\r
// ELSE flush spare block to normal target block.ENDIF\r
//\r
if (IsInWorkingBlock (FtwLiteDevice, Fvb, Record->Lba)) {\r
ASSERT_EFI_ERROR (Status);\r
\r
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);\r
- } else if (IsBootBlock (FtwLiteDevice, Fvb, Record->Lba)) {\r
- //\r
- // Update boot block\r
- //\r
- Status = FlushSpareBlockToBootBlock (FtwLiteDevice);\r
} else {\r
//\r
- // Update blocks other than working block or boot block\r
+ // Update blocks other than working block\r
//\r
Status = FlushSpareBlockToTargetBlock (FtwLiteDevice, Fvb, Record->Lba);\r
}\r
}\r
\r
\r
+/**\r
+ Restarts a previously interrupted write. The caller must provide the\r
+ block protocol needed to complete the interrupted write.\r
+\r
+\r
+ @param FtwLiteDevice The private data of FTW_LITE driver\r
+ FvbHandle - The handle of FVB protocol that provides services for\r
+ reading, writing, and erasing the target block.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully\r
+ @retval EFI_ACCESS_DENIED No pending writes exist\r
+ @retval EFI_NOT_FOUND FVB protocol not found by the handle\r
+ @retval EFI_ABORTED The function could not complete successfully\r
+\r
+**/\r
EFI_STATUS\r
FtwRestart (\r
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
)\r
-/*++\r
-\r
-Routine Description:\r
- Restarts a previously interrupted write. The caller must provide the \r
- block protocol needed to complete the interrupted write.\r
- \r
-Arguments:\r
- FtwLiteDevice - The private data of FTW_LITE driver\r
- FvbHandle - The handle of FVB protocol that provides services for \r
- reading, writing, and erasing the target block.\r
-\r
-Returns:\r
- EFI_SUCCESS - The function completed successfully\r
- EFI_ACCESS_DENIED - No pending writes exist\r
- EFI_NOT_FOUND - FVB protocol not found by the handle\r
- EFI_ABORTED - The function could not complete successfully\r
-\r
---*/\r
{\r
EFI_STATUS Status;\r
EFI_FTW_LITE_RECORD *Record;\r
}\r
\r
\r
-EFI_STATUS\r
-FtwAbort (\r
- IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
- )\r
-/*++\r
+/**\r
+ Aborts all previous allocated writes.\r
\r
-Routine Description:\r
- Aborts all previous allocated writes.\r
\r
-Arguments:\r
- FtwLiteDevice - The private data of FTW_LITE driver\r
+ @param FtwLiteDevice The private data of FTW_LITE driver\r
\r
-Returns:\r
- EFI_SUCCESS - The function completed successfully\r
- EFI_ABORTED - The function could not complete successfully.\r
- EFI_NOT_FOUND - No allocated writes exist.\r
+ @retval EFI_SUCCESS The function completed successfully\r
+ @retval EFI_ABORTED The function could not complete successfully.\r
+ @retval EFI_NOT_FOUND No allocated writes exist.\r
\r
---*/\r
+**/\r
+EFI_STATUS\r
+FtwAbort (\r
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
+ )\r
{\r
EFI_STATUS Status;\r
UINTN Offset;\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ This function is the entry point of the Fault Tolerant Write driver.\r
+\r
+ @param ImageHandle A handle for the image that is initializing this driver\r
+ @param SystemTable A pointer to the EFI system table\r
+\r
+ @retval EFI_SUCCESS FTW has finished the initialization\r
+ @retval EFI_ABORTED FTW initialization error\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
InitializeFtwLite (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
-/*++\r
- Routine Description: \r
- This function is the entry point of the Fault Tolerant Write driver.\r
- \r
- Arguments: \r
- ImageHandle - EFI_HANDLE: A handle for the image that is initializing \r
- this driver\r
- SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table\r
- \r
- Returns: \r
- EFI_SUCCESS - FTW has finished the initialization\r
- EFI_ABORTED - FTW initialization error\r
-\r
---*/\r
{\r
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
UINTN Index;\r
UINT32 LbaIndex;\r
\r
//\r
- // Allocate Private data of this driver,\r
- // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
+ // Allocate Private data of this driver, including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
//\r
- FtwLiteDevice = NULL;\r
- FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);\r
- if (FtwLiteDevice != NULL) {\r
- Status = EFI_SUCCESS;\r
- } else {\r
- Status = EFI_OUT_OF_RESOURCES;\r
+ Length = FTW_WORK_SPACE_SIZE;\r
+ if (Length < PcdGet32 (PcdFlashNvStorageFtwWorkingSize)) {\r
+ Length = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
}\r
\r
- ASSERT_EFI_ERROR (Status);\r
+ FtwLiteDevice = NULL;\r
+ FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + Length);\r
+ ASSERT (FtwLiteDevice != NULL);\r
\r
ZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE));\r
FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE;\r
//\r
FtwLiteDevice->FtwWorkSpace = (UINT8 *) (FtwLiteDevice + 1);\r
FtwLiteDevice->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE;\r
+ FtwLiteDevice->FtwWorkSpaceBase = FTW_WORK_SPACE_BASE;\r
SetMem (\r
FtwLiteDevice->FtwWorkSpace,\r
FtwLiteDevice->FtwWorkSpaceSize,\r
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);\r
\r
if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) &&\r
- (FtwLiteDevice->WorkSpaceAddress <= (BaseAddress + FwVolHeader->FvLength))\r
+ (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FwVolHeader->FvLength))\r
) {\r
FtwLiteDevice->FtwFvBlock = Fvb;\r
//\r
FvbMapEntry = &FwVolHeader->BlockMap[0];\r
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {\r
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
- if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex)) {\r
+ if ((FtwLiteDevice->WorkSpaceAddress >= (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
+ && (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;\r
//\r
// Get the Work space size and Base(Offset)\r
//\r
// end for\r
//\r
+ if (LbaIndex <= FvbMapEntry->NumBlocks) {\r
+ //\r
+ // Work space range is found.\r
+ //\r
+ break;\r
+ }\r
FvbMapEntry++;\r
}\r
//\r
}\r
\r
if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&\r
- (FtwLiteDevice->SpareAreaAddress <= (BaseAddress + FwVolHeader->FvLength))\r
+ (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FwVolHeader->FvLength))\r
) {\r
FtwLiteDevice->FtwBackupFvb = Fvb;\r
//\r
FvbMapEntry = &FwVolHeader->BlockMap[0];\r
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {\r
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
- if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex)) {\r
+ if ((FtwLiteDevice->SpareAreaAddress >= (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
+ && (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
//\r
// Get the NumberOfSpareBlock and SizeOfSpareBlock\r
//\r
break;\r
}\r
}\r
-\r
+ if (LbaIndex <= FvbMapEntry->NumBlocks) {\r
+ //\r
+ // Spare FV range is found.\r
+ //\r
+ break;\r
+ }\r
FvbMapEntry++;\r
}\r
//\r
(FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))\r
) {\r
DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));\r
- ASSERT_EFI_ERROR (Status);\r
+ FreePool (FtwLiteDevice);\r
+ return EFI_ABORTED;\r
}\r
//\r
// Refresh workspace data from working block\r
//\r
Status = WorkSpaceRefresh (FtwLiteDevice);\r
if (EFI_ERROR (Status)) {\r
+ FreePool (FtwLiteDevice);\r
return EFI_ABORTED;\r
}\r
} else {\r
);\r
InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);\r
//\r
- // Write to work space on the working block\r
+ // Initialize the work space\r
//\r
- Length = FtwLiteDevice->FtwWorkSpaceSize;\r
- Status = FtwLiteDevice->FtwFvBlock->Write (\r
- FtwLiteDevice->FtwFvBlock,\r
- FtwLiteDevice->FtwWorkSpaceLba,\r
- FtwLiteDevice->FtwWorkSpaceBase,\r
- &Length,\r
- FtwLiteDevice->FtwWorkSpace\r
- );\r
+ Status = FtwReclaimWorkSpace (FtwLiteDevice, FALSE);\r
+\r
if (EFI_ERROR (Status)) {\r
+ FreePool (FtwLiteDevice);\r
return EFI_ABORTED;\r
}\r
}\r
&FtwLiteDevice->FtwLiteInstance\r
);\r
if (EFI_ERROR (Status)) {\r
+ FreePool (FtwLiteDevice);\r
return EFI_ABORTED;\r
}\r
//\r
Record = FtwLiteDevice->FtwLastRecord;\r
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;\r
if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {\r
- Offset += WRITE_TOTAL_SIZE;\r
+ Offset += FTW_LITE_RECORD_SIZE;\r
}\r
\r
if (!IsErasedFlashBuffer (\r
FtwLiteDevice->FtwWorkSpaceSize - Offset\r
)) {\r
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n"));\r
- Status = FtwReclaimWorkSpace (FtwLiteDevice);\r
+ Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status));\r
+ FreePool (FtwLiteDevice);\r
return EFI_ABORTED;\r
}\r
}\r