+++ /dev/null
-/** @file\r
-\r
- Internal functions to operate Working Block Space.\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
-\r
-#include "FtwLite.h"\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 EFI_SUCCESS The function completed successfully\r
- @retval EFI_ABORTED The function could not complete successfully.\r
-\r
-**/\r
-BOOLEAN\r
-IsValidWorkSpace (\r
- IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;\r
-\r
- ASSERT (WorkingHeader != NULL);\r
- if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {\r
- DEBUG ((EFI_D_ERROR, "FtwLite: Work block header valid bit check error\n"));\r
- return FALSE;\r
- }\r
- //\r
- // Check signature with gEfiSystemNvDataFvGuid\r
- //\r
- if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
- DEBUG ((EFI_D_ERROR, "FtwLite: Work block header signature check error\n"));\r
- return FALSE;\r
- }\r
- //\r
- // Check the CRC of header\r
- //\r
- CopyMem (\r
- &WorkingBlockHeader,\r
- WorkingHeader,\r
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
- );\r
-\r
- //\r
- // Filter out the Crc and State fields\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
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
- &WorkingBlockHeader.Crc\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {\r
- DEBUG ((EFI_D_ERROR, "FtwLite: Work block header CRC check error\n"));\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Initialize a work space when there is no work space.\r
-\r
-\r
- @param WorkingHeader Pointer of working block header\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
-InitWorkSpaceHeader (\r
- IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- ASSERT (WorkingHeader != NULL);\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
- SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);\r
-\r
- //\r
- // Calculate the CRC value\r
- //\r
- Status = gBS->CalculateCrc32 (\r
- (UINT8 *) WorkingHeader,\r
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
- &WorkingHeader->Crc\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Restore the WorkingBlockValid flag to VALID state\r
- //\r
- WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;\r
- WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Update a bit of state on a block device. The location of the bit is\r
- calculated by the (Lba, Offset, bit). Here bit is determined by the\r
- the name of a certain bit.\r
-\r
-\r
- @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock\r
- @param Lba Lba of a block\r
- @param Offset Offset on the Lba\r
- @param NewBit New value that will override the old value if it can be change\r
-\r
- @retval EFI_SUCCESS A state bit has been updated successfully\r
- @retval Others Access block device error.\r
- Notes:\r
- Assume all bits of State are inside the same BYTE.\r
- @retval EFI_ABORTED Read block fail\r
-\r
-**/\r
-EFI_STATUS\r
-FtwUpdateFvState (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
- IN EFI_LBA Lba,\r
- IN UINTN Offset,\r
- IN UINT8 NewBit\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 State;\r
- UINTN Length;\r
-\r
- //\r
- // Read state from device, assume State is only one byte.\r
- //\r
- Length = sizeof (UINT8);\r
- Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_ABORTED;\r
- }\r
-\r
- State ^= FTW_POLARITY_REVERT;\r
- State = (UINT8) (State | NewBit);\r
- State ^= FTW_POLARITY_REVERT;\r
-\r
- //\r
- // Write state back to device\r
- //\r
- Length = sizeof (UINT8);\r
- Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Get the last Write record pointer.\r
- The last record is the record whose 'complete' state hasn't been set.\r
- After all, this header may be a EMPTY header entry for next Allocate.\r
-\r
-\r
- @param FtwLiteDevice Private data of this driver\r
- @param FtwLastRecord Pointer to retrieve the last write record\r
-\r
- @retval EFI_SUCCESS Get the last write record successfully\r
- @retval EFI_ABORTED The FTW work space is damaged\r
-\r
-**/\r
-EFI_STATUS\r
-FtwGetLastRecord (\r
- IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
- OUT EFI_FTW_LITE_RECORD **FtwLastRecord\r
- )\r
-{\r
- EFI_FTW_LITE_RECORD *Record;\r
-\r
- *FtwLastRecord = NULL;\r
- Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);\r
- while (Record->WriteCompleted == FTW_VALID_STATE) {\r
- //\r
- // If Offset exceed the FTW work space boudary, return error.\r
- //\r
- if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {\r
- return EFI_ABORTED;\r
- }\r
-\r
- Record++;\r
- }\r
- //\r
- // Last write record is found\r
- //\r
- *FtwLastRecord = Record;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Read from working block to refresh the work space in memory.\r
-\r
-\r
- @param FtwLiteDevice Point to private data of FTW driver\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
-WorkSpaceRefresh (\r
- IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Length;\r
- UINTN Offset;\r
- EFI_FTW_LITE_RECORD *Record;\r
-\r
- //\r
- // Initialize WorkSpace as FTW_ERASED_BYTE\r
- //\r
- SetMem (\r
- FtwLiteDevice->FtwWorkSpace,\r
- FtwLiteDevice->FtwWorkSpaceSize,\r
- FTW_ERASED_BYTE\r
- );\r
-\r
- //\r
- // Read from working block\r
- //\r
- Length = FtwLiteDevice->FtwWorkSpaceSize;\r
- Status = FtwLiteDevice->FtwFvBlock->Read (\r
- FtwLiteDevice->FtwFvBlock,\r
- FtwLiteDevice->FtwWorkSpaceLba,\r
- FtwLiteDevice->FtwWorkSpaceBase,\r
- &Length,\r
- FtwLiteDevice->FtwWorkSpace\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_ABORTED;\r
- }\r
- //\r
- // Refresh the FtwLastRecord\r
- //\r
- Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
-\r
- Record = FtwLiteDevice->FtwLastRecord;\r
- Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;\r
-\r
- //\r
- // If work space has error or Record is out of the workspace limit, THEN\r
- // call reclaim.\r
- //\r
- if (EFI_ERROR (Status) || (Offset + FTW_LITE_RECORD_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {\r
- //\r
- // reclaim work space in working block.\r
- //\r
- Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim workspace - %r\n", Status));\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Reclaim the work space on the working block.\r
-\r
-\r
- @param FtwLiteDevice Point to private data of FTW driver\r
- @param PreserveRecord Whether get the last record or not\r
-\r
- @retval EFI_SUCCESS The function completed successfully\r
- @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
- @retval EFI_ABORTED The function could not complete successfully\r
-\r
-**/\r
-EFI_STATUS\r
-FtwReclaimWorkSpace (\r
- IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
- IN BOOLEAN PreserveRecord\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 *TempBuffer;\r
- UINTN TempBufferSize;\r
- UINT8 *Ptr;\r
- UINTN Length;\r
- UINTN Index;\r
- UINTN SpareBufferSize;\r
- UINT8 *SpareBuffer;\r
- EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
- EFI_FTW_LITE_RECORD *Record;\r
-\r
- DEBUG ((EFI_D_ERROR, "FtwLite: start to reclaim work space\n"));\r
-\r
- //\r
- // Read all original data from working block to a memory buffer\r
- //\r
- TempBufferSize = FtwLiteDevice->SpareAreaLength;\r
- TempBuffer = AllocateZeroPool (TempBufferSize);\r
- if (TempBuffer == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Ptr = TempBuffer;\r
- for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwLiteDevice->BlockSize;\r
- Status = FtwLiteDevice->FtwFvBlock->Read (\r
- FtwLiteDevice->FtwFvBlock,\r
- FtwLiteDevice->FtwWorkBlockLba + Index,\r
- 0,\r
- &Length,\r
- Ptr\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (TempBuffer);\r
- return EFI_ABORTED;\r
- }\r
-\r
- Ptr += Length;\r
- }\r
- //\r
- // Clean up the workspace, remove all the completed records.\r
- //\r
- Ptr = TempBuffer +\r
- ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *\r
- FtwLiteDevice->BlockSize + FtwLiteDevice->FtwWorkSpaceBase;\r
-\r
- //\r
- // Clear the content of buffer that will save the new work space data\r
- //\r
- SetMem (Ptr, FtwLiteDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);\r
-\r
- //\r
- // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
- //\r
- CopyMem (\r
- Ptr,\r
- FtwLiteDevice->FtwWorkSpaceHeader,\r
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
- );\r
- if (PreserveRecord) {\r
- //\r
- // Get the last record\r
- //\r
- Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
- Record = FtwLiteDevice->FtwLastRecord;\r
- if (!EFI_ERROR (Status) &&\r
- Record != NULL &&\r
- Record->WriteAllocated == FTW_VALID_STATE &&\r
- Record->WriteCompleted != FTW_VALID_STATE) {\r
- CopyMem (\r
- (UINT8 *) Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
- Record,\r
- FTW_LITE_RECORD_SIZE\r
- );\r
- }\r
- }\r
-\r
- CopyMem (\r
- FtwLiteDevice->FtwWorkSpace,\r
- Ptr,\r
- FtwLiteDevice->FtwWorkSpaceSize\r
- );\r
-\r
- Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
-\r
- //\r
- // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
- //\r
- WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;\r
- WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
- WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
-\r
- //\r
- // Try to keep the content of spare block\r
- // Save spare block into a spare backup memory buffer (Sparebuffer)\r
- //\r
- SpareBufferSize = FtwLiteDevice->SpareAreaLength;\r
- SpareBuffer = AllocatePool (SpareBufferSize);\r
- if (SpareBuffer == NULL) {\r
- FreePool (TempBuffer);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Ptr = SpareBuffer;\r
- for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwLiteDevice->BlockSize;\r
- Status = FtwLiteDevice->FtwBackupFvb->Read (\r
- FtwLiteDevice->FtwBackupFvb,\r
- FtwLiteDevice->FtwSpareLba + Index,\r
- 0,\r
- &Length,\r
- Ptr\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (TempBuffer);\r
- FreePool (SpareBuffer);\r
- return EFI_ABORTED;\r
- }\r
-\r
- Ptr += Length;\r
- }\r
- //\r
- // Write the memory buffer to spare block\r
- //\r
- Status = FtwEraseSpareBlock (FtwLiteDevice);\r
- Ptr = TempBuffer;\r
- for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwLiteDevice->BlockSize;\r
- Status = FtwLiteDevice->FtwBackupFvb->Write (\r
- FtwLiteDevice->FtwBackupFvb,\r
- FtwLiteDevice->FtwSpareLba + Index,\r
- 0,\r
- &Length,\r
- Ptr\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (TempBuffer);\r
- FreePool (SpareBuffer);\r
- return EFI_ABORTED;\r
- }\r
-\r
- Ptr += Length;\r
- }\r
- //\r
- // Free TempBuffer\r
- //\r
- FreePool (TempBuffer);\r
-\r
- //\r
- // Write the spare block to working block\r
- //\r
- Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);\r
- if (EFI_ERROR (Status)) {\r
- FreePool (SpareBuffer);\r
- return Status;\r
- }\r
- //\r
- // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
- //\r
- Status = FtwEraseSpareBlock (FtwLiteDevice);\r
- Ptr = SpareBuffer;\r
- for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
- Length = FtwLiteDevice->BlockSize;\r
- Status = FtwLiteDevice->FtwBackupFvb->Write (\r
- FtwLiteDevice->FtwBackupFvb,\r
- FtwLiteDevice->FtwSpareLba + Index,\r
- 0,\r
- &Length,\r
- Ptr\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (SpareBuffer);\r
- return EFI_ABORTED;\r
- }\r
-\r
- Ptr += Length;\r
- }\r
-\r
- FreePool (SpareBuffer);\r
-\r
- DEBUG ((EFI_D_ERROR, "FtwLite: reclaim work space success\n"));\r
-\r
- return EFI_SUCCESS;\r
-}\r