summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c')
-rw-r--r--MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c1250
1 files changed, 625 insertions, 625 deletions
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
index fd563643eb..22191e7e2a 100644
--- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
+++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
@@ -1,625 +1,625 @@
-/** @file
-
- Internal functions to operate Working Block Space.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FaultTolerantWrite.h"
-
-EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = { ZERO_GUID, 0, 0, 0, 0, { 0, 0, 0 }, 0 };
-
-/**
- Initialize a local work space header.
-
- Since Signature and WriteQueueSize have been known, Crc can be calculated out,
- then the work space header will be fixed.
-
- @param[in] WorkSpaceLength Length in bytes of the FTW workspace area.
-
-**/
-VOID
-InitializeLocalWorkSpaceHeader (
- IN UINTN WorkSpaceLength
- )
-{
- //
- // Check signature with gEdkiiWorkingBlockSignatureGuid.
- //
- if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {
- //
- // The local work space header has been initialized.
- //
- return;
- }
-
- SetMem (
- &mWorkingBlockHeader,
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
- FTW_ERASED_BYTE
- );
-
- //
- // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
- //
- CopyMem (
- &mWorkingBlockHeader.Signature,
- &gEdkiiWorkingBlockSignatureGuid,
- sizeof (EFI_GUID)
- );
- mWorkingBlockHeader.WriteQueueSize = WorkSpaceLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
-
- //
- // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
- //
-
- //
- // Calculate the Crc of woking block header
- //
- mWorkingBlockHeader.Crc = FtwCalculateCrc32 (
- &mWorkingBlockHeader,
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
- );
-
- mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;
- mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;
-}
-
-/**
- Check to see if it is a valid work space.
-
-
- @param WorkingHeader Pointer of working block header
-
- @retval TRUE The work space is valid.
- @retval FALSE The work space is invalid.
-
-**/
-BOOLEAN
-IsValidWorkSpace (
- IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
- )
-{
- if (WorkingHeader == NULL) {
- return FALSE;
- }
-
- if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {
- return TRUE;
- }
-
- DEBUG ((DEBUG_INFO, "Ftw: Work block header check mismatch\n"));
- return FALSE;
-}
-
-/**
- Initialize a work space when there is no work space.
-
- @param WorkingHeader Pointer of working block header
-
- @retval EFI_SUCCESS The function completed successfully
- @retval EFI_ABORTED The function could not complete successfully.
-
-**/
-EFI_STATUS
-InitWorkSpaceHeader (
- IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
- )
-{
- if (WorkingHeader == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
-
- return EFI_SUCCESS;
-}
-
-/**
- Read work space data from work block or spare block.
-
- @param FvBlock FVB Protocol interface to access the block.
- @param BlockSize The size of the block.
- @param Lba Lba of the block.
- @param Offset The offset within the block.
- @param Length The number of bytes to read from the block.
- @param Buffer The data is read.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ABORTED The function could not complete successfully.
-
-**/
-EFI_STATUS
-ReadWorkSpaceData (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
- IN UINTN BlockSize,
- IN EFI_LBA Lba,
- IN UINTN Offset,
- IN UINTN Length,
- OUT UINT8 *Buffer
- )
-{
- EFI_STATUS Status;
- UINT8 *Ptr;
- UINTN MyLength;
-
- //
- // Calculate the real Offset and Lba to write.
- //
- while (Offset >= BlockSize) {
- Offset -= BlockSize;
- Lba++;
- }
-
- Ptr = Buffer;
- while (Length > 0) {
- if ((Offset + Length) > BlockSize) {
- MyLength = BlockSize - Offset;
- } else {
- MyLength = Length;
- }
-
- Status = FvBlock->Read (
- FvBlock,
- Lba,
- Offset,
- &MyLength,
- Ptr
- );
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
-
- Offset = 0;
- Length -= MyLength;
- Ptr += MyLength;
- Lba++;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Write work space data to work block.
-
- @param FvBlock FVB Protocol interface to access the block.
- @param BlockSize The size of the block.
- @param Lba Lba of the block.
- @param Offset The offset within the block to place the data.
- @param Length The number of bytes to write to the block.
- @param Buffer The data to write.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ABORTED The function could not complete successfully.
-
-**/
-EFI_STATUS
-WriteWorkSpaceData (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
- IN UINTN BlockSize,
- IN EFI_LBA Lba,
- IN UINTN Offset,
- IN UINTN Length,
- IN UINT8 *Buffer
- )
-{
- EFI_STATUS Status;
- UINT8 *Ptr;
- UINTN MyLength;
-
- //
- // Calculate the real Offset and Lba to write.
- //
- while (Offset >= BlockSize) {
- Offset -= BlockSize;
- Lba++;
- }
-
- Ptr = Buffer;
- while (Length > 0) {
- if ((Offset + Length) > BlockSize) {
- MyLength = BlockSize - Offset;
- } else {
- MyLength = Length;
- }
-
- Status = FvBlock->Write (
- FvBlock,
- Lba,
- Offset,
- &MyLength,
- Ptr
- );
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
-
- Offset = 0;
- Length -= MyLength;
- Ptr += MyLength;
- Lba++;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Read from working block to refresh the work space in memory.
-
- @param FtwDevice Point to private data of FTW driver
-
- @retval EFI_SUCCESS The function completed successfully
- @retval EFI_ABORTED The function could not complete successfully.
-
-**/
-EFI_STATUS
-WorkSpaceRefresh (
- IN EFI_FTW_DEVICE *FtwDevice
- )
-{
- EFI_STATUS Status;
- UINTN RemainingSpaceSize;
-
- //
- // Initialize WorkSpace as FTW_ERASED_BYTE
- //
- SetMem (
- FtwDevice->FtwWorkSpace,
- FtwDevice->FtwWorkSpaceSize,
- FTW_ERASED_BYTE
- );
-
- //
- // Read from working block
- //
- Status = ReadWorkSpaceData (
- FtwDevice->FtwFvBlock,
- FtwDevice->WorkBlockSize,
- FtwDevice->FtwWorkSpaceLba,
- FtwDevice->FtwWorkSpaceBase,
- FtwDevice->FtwWorkSpaceSize,
- FtwDevice->FtwWorkSpace
- );
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
-
- //
- // Refresh the FtwLastWriteHeader
- //
- Status = FtwGetLastWriteHeader (
- FtwDevice->FtwWorkSpaceHeader,
- FtwDevice->FtwWorkSpaceSize,
- &FtwDevice->FtwLastWriteHeader
- );
- RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN)FtwDevice->FtwLastWriteHeader - (UINTN)FtwDevice->FtwWorkSpace);
- DEBUG ((DEBUG_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));
- //
- // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
- // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
- // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
- // it needs to reclaim work space.
- //
- if (EFI_ERROR (Status) || (RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD))) {
- //
- // reclaim work space in working block.
- //
- Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Ftw: Reclaim workspace - %r\n", Status));
- return EFI_ABORTED;
- }
-
- //
- // Read from working block again
- //
- Status = ReadWorkSpaceData (
- FtwDevice->FtwFvBlock,
- FtwDevice->WorkBlockSize,
- FtwDevice->FtwWorkSpaceLba,
- FtwDevice->FtwWorkSpaceBase,
- FtwDevice->FtwWorkSpaceSize,
- FtwDevice->FtwWorkSpace
- );
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
-
- Status = FtwGetLastWriteHeader (
- FtwDevice->FtwWorkSpaceHeader,
- FtwDevice->FtwWorkSpaceSize,
- &FtwDevice->FtwLastWriteHeader
- );
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
- }
-
- //
- // Refresh the FtwLastWriteRecord
- //
- Status = FtwGetLastWriteRecord (
- FtwDevice->FtwLastWriteHeader,
- &FtwDevice->FtwLastWriteRecord
- );
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Reclaim the work space on the working block.
-
- @param FtwDevice Point to private data of FTW driver
- @param PreserveRecord Whether to preserve the working record is needed
-
- @retval EFI_SUCCESS The function completed successfully
- @retval EFI_OUT_OF_RESOURCES Allocate memory error
- @retval EFI_ABORTED The function could not complete successfully
-
-**/
-EFI_STATUS
-FtwReclaimWorkSpace (
- IN EFI_FTW_DEVICE *FtwDevice,
- IN BOOLEAN PreserveRecord
- )
-{
- EFI_STATUS Status;
- UINTN Length;
- EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
- UINT8 *TempBuffer;
- UINTN TempBufferSize;
- UINTN SpareBufferSize;
- UINT8 *SpareBuffer;
- EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
- UINTN Index;
- UINT8 *Ptr;
- EFI_LBA WorkSpaceLbaOffset;
-
- DEBUG ((DEBUG_INFO, "Ftw: start to reclaim work space\n"));
-
- WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
-
- //
- // Read all original data from working block to a memory buffer
- //
- TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;
- TempBuffer = AllocateZeroPool (TempBufferSize);
- if (TempBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Ptr = TempBuffer;
- for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {
- Length = FtwDevice->WorkBlockSize;
- Status = FtwDevice->FtwFvBlock->Read (
- FtwDevice->FtwFvBlock,
- FtwDevice->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)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
- FtwDevice->FtwWorkSpaceBase;
-
- //
- // Clear the content of buffer that will save the new work space data
- //
- SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);
-
- //
- // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
- //
- CopyMem (
- Ptr,
- FtwDevice->FtwWorkSpaceHeader,
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
- );
- if (PreserveRecord) {
- //
- // Get the last record following the header,
- //
- Status = FtwGetLastWriteHeader (
- FtwDevice->FtwWorkSpaceHeader,
- FtwDevice->FtwWorkSpaceSize,
- &FtwDevice->FtwLastWriteHeader
- );
- Header = FtwDevice->FtwLastWriteHeader;
- if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {
- CopyMem (
- Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
- FtwDevice->FtwLastWriteHeader,
- FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)
- );
- }
- }
-
- CopyMem (
- FtwDevice->FtwWorkSpace,
- Ptr,
- FtwDevice->FtwWorkSpaceSize
- );
-
- FtwGetLastWriteHeader (
- FtwDevice->FtwWorkSpaceHeader,
- FtwDevice->FtwWorkSpaceSize,
- &FtwDevice->FtwLastWriteHeader
- );
-
- FtwGetLastWriteRecord (
- FtwDevice->FtwLastWriteHeader,
- &FtwDevice->FtwLastWriteRecord
- );
-
- //
- // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
- //
- WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(TempBuffer +
- (UINTN)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
- FtwDevice->FtwWorkSpaceBase);
- 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 = FtwDevice->SpareAreaLength;
- SpareBuffer = AllocatePool (SpareBufferSize);
- if (SpareBuffer == NULL) {
- FreePool (TempBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
-
- Ptr = SpareBuffer;
- for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
- Length = FtwDevice->SpareBlockSize;
- Status = FtwDevice->FtwBackupFvb->Read (
- FtwDevice->FtwBackupFvb,
- FtwDevice->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 (FtwDevice);
- if (EFI_ERROR (Status)) {
- FreePool (TempBuffer);
- FreePool (SpareBuffer);
- return EFI_ABORTED;
- }
-
- Ptr = TempBuffer;
- for (Index = 0; TempBufferSize > 0; Index += 1) {
- if (TempBufferSize > FtwDevice->SpareBlockSize) {
- Length = FtwDevice->SpareBlockSize;
- } else {
- Length = TempBufferSize;
- }
-
- Status = FtwDevice->FtwBackupFvb->Write (
- FtwDevice->FtwBackupFvb,
- FtwDevice->FtwSpareLba + Index,
- 0,
- &Length,
- Ptr
- );
- if (EFI_ERROR (Status)) {
- FreePool (TempBuffer);
- FreePool (SpareBuffer);
- return EFI_ABORTED;
- }
-
- Ptr += Length;
- TempBufferSize -= Length;
- }
-
- //
- // Free TempBuffer
- //
- FreePool (TempBuffer);
-
- //
- // Set the WorkingBlockValid in spare block
- //
- Status = FtwUpdateFvState (
- FtwDevice->FtwBackupFvb,
- FtwDevice->SpareBlockSize,
- FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
- FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),
- WORKING_BLOCK_VALID
- );
- if (EFI_ERROR (Status)) {
- FreePool (SpareBuffer);
- return EFI_ABORTED;
- }
-
- //
- // Before erase the working block, set WorkingBlockInvalid in working block.
- //
- // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
- // WorkingBlockInvalid);
- //
- Status = FtwUpdateFvState (
- FtwDevice->FtwFvBlock,
- FtwDevice->WorkBlockSize,
- FtwDevice->FtwWorkSpaceLba,
- FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
- WORKING_BLOCK_INVALID
- );
- if (EFI_ERROR (Status)) {
- FreePool (SpareBuffer);
- return EFI_ABORTED;
- }
-
- FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
-
- //
- // Write the spare block to working block
- //
- Status = FlushSpareBlockToWorkingBlock (FtwDevice);
- if (EFI_ERROR (Status)) {
- FreePool (SpareBuffer);
- return Status;
- }
-
- //
- // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
- //
- Status = FtwEraseSpareBlock (FtwDevice);
- if (EFI_ERROR (Status)) {
- FreePool (SpareBuffer);
- return EFI_ABORTED;
- }
-
- Ptr = SpareBuffer;
- for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
- Length = FtwDevice->SpareBlockSize;
- Status = FtwDevice->FtwBackupFvb->Write (
- FtwDevice->FtwBackupFvb,
- FtwDevice->FtwSpareLba + Index,
- 0,
- &Length,
- Ptr
- );
- if (EFI_ERROR (Status)) {
- FreePool (SpareBuffer);
- return EFI_ABORTED;
- }
-
- Ptr += Length;
- }
-
- FreePool (SpareBuffer);
-
- DEBUG ((DEBUG_INFO, "Ftw: reclaim work space successfully\n"));
-
- return EFI_SUCCESS;
-}
+/** @file
+
+ Internal functions to operate Working Block Space.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FaultTolerantWrite.h"
+
+EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = { ZERO_GUID, 0, 0, 0, 0, { 0, 0, 0 }, 0 };
+
+/**
+ Initialize a local work space header.
+
+ Since Signature and WriteQueueSize have been known, Crc can be calculated out,
+ then the work space header will be fixed.
+
+ @param[in] WorkSpaceLength Length in bytes of the FTW workspace area.
+
+**/
+VOID
+InitializeLocalWorkSpaceHeader (
+ IN UINTN WorkSpaceLength
+ )
+{
+ //
+ // Check signature with gEdkiiWorkingBlockSignatureGuid.
+ //
+ if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {
+ //
+ // The local work space header has been initialized.
+ //
+ return;
+ }
+
+ SetMem (
+ &mWorkingBlockHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ FTW_ERASED_BYTE
+ );
+
+ //
+ // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
+ //
+ CopyMem (
+ &mWorkingBlockHeader.Signature,
+ &gEdkiiWorkingBlockSignatureGuid,
+ sizeof (EFI_GUID)
+ );
+ mWorkingBlockHeader.WriteQueueSize = WorkSpaceLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
+
+ //
+ // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
+ //
+
+ //
+ // Calculate the Crc of woking block header
+ //
+ mWorkingBlockHeader.Crc = FtwCalculateCrc32 (
+ &mWorkingBlockHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
+ );
+
+ mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;
+ mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;
+}
+
+/**
+ Check to see if it is a valid work space.
+
+
+ @param WorkingHeader Pointer of working block header
+
+ @retval TRUE The work space is valid.
+ @retval FALSE The work space is invalid.
+
+**/
+BOOLEAN
+IsValidWorkSpace (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ )
+{
+ if (WorkingHeader == NULL) {
+ return FALSE;
+ }
+
+ if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {
+ return TRUE;
+ }
+
+ DEBUG ((DEBUG_INFO, "Ftw: Work block header check mismatch\n"));
+ return FALSE;
+}
+
+/**
+ Initialize a work space when there is no work space.
+
+ @param WorkingHeader Pointer of working block header
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+InitWorkSpaceHeader (
+ IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
+ )
+{
+ if (WorkingHeader == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read work space data from work block or spare block.
+
+ @param FvBlock FVB Protocol interface to access the block.
+ @param BlockSize The size of the block.
+ @param Lba Lba of the block.
+ @param Offset The offset within the block.
+ @param Length The number of bytes to read from the block.
+ @param Buffer The data is read.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+ReadWorkSpaceData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINTN MyLength;
+
+ //
+ // Calculate the real Offset and Lba to write.
+ //
+ while (Offset >= BlockSize) {
+ Offset -= BlockSize;
+ Lba++;
+ }
+
+ Ptr = Buffer;
+ while (Length > 0) {
+ if ((Offset + Length) > BlockSize) {
+ MyLength = BlockSize - Offset;
+ } else {
+ MyLength = Length;
+ }
+
+ Status = FvBlock->Read (
+ FvBlock,
+ Lba,
+ Offset,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Offset = 0;
+ Length -= MyLength;
+ Ptr += MyLength;
+ Lba++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write work space data to work block.
+
+ @param FvBlock FVB Protocol interface to access the block.
+ @param BlockSize The size of the block.
+ @param Lba Lba of the block.
+ @param Offset The offset within the block to place the data.
+ @param Length The number of bytes to write to the block.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+WriteWorkSpaceData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
+ IN UINTN BlockSize,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINTN MyLength;
+
+ //
+ // Calculate the real Offset and Lba to write.
+ //
+ while (Offset >= BlockSize) {
+ Offset -= BlockSize;
+ Lba++;
+ }
+
+ Ptr = Buffer;
+ while (Length > 0) {
+ if ((Offset + Length) > BlockSize) {
+ MyLength = BlockSize - Offset;
+ } else {
+ MyLength = Length;
+ }
+
+ Status = FvBlock->Write (
+ FvBlock,
+ Lba,
+ Offset,
+ &MyLength,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Offset = 0;
+ Length -= MyLength;
+ Ptr += MyLength;
+ Lba++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read from working block to refresh the work space in memory.
+
+ @param FtwDevice Point to private data of FTW driver
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+WorkSpaceRefresh (
+ IN EFI_FTW_DEVICE *FtwDevice
+ )
+{
+ EFI_STATUS Status;
+ UINTN RemainingSpaceSize;
+
+ //
+ // Initialize WorkSpace as FTW_ERASED_BYTE
+ //
+ SetMem (
+ FtwDevice->FtwWorkSpace,
+ FtwDevice->FtwWorkSpaceSize,
+ FTW_ERASED_BYTE
+ );
+
+ //
+ // Read from working block
+ //
+ Status = ReadWorkSpaceData (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase,
+ FtwDevice->FtwWorkSpaceSize,
+ FtwDevice->FtwWorkSpace
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Refresh the FtwLastWriteHeader
+ //
+ Status = FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+ RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN)FtwDevice->FtwLastWriteHeader - (UINTN)FtwDevice->FtwWorkSpace);
+ DEBUG ((DEBUG_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));
+ //
+ // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
+ // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
+ // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
+ // it needs to reclaim work space.
+ //
+ if (EFI_ERROR (Status) || (RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD))) {
+ //
+ // reclaim work space in working block.
+ //
+ Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Ftw: Reclaim workspace - %r\n", Status));
+ return EFI_ABORTED;
+ }
+
+ //
+ // Read from working block again
+ //
+ Status = ReadWorkSpaceData (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase,
+ FtwDevice->FtwWorkSpaceSize,
+ FtwDevice->FtwWorkSpace
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ Status = FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Refresh the FtwLastWriteRecord
+ //
+ Status = FtwGetLastWriteRecord (
+ FtwDevice->FtwLastWriteHeader,
+ &FtwDevice->FtwLastWriteRecord
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reclaim the work space on the working block.
+
+ @param FtwDevice Point to private data of FTW driver
+ @param PreserveRecord Whether to preserve the working record is needed
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Allocate memory error
+ @retval EFI_ABORTED The function could not complete successfully
+
+**/
+EFI_STATUS
+FtwReclaimWorkSpace (
+ IN EFI_FTW_DEVICE *FtwDevice,
+ IN BOOLEAN PreserveRecord
+ )
+{
+ EFI_STATUS Status;
+ UINTN Length;
+ EFI_FAULT_TOLERANT_WRITE_HEADER *Header;
+ UINT8 *TempBuffer;
+ UINTN TempBufferSize;
+ UINTN SpareBufferSize;
+ UINT8 *SpareBuffer;
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
+ UINTN Index;
+ UINT8 *Ptr;
+ EFI_LBA WorkSpaceLbaOffset;
+
+ DEBUG ((DEBUG_INFO, "Ftw: start to reclaim work space\n"));
+
+ WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
+
+ //
+ // Read all original data from working block to a memory buffer
+ //
+ TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;
+ TempBuffer = AllocateZeroPool (TempBufferSize);
+ if (TempBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = TempBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {
+ Length = FtwDevice->WorkBlockSize;
+ Status = FtwDevice->FtwFvBlock->Read (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->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)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
+ FtwDevice->FtwWorkSpaceBase;
+
+ //
+ // Clear the content of buffer that will save the new work space data
+ //
+ SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);
+
+ //
+ // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
+ //
+ CopyMem (
+ Ptr,
+ FtwDevice->FtwWorkSpaceHeader,
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
+ );
+ if (PreserveRecord) {
+ //
+ // Get the last record following the header,
+ //
+ Status = FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+ Header = FtwDevice->FtwLastWriteHeader;
+ if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {
+ CopyMem (
+ Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
+ FtwDevice->FtwLastWriteHeader,
+ FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)
+ );
+ }
+ }
+
+ CopyMem (
+ FtwDevice->FtwWorkSpace,
+ Ptr,
+ FtwDevice->FtwWorkSpaceSize
+ );
+
+ FtwGetLastWriteHeader (
+ FtwDevice->FtwWorkSpaceHeader,
+ FtwDevice->FtwWorkSpaceSize,
+ &FtwDevice->FtwLastWriteHeader
+ );
+
+ FtwGetLastWriteRecord (
+ FtwDevice->FtwLastWriteHeader,
+ &FtwDevice->FtwLastWriteRecord
+ );
+
+ //
+ // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
+ //
+ WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(TempBuffer +
+ (UINTN)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
+ FtwDevice->FtwWorkSpaceBase);
+ 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 = FtwDevice->SpareAreaLength;
+ SpareBuffer = AllocatePool (SpareBufferSize);
+ if (SpareBuffer == NULL) {
+ FreePool (TempBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Read (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->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 (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr = TempBuffer;
+ for (Index = 0; TempBufferSize > 0; Index += 1) {
+ if (TempBufferSize > FtwDevice->SpareBlockSize) {
+ Length = FtwDevice->SpareBlockSize;
+ } else {
+ Length = TempBufferSize;
+ }
+
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TempBuffer);
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ TempBufferSize -= Length;
+ }
+
+ //
+ // Free TempBuffer
+ //
+ FreePool (TempBuffer);
+
+ //
+ // Set the WorkingBlockValid in spare block
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->SpareBlockSize,
+ FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
+ FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_VALID
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Before erase the working block, set WorkingBlockInvalid in working block.
+ //
+ // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
+ // WorkingBlockInvalid);
+ //
+ Status = FtwUpdateFvState (
+ FtwDevice->FtwFvBlock,
+ FtwDevice->WorkBlockSize,
+ FtwDevice->FtwWorkSpaceLba,
+ FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
+ WORKING_BLOCK_INVALID
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
+
+ //
+ // Write the spare block to working block
+ //
+ Status = FlushSpareBlockToWorkingBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return Status;
+ }
+
+ //
+ // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
+ //
+ Status = FtwEraseSpareBlock (FtwDevice);
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr = SpareBuffer;
+ for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
+ Length = FtwDevice->SpareBlockSize;
+ Status = FtwDevice->FtwBackupFvb->Write (
+ FtwDevice->FtwBackupFvb,
+ FtwDevice->FtwSpareLba + Index,
+ 0,
+ &Length,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (SpareBuffer);
+ return EFI_ABORTED;
+ }
+
+ Ptr += Length;
+ }
+
+ FreePool (SpareBuffer);
+
+ DEBUG ((DEBUG_INFO, "Ftw: reclaim work space successfully\n"));
+
+ return EFI_SUCCESS;
+}