--- /dev/null
+/*++\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
+Module Name:\r
+\r
+ FtwMisc.c\r
+ \r
+Abstract:\r
+ \r
+ Internal functions to support fault tolerant write.\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include <FtwLite.h>\r
+\r
+BOOLEAN\r
+IsErasedFlashBuffer (\r
+ IN BOOLEAN Polarity,\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check whether a flash buffer is erased.\r
+\r
+Arguments:\r
+\r
+ Polarity - All 1 or all 0\r
+ Buffer - Buffer to check\r
+ BufferSize - Size of the buffer\r
+\r
+Returns:\r
+\r
+ Erased or not.\r
+\r
+--*/\r
+{\r
+ UINT8 ErasedValue;\r
+ UINT8 *Ptr;\r
+\r
+ if (Polarity) {\r
+ ErasedValue = 0xFF;\r
+ } else {\r
+ ErasedValue = 0;\r
+ }\r
+\r
+ Ptr = Buffer;\r
+ while (BufferSize--) {\r
+ if (*Ptr++ != ErasedValue) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+EFI_STATUS\r
+FtwEraseBlock (\r
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+ EFI_LBA Lba\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ To Erase one block. The size is FTW_BLOCK_SIZE\r
+\r
+Arguments:\r
+ FtwLiteDevice - Calling context\r
+ FvBlock - FVB Protocol interface\r
+ Lba - Lba of the firmware block\r
+\r
+Returns:\r
+ EFI_SUCCESS - Block LBA is Erased successfully\r
+ Others - Error occurs\r
+\r
+--*/\r
+{\r
+ return FvBlock->EraseBlocks (\r
+ FvBlock,\r
+ Lba,\r
+ FtwLiteDevice->NumberOfSpareBlock,\r
+ EFI_LBA_LIST_TERMINATOR\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+FtwEraseSpareBlock (\r
+ IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Erase spare block.\r
+\r
+Arguments:\r
+\r
+ FtwLiteDevice - Calling context\r
+\r
+Returns:\r
+\r
+ Status code\r
+\r
+--*/\r
+{\r
+ return FtwLiteDevice->FtwBackupFvb->EraseBlocks (\r
+ FtwLiteDevice->FtwBackupFvb,\r
+ FtwLiteDevice->FtwSpareLba,\r
+ FtwLiteDevice->NumberOfSpareBlock,\r
+ EFI_LBA_LIST_TERMINATOR\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+FtwGetFvbByHandle (\r
+ IN EFI_HANDLE FvBlockHandle,\r
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Retrive the proper FVB protocol interface by HANDLE.\r
+\r
+Arguments:\r
+ FvBlockHandle - The handle of FVB protocol that provides services for \r
+ reading, writing, and erasing the target block.\r
+ FvBlock - The interface of FVB protocol\r
+\r
+Returns:\r
+ EFI_SUCCESS - The function completed successfully\r
+ EFI_ABORTED - The function could not complete successfully\r
+--*/\r
+{\r
+ //\r
+ // To get the FVB protocol interface on the handle\r
+ //\r
+ return gBS->HandleProtocol (\r
+ FvBlockHandle,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID **) FvBlock\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+GetFvbByAddress (\r
+ IN EFI_PHYSICAL_ADDRESS Address,\r
+ OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get firmware block by address.\r
+\r
+Arguments:\r
+\r
+ Address - Address specified the block\r
+ FvBlock - The block caller wanted\r
+\r
+Returns:\r
+\r
+ Status code\r
+\r
+ EFI_NOT_FOUND - Block not found\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+\r
+ *FvBlock = NULL;\r
+ //\r
+ // Locate all handles of Fvb protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Search all FVB until find the right one\r
+ //\r
+ for (Index = 0; Index < HandleCount; Index += 1) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID **) &Fvb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_NOT_FOUND;\r
+ break;\r
+ }\r
+ //\r
+ // Compare the address and select the right one\r
+ //\r
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+ if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {\r
+ *FvBlock = Fvb;\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HandleBuffer);\r
+ return Status;\r
+}\r
+\r
+BOOLEAN\r
+IsInWorkingBlock (\r
+ EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+ EFI_LBA Lba\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Is it in working block?\r
+\r
+Arguments:\r
+\r
+ FtwLiteDevice - Calling context\r
+ FvBlock - Fvb protocol instance\r
+ Lba - The block specified\r
+\r
+Returns:\r
+\r
+ In working block or not\r
+\r
+--*/\r
+{\r
+ //\r
+ // If matching the following condition, the target block is in working block.\r
+ // 1. Target block is on the FV of working block (Using the same FVB protocol instance).\r
+ // 2. Lba falls into the range of working block.\r
+ //\r
+ return (BOOLEAN)\r
+ (\r
+ (FvBlock == FtwLiteDevice->FtwFvBlock) &&\r
+ (Lba >= FtwLiteDevice->FtwWorkBlockLba) &&\r
+ (Lba <= FtwLiteDevice->FtwWorkSpaceLba)\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+FlushSpareBlockToTargetBlock (\r
+ EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+ EFI_LBA Lba\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.\r
+ Spare block is accessed by FTW backup FVB protocol interface. LBA is \r
+ FtwLiteDevice->FtwSpareLba.\r
+ Target block is accessed by FvBlock protocol interface. LBA is Lba.\r
+\r
+Arguments:\r
+ FtwLiteDevice - The private data of FTW_LITE driver\r
+ FvBlock - FVB Protocol interface to access target block\r
+ Lba - Lba of the target block\r
+\r
+Returns:\r
+ EFI_SUCCESS - Spare block content is copied to target block\r
+ EFI_INVALID_PARAMETER - Input parameter error\r
+ EFI_OUT_OF_RESOURCES - Allocate memory error\r
+ EFI_ABORTED - The function could not complete successfully\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Length;\r
+ UINT8 *Buffer;\r
+ UINTN Count;\r
+ UINT8 *Ptr;\r
+ UINTN Index;\r
+\r
+ if ((FtwLiteDevice == NULL) || (FvBlock == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Allocate a memory buffer\r
+ //\r
+ Length = FtwLiteDevice->SpareAreaLength;\r
+ Buffer = AllocatePool (Length);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Read all content of spare block to memory buffer\r
+ //\r
+ Ptr = Buffer;\r
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+ Count = FtwLiteDevice->SizeOfSpareBlock;\r
+ Status = FtwLiteDevice->FtwBackupFvb->Read (\r
+ FtwLiteDevice->FtwBackupFvb,\r
+ FtwLiteDevice->FtwSpareLba + Index,\r
+ 0,\r
+ &Count,\r
+ Ptr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Buffer);\r
+ return Status;\r
+ }\r
+\r
+ Ptr += Count;\r
+ }\r
+ //\r
+ // Erase the target block\r
+ //\r
+ Status = FtwEraseBlock (FtwLiteDevice, FvBlock, Lba);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Buffer);\r
+ return EFI_ABORTED;\r
+ }\r
+ //\r
+ // Write memory buffer to block, using the FvbBlock protocol interface\r
+ //\r
+ Ptr = Buffer;\r
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+ Count = FtwLiteDevice->SizeOfSpareBlock;\r
+ Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status));\r
+ FreePool (Buffer);\r
+ return Status;\r
+ }\r
+\r
+ Ptr += Count;\r
+ }\r
+\r
+ FreePool (Buffer);\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FlushSpareBlockToWorkingBlock (\r
+ EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.\r
+ Spare block is accessed by FTW backup FVB protocol interface. LBA is \r
+ FtwLiteDevice->FtwSpareLba.\r
+ Working block is accessed by FTW working FVB protocol interface. LBA is \r
+ FtwLiteDevice->FtwWorkBlockLba.\r
+\r
+Arguments:\r
+ FtwLiteDevice - The private data of FTW_LITE driver\r
+\r
+Returns:\r
+ EFI_SUCCESS - Spare block content is copied to target block\r
+ EFI_OUT_OF_RESOURCES - Allocate memory error\r
+ EFI_ABORTED - The function could not complete successfully\r
+\r
+Notes:\r
+ Since the working block header is important when FTW initializes, the \r
+ state of the operation should be handled carefully. The Crc value is \r
+ calculated without STATE element. \r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Length;\r
+ UINT8 *Buffer;\r
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
+ EFI_LBA WorkSpaceLbaOffset;\r
+ UINTN Count;\r
+ UINT8 *Ptr;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Allocate a memory buffer\r
+ //\r
+ Length = FtwLiteDevice->SpareAreaLength;\r
+ Buffer = AllocatePool (Length);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // To guarantee that the WorkingBlockValid is set on spare block\r
+ //\r
+ WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;\r
+ FtwUpdateFvState (\r
+ FtwLiteDevice->FtwBackupFvb,\r
+ FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
+ FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
+ WORKING_BLOCK_VALID\r
+ );\r
+ //\r
+ // Read from spare block to memory buffer\r
+ //\r
+ Ptr = Buffer;\r
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+ Count = FtwLiteDevice->SizeOfSpareBlock;\r
+ Status = FtwLiteDevice->FtwBackupFvb->Read (\r
+ FtwLiteDevice->FtwBackupFvb,\r
+ FtwLiteDevice->FtwSpareLba + Index,\r
+ 0,\r
+ &Count,\r
+ Ptr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Buffer);\r
+ return Status;\r
+ }\r
+\r
+ Ptr += Count;\r
+ }\r
+ //\r
+ // Clear the CRC and STATE, copy data from spare to working block.\r
+ //\r
+ WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase);\r
+ InitWorkSpaceHeader (WorkingBlockHeader);\r
+ WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
+ WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
+\r
+ //\r
+ // target block is working block, then\r
+ // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER\r
+ // before erase the working block.\r
+ //\r
+ // Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
+ // WorkingBlockInvalid);\r
+ // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).\r
+ //\r
+ Status = FtwUpdateFvState (\r
+ FtwLiteDevice->FtwFvBlock,\r
+ FtwLiteDevice->FtwWorkSpaceLba,\r
+ FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
+ WORKING_BLOCK_INVALID\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Buffer);\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;\r
+\r
+ //\r
+ // Erase the working block\r
+ //\r
+ Status = FtwEraseBlock (\r
+ FtwLiteDevice,\r
+ FtwLiteDevice->FtwFvBlock,\r
+ FtwLiteDevice->FtwWorkBlockLba\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Buffer);\r
+ return EFI_ABORTED;\r
+ }\r
+ //\r
+ // Write memory buffer to working block, using the FvbBlock protocol interface\r
+ //\r
+ Ptr = Buffer;\r
+ for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
+ Count = FtwLiteDevice->SizeOfSpareBlock;\r
+ Status = FtwLiteDevice->FtwFvBlock->Write (\r
+ FtwLiteDevice->FtwFvBlock,\r
+ FtwLiteDevice->FtwWorkBlockLba + Index,\r
+ 0,\r
+ &Count,\r
+ Ptr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status));\r
+ FreePool (Buffer);\r
+ return Status;\r
+ }\r
+\r
+ Ptr += Count;\r
+ }\r
+ //\r
+ // Since the memory buffer will not be used, free memory Buffer.\r
+ //\r
+ FreePool (Buffer);\r
+\r
+ //\r
+ // Update the VALID of the working block\r
+ //\r
+ // Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
+ // WorkingBlockValid);\r
+ // Hardcode offset sizeof(EFI_GUID)+sizeof(UINT32), to skip Signature and Crc\r
+ //\r
+ Status = FtwUpdateFvState (\r
+ FtwLiteDevice->FtwFvBlock,\r
+ FtwLiteDevice->FtwWorkSpaceLba,\r
+ FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
+ WORKING_BLOCK_VALID\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r