summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
diff options
context:
space:
mode:
authorqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-18 14:32:48 +0000
committerqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-18 14:32:48 +0000
commit53c71d097b13311e2bd8dda6ae54b5766a1c7d6d (patch)
tree389779feb53ef5f1a5e212d75ee8399697086d3b /MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
parent7fb66a6dff5f9737c086c700d53e5afd5bb53dc7 (diff)
downloadedk2-53c71d097b13311e2bd8dda6ae54b5766a1c7d6d.zip
edk2-53c71d097b13311e2bd8dda6ae54b5766a1c7d6d.tar.gz
edk2-53c71d097b13311e2bd8dda6ae54b5766a1c7d6d.tar.bz2
Adjust directory structures.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3325 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c')
-rw-r--r--MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c561
1 files changed, 561 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c b/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
new file mode 100644
index 0000000..00d7d8e
--- /dev/null
+++ b/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
@@ -0,0 +1,561 @@
+/*++
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ FtwWorkSpace.c
+
+Abstract:
+
+Revision History
+
+--*/
+
+
+#include <FtwLite.h>
+
+BOOLEAN
+IsValidWorkSpace (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ )
+/*++
+
+Routine Description:
+ Check to see if it is a valid work space.
+
+Arguments:
+ WorkingHeader - Pointer of working block header
+
+Returns:
+ EFI_SUCCESS - The function completed successfully
+ EFI_ABORTED - The function could not complete successfully.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;
+
+ ASSERT (WorkingHeader != NULL);
+ if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {
+ return FALSE;
+ }
+ //
+ // Check signature with gEfiSystemNvDataFvGuid
+ //
+ if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
+ return FALSE;
+ }
+ //
+ // Check the CRC of header
+ //
+ CopyMem (
+ &WorkingBlockHeader,
+ WorkingHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
+ );
+
+ //
+ // Filter out the Crc and State fields
+ //
+ SetMem (
+ &WorkingBlockHeader.Crc,
+ sizeof (UINT32),
+ FTW_ERASED_BYTE
+ );
+ WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;
+ WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;
+
+ //
+ // Calculate the Crc of woking block header
+ //
+ Status = gBS->CalculateCrc32 (
+ (UINT8 *) &WorkingBlockHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ &WorkingBlockHeader.Crc
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {
+ DEBUG ((EFI_D_FTW_LITE, "FtwLite: Work block header CRC check error\n"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+EFI_STATUS
+InitWorkSpaceHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ )
+/*++
+
+Routine Description:
+ Initialize a work space when there is no work space.
+
+Arguments:
+ WorkingHeader - Pointer of working block header
+
+Returns:
+ EFI_SUCCESS - The function completed successfully
+ EFI_ABORTED - The function could not complete successfully.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ ASSERT (WorkingHeader != NULL);
+
+ //
+ // Here using gEfiSystemNvDataFvGuid as the signature.
+ //
+ CopyMem (
+ &WorkingHeader->Signature,
+ &gEfiSystemNvDataFvGuid,
+ sizeof (EFI_GUID)
+ );
+ WorkingHeader->WriteQueueSize = FTW_WORKING_QUEUE_SIZE;
+
+ //
+ // Crc is calculated with all the fields except Crc and STATE
+ //
+ WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
+ WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
+ SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);
+
+ //
+ // Calculate the CRC value
+ //
+ Status = gBS->CalculateCrc32 (
+ (UINT8 *) WorkingHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ &WorkingHeader->Crc
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Restore the WorkingBlockValid flag to VALID state
+ //
+ WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;
+ WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FtwUpdateFvState (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINT8 NewBit
+ )
+/*++
+
+Routine Description:
+ Update a bit of state on a block device. The location of the bit is
+ calculated by the (Lba, Offset, bit). Here bit is determined by the
+ the name of a certain bit.
+
+Arguments:
+ FvBlock - FVB Protocol interface to access SrcBlock and DestBlock
+ Lba - Lba of a block
+ Offset - Offset on the Lba
+ NewBit - New value that will override the old value if it can be change
+
+Returns:
+ EFI_SUCCESS - A state bit has been updated successfully
+ Others - Access block device error.
+
+Notes:
+ Assume all bits of State are inside the same BYTE.
+
+ EFI_ABORTED - Read block fail
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 State;
+ UINTN Length;
+
+ //
+ // Read state from device, assume State is only one byte.
+ //
+ Length = sizeof (UINT8);
+ Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ State ^= FTW_POLARITY_REVERT;
+ State = (UINT8) (State | NewBit);
+ State ^= FTW_POLARITY_REVERT;
+
+ //
+ // Write state back to device
+ //
+ Length = sizeof (UINT8);
+ Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
+
+ return Status;
+}
+
+EFI_STATUS
+FtwGetLastRecord (
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
+ OUT EFI_FTW_LITE_RECORD **FtwLastRecord
+ )
+/*++
+
+Routine Description:
+ Get the last Write record pointer.
+ The last record is the record whose 'complete' state hasn't been set.
+ After all, this header may be a EMPTY header entry for next Allocate.
+
+Arguments:
+ FtwLiteDevice - Private data of this driver
+ FtwLastRecord - Pointer to retrieve the last write record
+
+Returns:
+ EFI_SUCCESS - Get the last write record successfully
+ EFI_ABORTED - The FTW work space is damaged
+
+--*/
+{
+ EFI_FTW_LITE_RECORD *Record;
+
+ Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);
+ while (Record->WriteCompleted == FTW_VALID_STATE) {
+ //
+ // If Offset exceed the FTW work space boudary, return error.
+ //
+ if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {
+ return EFI_ABORTED;
+ }
+
+ Record++;
+ }
+ //
+ // Last write record is found
+ //
+ *FtwLastRecord = Record;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+WorkSpaceRefresh (
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
+ )
+/*++
+
+Routine Description:
+ Read from working block to refresh the work space in memory.
+
+Arguments:
+ FtwLiteDevice - Point to private data of FTW driver
+
+Returns:
+ EFI_SUCCESS - The function completed successfully
+ EFI_ABORTED - The function could not complete successfully.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Length;
+ UINTN Offset;
+ EFI_FTW_LITE_RECORD *Record;
+
+ //
+ // Initialize WorkSpace as FTW_ERASED_BYTE
+ //
+ SetMem (
+ FtwLiteDevice->FtwWorkSpace,
+ FtwLiteDevice->FtwWorkSpaceSize,
+ FTW_ERASED_BYTE
+ );
+
+ //
+ // Read from working block
+ //
+ Length = FtwLiteDevice->FtwWorkSpaceSize;
+ Status = FtwLiteDevice->FtwFvBlock->Read (
+ FtwLiteDevice->FtwFvBlock,
+ FtwLiteDevice->FtwWorkSpaceLba,
+ FtwLiteDevice->FtwWorkSpaceBase,
+ &Length,
+ FtwLiteDevice->FtwWorkSpace
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Refresh the FtwLastRecord
+ //
+ Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
+
+ Record = FtwLiteDevice->FtwLastRecord;
+ Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;
+
+ //
+ // IF work space has error or Record is out of the workspace limit, THEN
+ // call reclaim.
+ //
+ if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {
+ //
+ // reclaim work space in working block.
+ //
+ Status = FtwReclaimWorkSpace (FtwLiteDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status));
+ return EFI_ABORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CleanupWorkSpace (
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
+ IN OUT UINT8 *FtwSpaceBuffer,
+ IN UINTN BufferSize
+ )
+/*++
+
+Routine Description:
+ Reclaim the work space. Get rid of all the completed write records
+ and write records in the Fault Tolerant work space.
+
+Arguments:
+ FtwLiteDevice - Point to private data of FTW driver
+ FtwSpaceBuffer - Buffer to contain the reclaimed clean data
+ BufferSize - Size of the FtwSpaceBuffer
+
+Returns:
+ EFI_SUCCESS - The function completed successfully
+ EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small
+ EFI_ABORTED - The function could not complete successfully.
+
+--*/
+{
+ UINTN Length;
+ EFI_FTW_LITE_RECORD *Record;
+
+ //
+ // To check if the buffer is large enough
+ //
+ Length = FtwLiteDevice->FtwWorkSpaceSize;
+ if (BufferSize < Length) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Clear the content of buffer that will save the new work space data
+ //
+ SetMem (FtwSpaceBuffer, Length, FTW_ERASED_BYTE);
+
+ //
+ // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
+ //
+ CopyMem (
+ FtwSpaceBuffer,
+ FtwLiteDevice->FtwWorkSpaceHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
+ );
+
+ //
+ // Get the last record
+ //
+ Record = FtwLiteDevice->FtwLastRecord;
+ if ((Record != NULL) && (Record->WriteAllocated == FTW_VALID_STATE) && (Record->WriteCompleted != FTW_VALID_STATE)) {
+ CopyMem (
+ (UINT8 *) FtwSpaceBuffer + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ Record,
+ WRITE_TOTAL_SIZE
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FtwReclaimWorkSpace (
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
+ )
+/*++
+
+Routine Description:
+ Reclaim the work space on the working block.
+
+Arguments:
+ FtwLiteDevice - Point to private data of FTW driver
+
+Returns:
+ EFI_SUCCESS - The function completed successfully
+ EFI_OUT_OF_RESOURCES - Allocate memory error
+ EFI_ABORTED - The function could not complete successfully
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 *TempBuffer;
+ UINTN TempBufferSize;
+ UINT8 *Ptr;
+ UINTN Length;
+ UINTN Index;
+ UINTN SpareBufferSize;
+ UINT8 *SpareBuffer;
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
+
+ DEBUG ((EFI_D_FTW_LITE, "FtwLite: start to reclaim work space\n"));
+
+ //
+ // Read all original data from working block to a memory buffer
+ //
+ TempBufferSize = FtwLiteDevice->SpareAreaLength;
+ TempBuffer = AllocateZeroPool (TempBufferSize);
+ if (TempBuffer != NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = TempBuffer;
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwLiteDevice->SizeOfSpareBlock;
+ Status = FtwLiteDevice->FtwFvBlock->Read (
+ FtwLiteDevice->FtwFvBlock,
+ FtwLiteDevice->FtwWorkBlockLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+ //
+ // Clean up the workspace, remove all the completed records.
+ //
+ Ptr = TempBuffer +
+ ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *
+ FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase;
+
+ Status = CleanupWorkSpace (
+ FtwLiteDevice,
+ Ptr,
+ FtwLiteDevice->FtwWorkSpaceSize
+ );
+
+ CopyMem (
+ FtwLiteDevice->FtwWorkSpace,
+ Ptr,
+ FtwLiteDevice->FtwWorkSpaceSize
+ );
+
+ Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
+
+ //
+ // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
+ //
+ WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;
+ WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;
+ WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
+
+ //
+ // Try to keep the content of spare block
+ // Save spare block into a spare backup memory buffer (Sparebuffer)
+ //
+ SpareBufferSize = FtwLiteDevice->SpareAreaLength;
+ SpareBuffer = AllocatePool (SpareBufferSize);
+ if (SpareBuffer == NULL) {
+ FreePool (TempBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwLiteDevice->SizeOfSpareBlock;
+ Status = FtwLiteDevice->FtwBackupFvb->Read (
+ FtwLiteDevice->FtwBackupFvb,
+ FtwLiteDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+ //
+ // Write the memory buffer to spare block
+ //
+ Status = FtwEraseSpareBlock (FtwLiteDevice);
+ Ptr = TempBuffer;
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwLiteDevice->SizeOfSpareBlock;
+ Status = FtwLiteDevice->FtwBackupFvb->Write (
+ FtwLiteDevice->FtwBackupFvb,
+ FtwLiteDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+ //
+ // Free TempBuffer
+ //
+ FreePool (TempBuffer);
+
+ //
+ // Write the spare block to working block
+ //
+ Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return Status;
+ }
+ //
+ // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
+ //
+ Status = FtwEraseSpareBlock (FtwLiteDevice);
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwLiteDevice->SizeOfSpareBlock;
+ Status = FtwLiteDevice->FtwBackupFvb->Write (
+ FtwLiteDevice->FtwBackupFvb,
+ FtwLiteDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+
+ FreePool (SpareBuffer);
+
+ DEBUG ((EFI_D_FTW_LITE, "FtwLite: reclaim work space success\n"));
+
+ return EFI_SUCCESS;
+}