]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
MdeModulePkg/FaultTolerantWriteDxe: factor out boot service accesses
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / UpdateWorkingBlock.c
index 4c658b2977c4230def1d70df54b5fba390ab7765..d09e9719cf0586e1bfaec06298213fafb198cc78 100644 (file)
@@ -2,14 +2,14 @@
 \r
    Internal functions to operate Working Block Space.\r
 \r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
-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
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+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
@@ -29,8 +29,6 @@ InitializeLocalWorkSpaceHeader (
   VOID\r
   )\r
 {\r
-  EFI_STATUS                              Status;\r
-\r
   //\r
   // Check signature with gEdkiiWorkingBlockSignatureGuid.\r
   //\r
@@ -55,7 +53,7 @@ InitializeLocalWorkSpaceHeader (
     &gEdkiiWorkingBlockSignatureGuid,\r
     sizeof (EFI_GUID)\r
     );\r
-  mWorkingBlockHeader.WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
+  mWorkingBlockHeader.WriteQueueSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
 \r
   //\r
   // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.\r
@@ -64,12 +62,8 @@ InitializeLocalWorkSpaceHeader (
   //\r
   // Calculate the Crc of woking block header\r
   //\r
-  Status = gBS->CalculateCrc32 (\r
-                  &mWorkingBlockHeader,\r
-                  sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
-                  &mWorkingBlockHeader.Crc\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
+  mWorkingBlockHeader.Crc = FtwCalculateCrc32 (&mWorkingBlockHeader,\r
+                              sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
 \r
   mWorkingBlockHeader.WorkingBlockValid    = FTW_VALID_STATE;\r
   mWorkingBlockHeader.WorkingBlockInvalid  = FTW_INVALID_STATE;\r
@@ -98,7 +92,7 @@ IsValidWorkSpace (
     return TRUE;\r
   }\r
 \r
-  DEBUG ((EFI_D_ERROR, "Ftw: Work block header check error\n"));\r
+  DEBUG ((EFI_D_INFO, "Ftw: Work block header check mismatch\n"));\r
   return FALSE;\r
 }\r
 \r
@@ -125,6 +119,131 @@ InitWorkSpaceHeader (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Read work space data from work block or spare block.\r
+\r
+  @param FvBlock        FVB Protocol interface to access the block.\r
+  @param BlockSize      The size of the block.\r
+  @param Lba            Lba of the block.\r
+  @param Offset         The offset within the block.\r
+  @param Length         The number of bytes to read from the block.\r
+  @param Buffer         The data is read.\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
+ReadWorkSpaceData (\r
+  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+  IN UINTN                              BlockSize,\r
+  IN EFI_LBA                            Lba,\r
+  IN UINTN                              Offset,\r
+  IN UINTN                              Length,\r
+  OUT UINT8                             *Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 *Ptr;\r
+  UINTN                 MyLength;\r
+\r
+  //\r
+  // Calculate the real Offset and Lba to write.\r
+  //\r
+  while (Offset >= BlockSize) {\r
+    Offset -= BlockSize;\r
+    Lba++;\r
+  }\r
+\r
+  Ptr = Buffer;\r
+  while (Length > 0) {\r
+    if ((Offset + Length) > BlockSize) {\r
+      MyLength = BlockSize - Offset;\r
+    } else {\r
+      MyLength = Length;\r
+    }\r
+\r
+    Status = FvBlock->Read (\r
+                        FvBlock,\r
+                        Lba,\r
+                        Offset,\r
+                        &MyLength,\r
+                        Ptr\r
+                        );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_ABORTED;\r
+    }\r
+    Offset = 0;\r
+    Length -= MyLength;\r
+    Ptr += MyLength;\r
+    Lba++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write work space data to work block.\r
+\r
+  @param FvBlock        FVB Protocol interface to access the block.\r
+  @param BlockSize      The size of the block.\r
+  @param Lba            Lba of the block.\r
+  @param Offset         The offset within the block to place the data.\r
+  @param Length         The number of bytes to write to the block.\r
+  @param Buffer         The data to write.\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
+WriteWorkSpaceData (\r
+  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
+  IN UINTN                              BlockSize,\r
+  IN EFI_LBA                            Lba,\r
+  IN UINTN                              Offset,\r
+  IN UINTN                              Length,\r
+  IN UINT8                              *Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 *Ptr;\r
+  UINTN                 MyLength;\r
+\r
+  //\r
+  // Calculate the real Offset and Lba to write.\r
+  //\r
+  while (Offset >= BlockSize) {\r
+    Offset -= BlockSize;\r
+    Lba++;\r
+  }\r
+\r
+  Ptr = Buffer;\r
+  while (Length > 0) {\r
+    if ((Offset + Length) > BlockSize) {\r
+      MyLength = BlockSize - Offset;\r
+    } else {\r
+      MyLength = Length;\r
+    }\r
+\r
+    Status = FvBlock->Write (\r
+                        FvBlock,\r
+                        Lba,\r
+                        Offset,\r
+                        &MyLength,\r
+                        Ptr\r
+                        );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_ABORTED;\r
+    }\r
+    Offset = 0;\r
+    Length -= MyLength;\r
+    Ptr += MyLength;\r
+    Lba++;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Read from working block to refresh the work space in memory.\r
 \r
@@ -140,7 +259,6 @@ WorkSpaceRefresh (
   )\r
 {\r
   EFI_STATUS                      Status;\r
-  UINTN                           Length;\r
   UINTN                           RemainingSpaceSize;\r
 \r
   //\r
@@ -155,14 +273,14 @@ WorkSpaceRefresh (
   //\r
   // Read from working block\r
   //\r
-  Length = FtwDevice->FtwWorkSpaceSize;\r
-  Status = FtwDevice->FtwFvBlock->Read (\r
-                                    FtwDevice->FtwFvBlock,\r
-                                    FtwDevice->FtwWorkSpaceLba,\r
-                                    FtwDevice->FtwWorkSpaceBase,\r
-                                    &Length,\r
-                                    FtwDevice->FtwWorkSpace\r
-                                    );\r
+  Status = ReadWorkSpaceData (\r
+             FtwDevice->FtwFvBlock,\r
+             FtwDevice->WorkBlockSize,\r
+             FtwDevice->FtwWorkSpaceLba,\r
+             FtwDevice->FtwWorkSpaceBase,\r
+             FtwDevice->FtwWorkSpaceSize,\r
+             FtwDevice->FtwWorkSpace\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return EFI_ABORTED;\r
   }\r
@@ -194,14 +312,14 @@ WorkSpaceRefresh (
     //\r
     // Read from working block again\r
     //\r
-    Length = FtwDevice->FtwWorkSpaceSize;\r
-    Status = FtwDevice->FtwFvBlock->Read (\r
-                                      FtwDevice->FtwFvBlock,\r
-                                      FtwDevice->FtwWorkSpaceLba,\r
-                                      FtwDevice->FtwWorkSpaceBase,\r
-                                      &Length,\r
-                                      FtwDevice->FtwWorkSpace\r
-                                      );\r
+    Status = ReadWorkSpaceData (\r
+               FtwDevice->FtwFvBlock,\r
+               FtwDevice->WorkBlockSize,\r
+               FtwDevice->FtwWorkSpaceLba,\r
+               FtwDevice->FtwWorkSpaceBase,\r
+               FtwDevice->FtwWorkSpaceSize,\r
+               FtwDevice->FtwWorkSpace\r
+               );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_ABORTED;\r
     }\r
@@ -258,22 +376,22 @@ FtwReclaimWorkSpace (
   UINT8                                   *Ptr;\r
   EFI_LBA                                 WorkSpaceLbaOffset;\r
 \r
-  DEBUG ((EFI_D_ERROR, "Ftw: start to reclaim work space\n"));\r
+  DEBUG ((EFI_D_INFO, "Ftw: start to reclaim work space\n"));\r
 \r
   WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
 \r
   //\r
   // Read all original data from working block to a memory buffer\r
   //\r
-  TempBufferSize = FtwDevice->SpareAreaLength;\r
+  TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;\r
   TempBuffer     = AllocateZeroPool (TempBufferSize);\r
   if (TempBuffer == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   Ptr = TempBuffer;\r
-  for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
-    Length = FtwDevice->BlockSize;\r
+  for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {\r
+    Length = FtwDevice->WorkBlockSize;\r
     Status = FtwDevice->FtwFvBlock->Read (\r
                                           FtwDevice->FtwFvBlock,\r
                                           FtwDevice->FtwWorkBlockLba + Index,\r
@@ -292,7 +410,7 @@ FtwReclaimWorkSpace (
   // Clean up the workspace, remove all the completed records.\r
   //\r
   Ptr = TempBuffer +\r
-        (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
+        (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +\r
         FtwDevice->FtwWorkSpaceBase;\r
 \r
   //\r
@@ -348,7 +466,7 @@ FtwReclaimWorkSpace (
   // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
   //\r
   WorkingBlockHeader                      = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (TempBuffer +\r
-                                            (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
+                                            (UINTN) WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +\r
                                             FtwDevice->FtwWorkSpaceBase);\r
   WorkingBlockHeader->WorkingBlockValid   = FTW_INVALID_STATE;\r
   WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
@@ -366,7 +484,7 @@ FtwReclaimWorkSpace (
 \r
   Ptr = SpareBuffer;\r
   for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
-    Length = FtwDevice->BlockSize;\r
+    Length = FtwDevice->SpareBlockSize;\r
     Status = FtwDevice->FtwBackupFvb->Read (\r
                                         FtwDevice->FtwBackupFvb,\r
                                         FtwDevice->FtwSpareLba + Index,\r
@@ -386,9 +504,18 @@ FtwReclaimWorkSpace (
   // Write the memory buffer to spare block\r
   //\r
   Status  = FtwEraseSpareBlock (FtwDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (TempBuffer);\r
+    FreePool (SpareBuffer);\r
+    return EFI_ABORTED;\r
+  }\r
   Ptr     = TempBuffer;\r
-  for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
-    Length = FtwDevice->BlockSize;\r
+  for (Index = 0; TempBufferSize > 0; Index += 1) {\r
+    if (TempBufferSize > FtwDevice->SpareBlockSize) {\r
+      Length = FtwDevice->SpareBlockSize;\r
+    } else {\r
+      Length = TempBufferSize;\r
+    }\r
     Status = FtwDevice->FtwBackupFvb->Write (\r
                                             FtwDevice->FtwBackupFvb,\r
                                             FtwDevice->FtwSpareLba + Index,\r
@@ -403,6 +530,7 @@ FtwReclaimWorkSpace (
     }\r
 \r
     Ptr += Length;\r
+    TempBufferSize -= Length;\r
   }\r
   //\r
   // Free TempBuffer\r
@@ -414,8 +542,9 @@ FtwReclaimWorkSpace (
   //\r
   Status = FtwUpdateFvState (\r
             FtwDevice->FtwBackupFvb,\r
-            FtwDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
-            FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
+            FtwDevice->SpareBlockSize,\r
+            FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,\r
+            FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),\r
             WORKING_BLOCK_VALID\r
             );\r
   if (EFI_ERROR (Status)) {\r
@@ -430,6 +559,7 @@ FtwReclaimWorkSpace (
   //\r
   Status = FtwUpdateFvState (\r
             FtwDevice->FtwFvBlock,\r
+            FtwDevice->WorkBlockSize,\r
             FtwDevice->FtwWorkSpaceLba,\r
             FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
             WORKING_BLOCK_INVALID\r
@@ -453,9 +583,13 @@ FtwReclaimWorkSpace (
   // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
   //\r
   Status  = FtwEraseSpareBlock (FtwDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (SpareBuffer);\r
+    return EFI_ABORTED;\r
+  }\r
   Ptr     = SpareBuffer;\r
   for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
-    Length = FtwDevice->BlockSize;\r
+    Length = FtwDevice->SpareBlockSize;\r
     Status = FtwDevice->FtwBackupFvb->Write (\r
                                         FtwDevice->FtwBackupFvb,\r
                                         FtwDevice->FtwSpareLba + Index,\r
@@ -473,7 +607,7 @@ FtwReclaimWorkSpace (
 \r
   FreePool (SpareBuffer);\r
 \r
-  DEBUG ((EFI_D_ERROR, "Ftw: reclaim work space successfully\n"));\r
+  DEBUG ((EFI_D_INFO, "Ftw: reclaim work space successfully\n"));\r
 \r
   return EFI_SUCCESS;\r
 }\r