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
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 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 write record structure records the information of write operation.\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
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. We should check the target\r
- range to prevent the user from writing Spare block and Working \r
- space directly.\r
+ the modified contents are available.\r
\r
- @param This Calling context\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 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_BAD_BUFFER_SIZE The write would span a target block, which is not\r
- a valid action.\r
- @retval EFI_ACCESS_DENIED No writes have been allocated.\r
- @retval EFI_NOT_FOUND Cannot find FVB by handle.\r
- @retval EFI_OUT_OF_RESOURCES Cannot allocate memory.\r
- @retval EFI_ABORTED The function could not complete successfully.\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
//\r
// Check if there is enough free space for allocate a record\r
//\r
- if ((MyOffset + WRITE_TOTAL_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) {\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
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
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
//\r
// Allocate Private data of this driver, including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
//\r
+ Length = FTW_WORK_SPACE_SIZE;\r
+ if (Length < PcdGet32 (PcdFlashNvStorageFtwWorkingSize)) {\r
+ Length = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
+ }\r
+\r
FtwLiteDevice = NULL;\r
- FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);\r
+ FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + Length);\r
if (FtwLiteDevice != NULL) {\r
Status = EFI_SUCCESS;\r
} else {\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
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
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