]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwMisc.c
Adjust directory structures.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / FtwMisc.c
diff --git a/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwMisc.c b/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwMisc.c
new file mode 100644 (file)
index 0000000..eb334ea
--- /dev/null
@@ -0,0 +1,530 @@
+/*++\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