MdeModulePkg: Variable drivers robustly handle crashes during Reclaim().
authorStar Zeng <star.zeng@intel.com>
Wed, 3 Jul 2013 09:08:40 +0000 (09:08 +0000)
committerlzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 3 Jul 2013 09:08:40 +0000 (09:08 +0000)
PEI variable implementation checks only the variable header signature for validity. This does not seem robust if system crash occurred during previous Reclaim() operation. If the crash occurred while FTW was rewriting the variable FV, the signature could be valid even though the rest of the FV isn't valid.
Solution: Add a FaultTolerantWritePei driver to check and provide the FTW last write status, then PEI variable and early phase(before FTW protocol ready) of DXE variable can check the status and determine if all or partial variable data has been backed up in spare block, and then use the backed up data.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14454 6f19259b-4bc3-4df7-8a09-765794883524

19 files changed:
MdeModulePkg/Include/Guid/FaultTolerantWrite.h [new file with mode: 0644]
MdeModulePkg/Include/Guid/SystemNvDataGuid.h
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c [new file with mode: 0644]
MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf [new file with mode: 0644]
MdeModulePkg/Universal/Variable/Pei/Variable.c
MdeModulePkg/Universal/Variable/Pei/Variable.h
MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf

diff --git a/MdeModulePkg/Include/Guid/FaultTolerantWrite.h b/MdeModulePkg/Include/Guid/FaultTolerantWrite.h
new file mode 100644 (file)
index 0000000..cb7b454
--- /dev/null
@@ -0,0 +1,54 @@
+/** @file\r
+ Define the GUID gEdkiiFaultTolerantWriteGuid that will be used to build\r
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob and install PPI to inform the check\r
+ for FTW last write data has been done. The GUID hob will be only built if FTW last write was\r
+ still in progress with SpareComplete set and DestinationComplete not set.\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+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
+#ifndef _FAULT_TOLERANT_WRITE_H_\r
+#define _FAULT_TOLERANT_WRITE_H_\r
+\r
+#define EDKII_FAULT_TOLERANT_WRITE_GUID \\r
+  { \\r
+    0x1d3e9cb8, 0x43af, 0x490b, { 0x83,  0xa, 0x35, 0x16, 0xaa, 0x53, 0x20, 0x47 } \\r
+  }\r
+\r
+//\r
+// FTW Last write data. It will be used as gEdkiiFaultTolerantWriteGuid GUID hob data.\r
+//\r
+typedef struct {\r
+  ///\r
+  /// Target address to be updated in FTW last write.\r
+  ///\r
+  EFI_PHYSICAL_ADDRESS      TargetAddress;\r
+  ///\r
+  /// Spare address to back up the updated buffer.\r
+  ///\r
+  EFI_PHYSICAL_ADDRESS      SpareAddress;\r
+  ///\r
+  /// The length of data that have been backed up in spare block.\r
+  /// It is also the length of target block that has been erased.\r
+  ///\r
+  UINT64                    Length;\r
+} FAULT_TOLERANT_WRITE_LAST_WRITE_DATA;\r
+\r
+//\r
+// This GUID will be used to install PPI to inform the check for FTW last write data has been done.\r
+// The related FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob will be only built if\r
+// FTW last write was still in progress with SpareComplete set and DestinationComplete not set.\r
+// It means the target buffer has been backed up in spare block, then target block has been erased,\r
+// but the target buffer has not been writen in target block from spare block.\r
+//\r
+extern EFI_GUID gEdkiiFaultTolerantWriteGuid;\r
+\r
+#endif\r
index 4e21888..40446bc 100644 (file)
@@ -1,10 +1,10 @@
 /** @file  \r
-  This file defines NvDataFv GUID and FTW working block structure header.\r
-  This guid can be used as FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER if \r
+  This file defines NvDataFv GUID and FTW working block structures.\r
+  The NvDataFv GUID can be used as FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER if \r
   this FV image contains NV data, such as NV variable data.\r
-  This guid can also be used as the signature of FTW working block header.\r
+  This file also defines WorkingBlockSignature GUID for FTW working block signature.\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials are licensed and made available under \r
 the terms and conditions of the BSD License that accompanies this distribution.  \r
 The full text of the license may be found at\r
@@ -21,10 +21,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define EFI_SYSTEM_NV_DATA_FV_GUID \\r
   {0xfff12b8d, 0x7696, 0x4c8b, {0xa9, 0x85, 0x27, 0x47, 0x7, 0x5b, 0x4f, 0x50} }\r
 \r
-///\r
-/// An NvDataFv GUID used as the signature of FTW working block header.\r
-///\r
+#define EDKII_WORKING_BLOCK_SIGNATURE_GUID \\r
+  {0x9e58292b, 0x7c68, 0x497d, {0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95} }\r
+\r
 extern EFI_GUID gEfiSystemNvDataFvGuid;\r
+extern EFI_GUID gEdkiiWorkingBlockSignatureGuid;\r
 \r
 #define WORKING_BLOCK_VALID   0x1\r
 #define WORKING_BLOCK_INVALID 0x2\r
@@ -35,7 +36,9 @@ extern EFI_GUID gEfiSystemNvDataFvGuid;
 ///\r
 typedef struct {\r
   ///\r
-  /// System Non Volatile FV Guid.\r
+  /// FTW working block signature.\r
+  /// Its value has be updated from gEfiSystemNvDataFvGuid to gEdkiiWorkingBlockSignatureGuid,\r
+  /// because its write queue data format has been updated to support the crossing archs.\r
   ///\r
   EFI_GUID  Signature;\r
   ///\r
@@ -55,8 +58,60 @@ typedef struct {
   UINT64    WriteQueueSize;\r
   ///\r
   /// Write Queue data.\r
-  /// UINT8  WriteQueue[WriteQueueSize];\r
+  ///\r
+  /// EFI_FAULT_TOLERANT_WRITE_HEADER FtwHeader;\r
+  /// EFI_FAULT_TOLERANT_WRITE_RECORD FtwRecord[FtwHeader.NumberOfWrites]\r
+  /// EFI_FAULT_TOLERANT_WRITE_HEADER FtwHeader2;\r
+  /// EFI_FAULT_TOLERANT_WRITE_RECORD FtwRecord2[FtwHeader2.NumberOfWrites]\r
+  /// ...\r
   ///\r
 } EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER;\r
 \r
+#define FTW_VALID_STATE     0\r
+#define FTW_INVALID_STATE   1\r
+\r
+//\r
+// EFI Fault tolerant block update write queue entry.\r
+//\r
+typedef struct {\r
+  UINT8     HeaderAllocated : 1;\r
+  UINT8     WritesAllocated : 1;\r
+  UINT8     Complete : 1;\r
+  UINT8     Reserved : 5;\r
+  EFI_GUID  CallerId;\r
+  UINT64    NumberOfWrites;\r
+  UINT64    PrivateDataSize;\r
+} EFI_FAULT_TOLERANT_WRITE_HEADER;\r
+\r
+//\r
+// EFI Fault tolerant block update write queue record.\r
+//\r
+typedef struct {\r
+  UINT8   BootBlockUpdate : 1;\r
+  UINT8   SpareComplete : 1;\r
+  UINT8   DestinationComplete : 1;\r
+  UINT8   Reserved : 5;\r
+  EFI_LBA Lba;\r
+  UINT64  Offset;\r
+  UINT64  Length;\r
+  //\r
+  // Relative offset to spare block.\r
+  //\r
+  INT64   RelativeOffset;\r
+  //\r
+  // UINT8    PrivateData[PrivateDataSize]\r
+  //\r
+} EFI_FAULT_TOLERANT_WRITE_RECORD;\r
+\r
+#define FTW_RECORD_SIZE(PrivateDataSize)  (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize)\r
+\r
+#define FTW_RECORD_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \\r
+    ((UINTN) (NumberOfWrites) * (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize))\r
+\r
+#define FTW_WRITE_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \\r
+    ( \\r
+      sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + (UINTN) (NumberOfWrites) * \\r
+      (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize) \\r
+    )\r
+\r
 #endif\r
index 3c07c69..7db47ec 100644 (file)
   #  Include/Guid/SystemNvDataGuid.h\r
   gEfiSystemNvDataFvGuid         = { 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}\r
 \r
+  ## GUID used as the signature of FTW working block header.\r
+  #  Include/Guid/SystemNvDataGuid.h\r
+  gEdkiiWorkingBlockSignatureGuid   = { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95 }}\r
+\r
+  ## GUID used to build FTW last write data hob and install PPI to inform the check for FTW last write data has been done.\r
+  #  Include/Guid/FaultTolerantWrite.h\r
+  gEdkiiFaultTolerantWriteGuid      = { 0x1d3e9cb8, 0x43af, 0x490b, { 0x83,  0xa, 0x35, 0x16, 0xaa, 0x53, 0x20, 0x47 }}\r
+\r
   ## Guid specify the device is the console out device.\r
   #  Include/Guid/ConsoleOutDevice.h\r
   gEfiConsoleOutDeviceGuid       = { 0xD3B36F2C, 0xD551, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}\r
index 444cd83..6e1bbeb 100644 (file)
   MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf\r
   MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf\r
   MdeModulePkg/Application/VariableInfo/VariableInfo.inf\r
+  MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf\r
   MdeModulePkg/Universal/Variable/Pei/VariablePei.inf\r
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf\r
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf\r
index 2f11016..3d1d29d 100644 (file)
@@ -3,7 +3,7 @@
   These are the common Fault Tolerant Write (FTW) functions that are shared \r
   by DXE FTW driver and SMM FTW driver.\r
 \r
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\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
@@ -95,7 +95,7 @@ FtwAllocate (
   //\r
   // Check if there is enough space for the coming allocation\r
   //\r
-  if (WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {\r
+  if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {\r
     DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));\r
     return EFI_BUFFER_TOO_SMALL;\r
   }\r
@@ -115,7 +115,7 @@ FtwAllocate (
   // If workspace is not enough, then reclaim workspace\r
   //\r
   Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;\r
-  if (Offset + WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {\r
+  if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {\r
     Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
     if (EFI_ERROR (Status)) {\r
       return EFI_ABORTED;\r
@@ -365,7 +365,7 @@ FtwWrite (
   //\r
   // If Record is out of the range of Header, return access denied.\r
   //\r
-  if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {\r
+  if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {\r
     return EFI_ACCESS_DENIED;\r
   }\r
 \r
@@ -415,13 +415,13 @@ FtwWrite (
   Record->Lba     = Lba;\r
   Record->Offset  = Offset;\r
   Record->Length  = Length;\r
-  Record->FvBaseAddress = FvbPhysicalAddress;\r
+  Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * FtwDevice->BlockSize) - (INT64) FtwDevice->SpareAreaAddress;\r
   if (PrivateData != NULL) {\r
-    CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize);\r
+    CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);\r
   }\r
 \r
   MyOffset  = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
-  MyLength  = RECORD_SIZE (Header->PrivateDataSize);\r
+  MyLength  = FTW_RECORD_SIZE (Header->PrivateDataSize);\r
 \r
   Status = FtwDevice->FtwFvBlock->Write (\r
                                     FtwDevice->FtwFvBlock,\r
@@ -693,6 +693,10 @@ FtwAbort (
     return EFI_ABORTED;\r
   }\r
 \r
+  if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
   if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {\r
     return EFI_NOT_FOUND;\r
   }\r
@@ -809,16 +813,16 @@ FtwGetLastWrite (
   //\r
   CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));\r
   *Lba      = Record->Lba;\r
-  *Offset   = Record->Offset;\r
-  *Length   = Record->Length;\r
+  *Offset   = (UINTN) Record->Offset;\r
+  *Length   = (UINTN) Record->Length;\r
   *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);\r
 \r
   if (*PrivateDataSize < Header->PrivateDataSize) {\r
-    *PrivateDataSize  = Header->PrivateDataSize;\r
+    *PrivateDataSize  = (UINTN) Header->PrivateDataSize;\r
     PrivateData       = NULL;\r
     Status            = EFI_BUFFER_TOO_SMALL;\r
   } else {\r
-    *PrivateDataSize = Header->PrivateDataSize;\r
+    *PrivateDataSize = (UINTN) Header->PrivateDataSize;\r
     CopyMem (PrivateData, Record + 1, *PrivateDataSize);\r
     Status = EFI_SUCCESS;\r
   }\r
index 8deae88..78c65f2 100644 (file)
@@ -3,7 +3,7 @@
   The internal header file includes the common header files, defines\r
   internal structure and functions used by FtwLite module.\r
 \r
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\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
@@ -38,59 +38,17 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 #define FTW_ERASE_POLARITY  1\r
 \r
-#define FTW_VALID_STATE     0\r
-#define FTW_INVALID_STATE   1\r
-\r
 #define FTW_ERASED_BYTE     ((UINT8) (255))\r
 #define FTW_POLARITY_REVERT ((UINT8) (255))\r
 \r
-//\r
-// EFI Fault tolerant block update write queue entry\r
-//\r
-typedef struct {\r
-  UINT8     HeaderAllocated : 1;\r
-  UINT8     WritesAllocated : 1;\r
-  UINT8     Complete : 1;\r
 #define HEADER_ALLOCATED  0x1\r
 #define WRITES_ALLOCATED  0x2\r
 #define WRITES_COMPLETED  0x4\r
-  UINT8     Reserved : 5;\r
-  EFI_GUID  CallerId;\r
-  UINTN     NumberOfWrites;\r
-  UINTN     PrivateDataSize;\r
-} EFI_FAULT_TOLERANT_WRITE_HEADER;\r
 \r
-//\r
-// EFI Fault tolerant block update write queue record\r
-//\r
-typedef struct {\r
-  UINT8   BootBlockUpdate : 1;\r
-  UINT8   SpareComplete : 1;\r
-  UINT8   DestinationComplete : 1;\r
 #define BOOT_BLOCK_UPDATE 0x1\r
 #define SPARE_COMPLETED   0x2\r
 #define DEST_COMPLETED    0x4\r
-  UINT8   Reserved : 5;\r
-  EFI_LBA Lba;\r
-  UINTN   Offset;\r
-  UINTN   Length;\r
-  EFI_PHYSICAL_ADDRESS  FvBaseAddress;\r
-  //\r
-  // UINT8                PrivateData[PrivateDataSize]\r
-  //\r
-} EFI_FAULT_TOLERANT_WRITE_RECORD;\r
-\r
-\r
-#define RECORD_SIZE(PrivateDataSize)  (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + PrivateDataSize)\r
-\r
-#define RECORD_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \\r
-    ((NumberOfWrites) * (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + PrivateDataSize))\r
 \r
-#define WRITE_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \\r
-    ( \\r
-      sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + (NumberOfWrites) * \\r
-        (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + PrivateDataSize) \\r
-    )\r
 \r
 #define FTW_DEVICE_SIGNATURE  SIGNATURE_32 ('F', 'T', 'W', 'D')\r
 \r
index f60ab28..3d4b912 100644 (file)
@@ -3,7 +3,7 @@
 # which provides fault tolerant write capability for block devices.\r
 # Its implementation depends on the full functionality FVB protocol that support read, write/erase flash access.\r
 #\r
-# Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
 #\r
 #  This program and the accompanying materials\r
 #  are licensed and made available under the terms and conditions of the BSD License\r
@@ -49,7 +49,7 @@
   PcdLib\r
 \r
 [Guids]\r
-  gEfiSystemNvDataFvGuid                        ## CONSUMES ## FV Signature of Working Space Header\r
+  gEdkiiWorkingBlockSignatureGuid               ## CONSUMES ## FV Signature of Working Space Header\r
 \r
 [Protocols]\r
   gEfiSwapAddressRangeProtocolGuid     | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable          ## CONSUMES\r
index c39f84c..a5c8a58 100644 (file)
@@ -52,7 +52,7 @@
   PcdLib\r
 \r
 [Guids]\r
-  gEfiSystemNvDataFvGuid                        ## CONSUMES ## FV Signature of Working Space Header\r
+  gEdkiiWorkingBlockSignatureGuid                  ## CONSUMES ## FV Signature of Working Space Header\r
 \r
 [Protocols]\r
   gEfiSmmSwapAddressRangeProtocolGuid     | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable          ## CONSUMES\r
index 2e4052c..fdd9dfa 100644 (file)
@@ -689,6 +689,7 @@ FlushSpareBlockToWorkingBlock (
     return EFI_ABORTED;\r
   }\r
 \r
+  FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
   FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;\r
 \r
   return EFI_SUCCESS;\r
@@ -775,7 +776,7 @@ FtwGetLastWriteHeader (
   Offset          = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
 \r
   while (FtwHeader->Complete == FTW_VALID_STATE) {\r
-    Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
+    Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
     //\r
     // If Offset exceed the FTW work space boudary, return error.\r
     //\r
@@ -834,7 +835,7 @@ FtwGetLastWriteRecord (
     FtwRecord++;\r
 \r
     if (FtwWriteHeader->PrivateDataSize != 0) {\r
-      FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + FtwWriteHeader->PrivateDataSize);\r
+      FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize);\r
     }\r
   }\r
   //\r
@@ -844,7 +845,7 @@ FtwGetLastWriteRecord (
   //  also return the last record.\r
   //\r
   if (Index == FtwWriteHeader->NumberOfWrites) {\r
-    *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - RECORD_SIZE (FtwWriteHeader->PrivateDataSize));\r
+    *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize));\r
     return EFI_SUCCESS;\r
   }\r
 \r
@@ -901,7 +902,7 @@ IsLastRecordOfWrites (
   Head  = (UINT8 *) FtwHeader;\r
   Ptr   = (UINT8 *) FtwRecord;\r
 \r
-  Head += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);\r
+  Head += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);\r
   return (BOOLEAN) (Head == Ptr);\r
 }\r
 \r
@@ -929,7 +930,7 @@ GetPreviousRecordOfWrites (
   }\r
 \r
   Ptr = (UINT8 *) (*FtwRecord);\r
-  Ptr -= RECORD_SIZE (FtwHeader->PrivateDataSize);\r
+  Ptr -= FTW_RECORD_SIZE (FtwHeader->PrivateDataSize);\r
   *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;\r
   return EFI_SUCCESS;\r
 }\r
@@ -1259,7 +1260,7 @@ InitFtwProtocol (
   FtwHeader = FtwDevice->FtwLastWriteHeader;\r
   Offset    = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;\r
   if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {\r
-    Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
+    Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
   }\r
   \r
   if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {\r
@@ -1283,7 +1284,7 @@ InitFtwProtocol (
       // if (SpareCompleted) THEN  Restart to fault tolerant write.\r
       //\r
       FvbHandle = NULL;\r
-      FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);\r
+      FvbHandle = GetFvbByAddress ((EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) FtwDevice->SpareAreaAddress + FtwDevice->FtwLastWriteRecord->RelativeOffset), &Fvb);\r
       if (FvbHandle != NULL) {\r
         Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);\r
         DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));\r
index bd8285d..4c658b2 100644 (file)
@@ -2,7 +2,7 @@
 \r
    Internal functions to operate Working Block Space.\r
 \r
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\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
@@ -32,9 +32,9 @@ InitializeLocalWorkSpaceHeader (
   EFI_STATUS                              Status;\r
 \r
   //\r
-  // Check signature with gEfiSystemNvDataFvGuid.\r
+  // Check signature with gEdkiiWorkingBlockSignatureGuid.\r
   //\r
-  if (CompareGuid (&gEfiSystemNvDataFvGuid, &mWorkingBlockHeader.Signature)) {\r
+  if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {\r
     //\r
     // The local work space header has been initialized.\r
     //\r
@@ -48,11 +48,11 @@ InitializeLocalWorkSpaceHeader (
     );\r
 \r
   //\r
-  // Here using gEfiSystemNvDataFvGuid as the signature.\r
+  // Here using gEdkiiWorkingBlockSignatureGuid as the signature.\r
   //\r
   CopyMem (\r
     &mWorkingBlockHeader.Signature,\r
-    &gEfiSystemNvDataFvGuid,\r
+    &gEdkiiWorkingBlockSignatureGuid,\r
     sizeof (EFI_GUID)\r
     );\r
   mWorkingBlockHeader.WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
@@ -322,7 +322,7 @@ FtwReclaimWorkSpace (
       CopyMem (\r
         Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
         FtwDevice->FtwLastWriteHeader,\r
-        WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
+        FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
         );\r
     }\r
   }\r
diff --git a/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c b/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c
new file mode 100644 (file)
index 0000000..ec03216
--- /dev/null
@@ -0,0 +1,318 @@
+/** @file\r
+  This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform\r
+  the check for FTW last write data has been done.\r
+\r
+Copyright (c) 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
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/FaultTolerantWrite.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/HobLib.h>\r
+\r
+EFI_PEI_PPI_DESCRIPTOR     mPpiListVariable = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEdkiiFaultTolerantWriteGuid,\r
+  NULL\r
+};\r
+\r
+/**\r
+  Get the last Write Header pointer.\r
+  The last write header is the header whose 'complete' state hasn't been set.\r
+  After all, this header may be a EMPTY header entry for next Allocate.\r
+\r
+\r
+  @param FtwWorkSpaceHeader Pointer of the working block header\r
+  @param FtwWorkSpaceSize   Size of the work space\r
+  @param FtwWriteHeader     Pointer to retrieve the last write header\r
+\r
+  @retval  EFI_SUCCESS      Get the last write record successfully\r
+  @retval  EFI_ABORTED      The FTW work space is damaged\r
+\r
+**/\r
+EFI_STATUS\r
+FtwGetLastWriteHeader (\r
+  IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER  *FtwWorkSpaceHeader,\r
+  IN UINTN                                    FtwWorkSpaceSize,\r
+  OUT EFI_FAULT_TOLERANT_WRITE_HEADER         **FtwWriteHeader\r
+  )\r
+{\r
+  UINTN                           Offset;\r
+  EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;\r
+\r
+  *FtwWriteHeader = NULL;\r
+  FtwHeader       = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);\r
+  Offset          = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
+\r
+  while (FtwHeader->Complete == FTW_VALID_STATE) {\r
+    Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
+    //\r
+    // If Offset exceed the FTW work space boudary, return error.\r
+    //\r
+    if (Offset >= FtwWorkSpaceSize) {\r
+      *FtwWriteHeader = FtwHeader;\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);\r
+  }\r
+  //\r
+  // Last write header is found\r
+  //\r
+  *FtwWriteHeader = FtwHeader;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the last Write Record pointer. The last write Record is the Record\r
+  whose DestinationCompleted state hasn't been set. After all, this Record\r
+  may be a EMPTY record entry for next write.\r
+\r
+\r
+  @param FtwWriteHeader  Pointer to the write record header\r
+  @param FtwWriteRecord  Pointer to retrieve the last write record\r
+\r
+  @retval EFI_SUCCESS        Get the last write record successfully\r
+  @retval EFI_ABORTED        The FTW work space is damaged\r
+\r
+**/\r
+EFI_STATUS\r
+FtwGetLastWriteRecord (\r
+  IN EFI_FAULT_TOLERANT_WRITE_HEADER          *FtwWriteHeader,\r
+  OUT EFI_FAULT_TOLERANT_WRITE_RECORD         **FtwWriteRecord\r
+  )\r
+{\r
+  UINTN                           Index;\r
+  EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;\r
+\r
+  *FtwWriteRecord = NULL;\r
+  FtwRecord       = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);\r
+\r
+  //\r
+  // Try to find the last write record "that has not completed"\r
+  //\r
+  for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {\r
+    if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {\r
+      //\r
+      // The last write record is found\r
+      //\r
+      *FtwWriteRecord = FtwRecord;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    FtwRecord++;\r
+\r
+    if (FtwWriteHeader->PrivateDataSize != 0) {\r
+      FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize);\r
+    }\r
+  }\r
+  //\r
+  //  if Index == NumberOfWrites, then\r
+  //  the last record has been written successfully,\r
+  //  but the Header->Complete Flag has not been set.\r
+  //  also return the last record.\r
+  //\r
+  if (Index == FtwWriteHeader->NumberOfWrites) {\r
+    *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_ABORTED;\r
+}\r
+\r
+/**\r
+  Check to see if it is a valid work space.\r
+\r
+\r
+  @param WorkingHeader   Pointer of working block header\r
+  @param WorkingLength   Working block length\r
+\r
+  @retval TRUE          The work space is valid.\r
+  @retval FALSE         The work space is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidWorkSpace (\r
+  IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER    *WorkingHeader,\r
+  IN UINTN                                      WorkingLength\r
+  )\r
+{\r
+  UINT8 Data;\r
+\r
+  if (WorkingHeader == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) || (WorkingHeader->WorkingBlockInvalid == FTW_VALID_STATE)) {\r
+    DEBUG ((EFI_D_ERROR, "FtwPei: Work block header valid bit check error\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  if (WorkingHeader->WriteQueueSize != (WorkingLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))) {\r
+    DEBUG ((EFI_D_ERROR, "FtwPei: Work block header WriteQueueSize check error\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check signature with gEdkiiWorkingBlockSignatureGuid\r
+  //\r
+  if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &WorkingHeader->Signature)) {\r
+    DEBUG ((EFI_D_ERROR, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n"));\r
+    //\r
+    // To be compatible with old signature gEfiSystemNvDataFvGuid.\r
+    //\r
+    if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
+      return FALSE;\r
+    } else {\r
+      Data = *(UINT8 *) (WorkingHeader + 1);\r
+      if (Data != 0xff) {\r
+        DEBUG ((EFI_D_ERROR, "FtwPei: Old format FTW structure can't be handled\n"));\r
+        ASSERT (FALSE);\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+\r
+}\r
+\r
+/**\r
+  Main entry for Fault Tolerant Write PEIM.\r
+\r
+  @param[in]  FileHandle              Handle of the file being invoked.\r
+  @param[in]  PeiServices             Pointer to PEI Services table.\r
+\r
+  @retval EFI_SUCCESS  If the interface could be successfully installed\r
+  @retval Others       Returned from PeiServicesInstallPpi()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimFaultTolerantWriteInitialize (\r
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER   *FtwWorkingBlockHeader;\r
+  EFI_FAULT_TOLERANT_WRITE_HEADER           *FtwLastWriteHeader;\r
+  EFI_FAULT_TOLERANT_WRITE_RECORD           *FtwLastWriteRecord;\r
+  EFI_PHYSICAL_ADDRESS                      WorkSpaceAddress;\r
+  UINTN                                     WorkSpaceLength;\r
+  EFI_PHYSICAL_ADDRESS                      SpareAreaAddress;\r
+  UINTN                                     SpareAreaLength;\r
+  EFI_PHYSICAL_ADDRESS                      WorkSpaceInSpareArea;\r
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA      FtwLastWrite;\r
+\r
+  FtwWorkingBlockHeader = NULL;\r
+  FtwLastWriteHeader = NULL;\r
+  FtwLastWriteRecord = NULL;\r
+\r
+  WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);\r
+  if (WorkSpaceAddress == 0) {\r
+    WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);\r
+  }\r
+  WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
+\r
+  SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);\r
+  if (SpareAreaAddress == 0) {\r
+    SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);\r
+  }\r
+  SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
+\r
+  //\r
+  // The address of FTW working base and spare base must not be 0.\r
+  //\r
+  ASSERT ((WorkSpaceAddress != 0) && (SpareAreaAddress != 0));\r
+\r
+  FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (UINTN) WorkSpaceAddress;\r
+  if (IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {\r
+    Status = FtwGetLastWriteHeader (\r
+               FtwWorkingBlockHeader,\r
+               WorkSpaceLength,\r
+               &FtwLastWriteHeader\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = FtwGetLastWriteRecord (\r
+                 FtwLastWriteHeader,\r
+                 &FtwLastWriteRecord\r
+                 );\r
+    }\r
+\r
+    if (!EFI_ERROR (Status) && ((FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) && (FtwLastWriteRecord->DestinationComplete != FTW_VALID_STATE))) {\r
+      //\r
+      // If FTW last write was still in progress with SpareComplete set and DestinationComplete not set.\r
+      // It means the target buffer has been backed up in spare block, then target block has been erased,\r
+      // but the target buffer has not been writen in target block from spare block, we need to build\r
+      // FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob to hold the FTW last write data.\r
+      //\r
+      FtwLastWrite.TargetAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) SpareAreaAddress + FtwLastWriteRecord->RelativeOffset);\r
+      FtwLastWrite.SpareAddress = SpareAreaAddress;\r
+      FtwLastWrite.Length = SpareAreaLength;\r
+      DEBUG ((\r
+        EFI_D_INFO,\r
+        "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",\r
+        (UINTN) FtwLastWrite.TargetAddress,\r
+        (UINTN) FtwLastWrite.SpareAddress,\r
+        (UINTN) FtwLastWrite.Length));\r
+      BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *) &FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));\r
+    }\r
+  } else {\r
+    FtwWorkingBlockHeader = NULL;\r
+    //\r
+    // If the working block workspace is not valid, try to find workspace in the spare block.\r
+    //\r
+    WorkSpaceInSpareArea = SpareAreaAddress + SpareAreaLength - WorkSpaceLength;\r
+    while (WorkSpaceInSpareArea >= SpareAreaAddress) {\r
+      if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, (EFI_GUID *) (UINTN) WorkSpaceInSpareArea)) {\r
+        //\r
+        // Found the workspace.\r
+        //\r
+        DEBUG ((EFI_D_INFO, "FtwPei: workspace in spare block is at 0x%x.\n", (UINTN) WorkSpaceInSpareArea));\r
+        FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (UINTN) WorkSpaceInSpareArea;\r
+        break;\r
+      }\r
+      WorkSpaceInSpareArea = WorkSpaceInSpareArea - sizeof (EFI_GUID);\r
+    }\r
+    if ((FtwWorkingBlockHeader != NULL) && IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {\r
+      //\r
+      // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it.\r
+      //\r
+      FtwLastWrite.TargetAddress = WorkSpaceAddress - (WorkSpaceInSpareArea - SpareAreaAddress);\r
+      FtwLastWrite.SpareAddress = SpareAreaAddress;\r
+      FtwLastWrite.Length = SpareAreaLength;\r
+      DEBUG ((\r
+        EFI_D_INFO,\r
+        "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",\r
+        (UINTN) FtwLastWrite.TargetAddress,\r
+        (UINTN) FtwLastWrite.SpareAddress,\r
+        (UINTN) FtwLastWrite.Length));\r
+      BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *) &FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));\r
+    } else {\r
+      //\r
+      // Both are invalid.\r
+      //\r
+      DEBUG ((EFI_D_ERROR, "FtwPei: Both working and spare block are invalid.\n"));\r
+    }\r
+  }\r
+\r
+  //\r
+  // Install gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.\r
+  //\r
+  return PeiServicesInstallPpi (&mPpiListVariable);\r
+}\r
diff --git a/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf b/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
new file mode 100644 (file)
index 0000000..bcc2313
--- /dev/null
@@ -0,0 +1,61 @@
+## @file\r
+# This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform\r
+# the check for FTW last write data has been done.\r
+#\r
+# Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+#\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
+#  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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = FaultTolerantWritePei\r
+  FILE_GUID                      = AAC33064-9ED0-4b89-A5AD-3EA767960B22\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = PeimFaultTolerantWriteInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  FaultTolerantWritePei.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+  BaseLib\r
+  DebugLib\r
+  HobLib\r
+  BaseMemoryLib\r
+  PcdLib\r
+\r
+[Guids]\r
+  gEdkiiFaultTolerantWriteGuid                  ## CONSUMES\r
+  gEdkiiWorkingBlockSignatureGuid               ## CONSUMES\r
+  gEfiSystemNvDataFvGuid                        ## CONSUMES\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize\r
+\r
+[Depex]\r
+  TRUE\r
+\r
index 10ad3f5..df03047 100644 (file)
@@ -11,7 +11,6 @@ http://opensource.org/licenses/bsd-license.php
 \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
-Module Name:\r
 \r
 **/\r
 \r
@@ -174,7 +173,6 @@ GetVariableNamePtr (
   IN  VARIABLE_HEADER   *Variable\r
   )\r
 {\r
-\r
   return (CHAR16 *) (Variable + 1);\r
 }\r
 \r
@@ -182,14 +180,16 @@ GetVariableNamePtr (
 /**\r
   This code gets the pointer to the variable data.\r
 \r
-  @param   Variable  Pointer to the Variable Header.\r
+  @param   Variable         Pointer to the Variable Header.\r
+  @param   VariableHeader   Pointer to the Variable Header that has consecutive content.\r
 \r
   @return  A UINT8* pointer to Variable Data.\r
 \r
 **/\r
 UINT8 *\r
 GetVariableDataPtr (\r
-  IN  VARIABLE_HEADER   *Variable\r
+  IN  VARIABLE_HEADER   *Variable,\r
+  IN  VARIABLE_HEADER   *VariableHeader\r
   )\r
 {\r
   UINTN Value;\r
@@ -198,8 +198,8 @@ GetVariableDataPtr (
   // Be careful about pad size for alignment\r
   //\r
   Value =  (UINTN) GetVariableNamePtr (Variable);\r
-  Value += NameSizeOfVariable (Variable);\r
-  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
+  Value += NameSizeOfVariable (VariableHeader);\r
+  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader));\r
 \r
   return (UINT8 *) Value;\r
 }\r
@@ -208,34 +208,48 @@ GetVariableDataPtr (
 /**\r
   This code gets the pointer to the next variable header.\r
 \r
-  @param  Variable  Pointer to the Variable Header.\r
+  @param  StoreInfo         Pointer to variable store info structure.\r
+  @param  Variable          Pointer to the Variable Header.\r
+  @param  VariableHeader    Pointer to the Variable Header that has consecutive content.\r
 \r
   @return  A VARIABLE_HEADER* pointer to next variable header.\r
 \r
 **/\r
 VARIABLE_HEADER *\r
 GetNextVariablePtr (\r
-  IN  VARIABLE_HEADER   *Variable\r
+  IN  VARIABLE_STORE_INFO   *StoreInfo,\r
+  IN  VARIABLE_HEADER       *Variable,\r
+  IN  VARIABLE_HEADER       *VariableHeader\r
   )\r
 {\r
-  UINTN Value;\r
-\r
-  if (!IsValidVariableHeader (Variable)) {\r
-    return NULL;\r
-  }\r
-\r
-  Value =  (UINTN) GetVariableDataPtr (Variable);\r
-  Value += DataSizeOfVariable (Variable);\r
-  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
+  EFI_PHYSICAL_ADDRESS  TargetAddress;\r
+  EFI_PHYSICAL_ADDRESS  SpareAddress;\r
+  UINTN                 Value;\r
 \r
+  Value =  (UINTN) GetVariableDataPtr (Variable, VariableHeader);\r
+  Value += DataSizeOfVariable (VariableHeader);\r
+  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader));\r
   //\r
   // Be careful about pad size for alignment\r
   //\r
-  return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
+  Value = HEADER_ALIGN (Value);\r
+\r
+  if (StoreInfo->FtwLastWriteData != NULL) {\r
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
+    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
+    if (((UINTN) Variable < (UINTN) TargetAddress) && (Value >= (UINTN) TargetAddress)) {\r
+      //\r
+      // Next variable is in spare block.\r
+      //\r
+      Value = (UINTN) SpareAddress + (Value - (UINTN) TargetAddress);\r
+    }\r
+  }\r
+\r
+  return (VARIABLE_HEADER *) Value;\r
 }\r
 \r
 /**\r
-  This code gets the pointer to the variable name.\r
+  Get variable store status.\r
 \r
   @param  VarStoreHeader  Pointer to the Variable Store Header.\r
 \r
@@ -249,7 +263,6 @@ GetVariableStoreStatus (
   IN VARIABLE_STORE_HEADER *VarStoreHeader\r
   )\r
 {\r
-       \r
   if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
       VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
       VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
@@ -273,11 +286,85 @@ GetVariableStoreStatus (
   }\r
 }\r
 \r
+/**\r
+  Compare two variable names, one of them may be inconsecutive.\r
+\r
+  @param StoreInfo      Pointer to variable store info structure.\r
+  @param Name1          Pointer to one variable name.\r
+  @param Name2          Pointer to another variable name.\r
+  @param NameSize       Variable name size.\r
+\r
+  @retval TRUE          Name1 and Name2 are identical.\r
+  @retval FALSE         Name1 and Name2 are not identical.\r
+\r
+**/\r
+BOOLEAN\r
+CompareVariableName (\r
+  IN VARIABLE_STORE_INFO    *StoreInfo,\r
+  IN CONST CHAR16           *Name1,\r
+  IN CONST CHAR16           *Name2,\r
+  IN UINTN                  NameSize\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  TargetAddress;\r
+  EFI_PHYSICAL_ADDRESS  SpareAddress;\r
+  UINTN                 PartialNameSize;\r
+\r
+  if (StoreInfo->FtwLastWriteData != NULL) {\r
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
+    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
+    if (((UINTN) Name1 < (UINTN) TargetAddress) && (((UINTN) Name1 + NameSize) > (UINTN) TargetAddress)) {\r
+      //\r
+      // Name1 is inconsecutive.\r
+      //\r
+      PartialNameSize = (UINTN) TargetAddress - (UINTN) Name1;\r
+      //\r
+      // Partial content is in NV storage.\r
+      //\r
+      if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, PartialNameSize) == 0) {\r
+        //\r
+        // Another partial content is in spare block.\r
+        //\r
+        if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {\r
+          return TRUE;\r
+        }\r
+      }\r
+      return FALSE;\r
+    } else if (((UINTN) Name2 < (UINTN) TargetAddress) && (((UINTN) Name2 + NameSize) > (UINTN) TargetAddress)) {\r
+      //\r
+      // Name2 is inconsecutive.\r
+      //\r
+      PartialNameSize = (UINTN) TargetAddress - (UINTN) Name2;\r
+      //\r
+      // Partial content is in NV storage.\r
+      //\r
+      if (CompareMem ((UINT8 *) Name2, (UINT8 *) Name1, PartialNameSize) == 0) {\r
+        //\r
+        // Another partial content is in spare block.\r
+        //\r
+        if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {\r
+          return TRUE;\r
+        }\r
+      }\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Both Name1 and Name2 are consecutive.\r
+  //\r
+  if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) {\r
+    return TRUE;\r
+  }\r
+  return FALSE;\r
+}\r
 \r
 /**\r
   This function compares a variable with variable entries in database.\r
 \r
+  @param  StoreInfo     Pointer to variable store info structure.\r
   @param  Variable      Pointer to the variable in our database\r
+  @param  VariableHeader Pointer to the Variable Header that has consecutive content.\r
   @param  VariableName  Name of the variable to compare to 'Variable'\r
   @param  VendorGuid    GUID of the variable to compare to 'Variable'\r
   @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.\r
@@ -288,7 +375,9 @@ GetVariableStoreStatus (
 **/\r
 EFI_STATUS\r
 CompareWithValidVariable (\r
+  IN  VARIABLE_STORE_INFO           *StoreInfo,\r
   IN  VARIABLE_HEADER               *Variable,\r
+  IN  VARIABLE_HEADER               *VariableHeader,\r
   IN  CONST CHAR16                  *VariableName,\r
   IN  CONST EFI_GUID                *VendorGuid,\r
   OUT VARIABLE_POINTER_TRACK        *PtrTrack\r
@@ -305,14 +394,14 @@ CompareWithValidVariable (
     // Instead we compare the GUID a UINT32 at a time and branch\r
     // on the first failed comparison.\r
     //\r
-    if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&\r
-        (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&\r
-        (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&\r
-        (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])\r
+    if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &VariableHeader->VendorGuid)[0]) &&\r
+        (((INT32 *) VendorGuid)[1] == ((INT32 *) &VariableHeader->VendorGuid)[1]) &&\r
+        (((INT32 *) VendorGuid)[2] == ((INT32 *) &VariableHeader->VendorGuid)[2]) &&\r
+        (((INT32 *) VendorGuid)[3] == ((INT32 *) &VariableHeader->VendorGuid)[3])\r
         ) {\r
-      ASSERT (NameSizeOfVariable (Variable) != 0);\r
+      ASSERT (NameSizeOfVariable (VariableHeader) != 0);\r
       Point = (VOID *) GetVariableNamePtr (Variable);\r
-      if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable)) == 0) {\r
+      if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader))) {\r
         PtrTrack->CurrPtr = Variable;\r
         return EFI_SUCCESS;\r
       }\r
@@ -323,26 +412,29 @@ CompareWithValidVariable (
 }\r
 \r
 /**\r
-  Return the variable store header and the index table based on the Index.\r
+  Return the variable store header and the store info based on the Index.\r
 \r
   @param Type       The type of the variable store.\r
-  @param IndexTable Return the index table.\r
+  @param StoreInfo  Return the store info.\r
 \r
   @return  Pointer to the variable store header.\r
 **/\r
 VARIABLE_STORE_HEADER *\r
 GetVariableStore (\r
   IN VARIABLE_STORE_TYPE         Type,\r
-  OUT VARIABLE_INDEX_TABLE       **IndexTable  OPTIONAL\r
+  OUT VARIABLE_STORE_INFO        *StoreInfo\r
   )\r
 {\r
-  EFI_HOB_GUID_TYPE           *GuidHob;\r
-  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
-  VARIABLE_STORE_HEADER       *VariableStoreHeader;\r
-\r
-  if (IndexTable != NULL) {\r
-    *IndexTable       = NULL;\r
-  }\r
+  EFI_HOB_GUID_TYPE                     *GuidHob;\r
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;\r
+  VARIABLE_STORE_HEADER                 *VariableStoreHeader;\r
+  EFI_PHYSICAL_ADDRESS                  NvStorageBase;\r
+  UINT32                                NvStorageSize;\r
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;\r
+  UINT32                                BackUpOffset;\r
+\r
+  StoreInfo->IndexTable = NULL;\r
+  StoreInfo->FtwLastWriteData = NULL;\r
   VariableStoreHeader = NULL;\r
   switch (Type) {\r
     case VariableStoreTypeHob:\r
@@ -357,10 +449,42 @@ GetVariableStore (
         //\r
         // The content of NV storage for variable is not reliable in recovery boot mode.\r
         //\r
-        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? \r
-                                                           PcdGet64 (PcdFlashNvStorageVariableBase64) : \r
-                                                           PcdGet32 (PcdFlashNvStorageVariableBase)\r
-                                                          );\r
+\r
+        NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
+        NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? \r
+                                                PcdGet64 (PcdFlashNvStorageVariableBase64) : \r
+                                                PcdGet32 (PcdFlashNvStorageVariableBase)\r
+                                               );\r
+        //\r
+        // First let FvHeader point to NV storage base.\r
+        //\r
+        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase;\r
+\r
+        //\r
+        // Check the FTW last write data hob.\r
+        //\r
+        BackUpOffset = 0;\r
+        GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
+        if (GuidHob != NULL) {\r
+          FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
+          if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
+            //\r
+            // Let FvHeader point to spare block.\r
+            //\r
+            FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress;\r
+            DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+          } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+            StoreInfo->FtwLastWriteData = FtwLastWriteData;\r
+            //\r
+            // Flash NV storage from the offset is backed up in spare block.\r
+            //\r
+            BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+            DEBUG ((EFI_D_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
+            //\r
+            // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.\r
+            //\r
+          }\r
+        }\r
 \r
         //\r
         // Check if the Firmware Volume is not corrupted\r
@@ -372,23 +496,21 @@ GetVariableStore (
 \r
         VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength);\r
 \r
-        if (IndexTable != NULL) {\r
-          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);\r
-          if (GuidHob != NULL) {\r
-            *IndexTable = GET_GUID_HOB_DATA (GuidHob);\r
-          } else {\r
-            //\r
-            // If it's the first time to access variable region in flash, create a guid hob to record\r
-            // VAR_ADDED type variable info.\r
-            // Note that as the resource of PEI phase is limited, only store the limited number of \r
-            // VAR_ADDED type variables to reduce access time.\r
-            //\r
-            *IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));\r
-            (*IndexTable)->Length      = 0;\r
-            (*IndexTable)->StartPtr    = GetStartPointer (VariableStoreHeader);\r
-            (*IndexTable)->EndPtr      = GetEndPointer   (VariableStoreHeader);\r
-            (*IndexTable)->GoneThrough = 0;\r
-          }\r
+        GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);\r
+        if (GuidHob != NULL) {\r
+          StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);\r
+        } else {\r
+          //\r
+          // If it's the first time to access variable region in flash, create a guid hob to record\r
+          // VAR_ADDED type variable info.\r
+          // Note that as the resource of PEI phase is limited, only store the limited number of \r
+          // VAR_ADDED type variables to reduce access time.\r
+          //\r
+          StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));\r
+          StoreInfo->IndexTable->Length      = 0;\r
+          StoreInfo->IndexTable->StartPtr    = GetStartPointer (VariableStoreHeader);\r
+          StoreInfo->IndexTable->EndPtr      = GetEndPointer   (VariableStoreHeader);\r
+          StoreInfo->IndexTable->GoneThrough = 0;\r
         }\r
       }\r
       break;\r
@@ -398,14 +520,118 @@ GetVariableStore (
       break;\r
   }\r
 \r
+  StoreInfo->VariableStoreHeader = VariableStoreHeader;\r
   return VariableStoreHeader;\r
 }\r
 \r
+/**\r
+  Get variable header that has consecutive content.\r
+\r
+  @param StoreInfo      Pointer to variable store info structure.\r
+  @param Variable       Pointer to the Variable Header.\r
+  @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.\r
+\r
+  @retval TRUE          Variable header is valid.\r
+  @retval FALSE         Variable header is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+GetVariableHeader (\r
+  IN VARIABLE_STORE_INFO    *StoreInfo,\r
+  IN VARIABLE_HEADER        *Variable,\r
+  OUT VARIABLE_HEADER       **VariableHeader\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  TargetAddress;\r
+  EFI_PHYSICAL_ADDRESS  SpareAddress;\r
+  EFI_HOB_GUID_TYPE     *GuidHob;\r
+  UINTN                 PartialHeaderSize;\r
+\r
+   //\r
+   // First assume variable header pointed by Variable is consecutive.\r
+   //\r
+  *VariableHeader = Variable;\r
+\r
+  if ((Variable != NULL) && (StoreInfo->FtwLastWriteData != NULL)) {\r
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
+    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
+    if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + sizeof (VARIABLE_HEADER)) > (UINTN) TargetAddress)) {\r
+      //\r
+      // Variable header pointed by Variable is inconsecutive,\r
+      // create a guid hob to combine the two partial variable header content together.\r
+      //\r
+      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
+      if (GuidHob != NULL) {\r
+        *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);\r
+      } else {\r
+        *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, sizeof (VARIABLE_HEADER));\r
+        PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;\r
+        //\r
+        // Partial content is in NV storage.\r
+        //\r
+        CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);\r
+        //\r
+        // Another partial content is in spare block.\r
+        //\r
+        CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, sizeof (VARIABLE_HEADER) - PartialHeaderSize);\r
+      }\r
+    }\r
+  }\r
+\r
+  return IsValidVariableHeader (*VariableHeader);\r
+}\r
+\r
+/**\r
+  Get variable name or data to output buffer.\r
+\r
+  @param  StoreInfo     Pointer to variable store info structure.\r
+  @param  NameOrData    Pointer to the variable name/data that may be inconsecutive.\r
+  @param  Size          Variable name/data size.\r
+  @param  Buffer        Pointer to output buffer to hold the variable name/data.\r
+\r
+**/\r
+VOID\r
+GetVariableNameOrData (\r
+  IN VARIABLE_STORE_INFO    *StoreInfo,\r
+  IN UINT8                  *NameOrData,\r
+  IN UINTN                  Size,\r
+  OUT UINT8                 *Buffer\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  TargetAddress;\r
+  EFI_PHYSICAL_ADDRESS  SpareAddress;\r
+  UINTN                 PartialSize;\r
\r
+  if (StoreInfo->FtwLastWriteData != NULL) {\r
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
+    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
+    if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) {\r
+      //\r
+      // Variable name/data is inconsecutive.\r
+      //\r
+      PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData;\r
+      //\r
+      // Partial content is in NV storage.\r
+      //\r
+      CopyMem (Buffer, NameOrData, PartialSize);\r
+      //\r
+      // Another partial content is in spare block.\r
+      //\r
+      CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize);\r
+      return;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Variable name/data is consecutive.\r
+  //\r
+  CopyMem (Buffer, NameOrData, Size);\r
+}\r
+\r
 /**\r
   Find the variable in the specified variable store.\r
 \r
-  @param  VariableStoreHeader Pointer to the variable store header.\r
-  @param  IndexTable          Pointer to the index table.\r
+  @param  StoreInfo           Pointer to the store info structure.\r
   @param  VariableName        Name of the variable to be found\r
   @param  VendorGuid          Vendor GUID to be found.\r
   @param  PtrTrack            Variable Track Pointer structure that contains Variable Information.\r
@@ -417,8 +643,7 @@ GetVariableStore (
 **/\r
 EFI_STATUS\r
 FindVariableEx (\r
-  IN VARIABLE_STORE_HEADER       *VariableStoreHeader,\r
-  IN VARIABLE_INDEX_TABLE        *IndexTable,\r
+  IN VARIABLE_STORE_INFO         *StoreInfo,\r
   IN CONST CHAR16                *VariableName,\r
   IN CONST EFI_GUID              *VendorGuid,\r
   OUT VARIABLE_POINTER_TRACK     *PtrTrack\r
@@ -431,6 +656,11 @@ FindVariableEx (
   UINTN                   Offset;\r
   BOOLEAN                 StopRecord;\r
   VARIABLE_HEADER         *InDeletedVariable;\r
+  VARIABLE_STORE_HEADER   *VariableStoreHeader;\r
+  VARIABLE_INDEX_TABLE    *IndexTable;\r
+  VARIABLE_HEADER         *VariableHeader;\r
+\r
+  VariableStoreHeader = StoreInfo->VariableStoreHeader;\r
 \r
   if (VariableStoreHeader == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -444,6 +674,7 @@ FindVariableEx (
     return EFI_NOT_FOUND;\r
   }\r
 \r
+  IndexTable = StoreInfo->IndexTable;\r
   PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);\r
   PtrTrack->EndPtr   = GetEndPointer   (VariableStoreHeader);\r
 \r
@@ -453,6 +684,7 @@ FindVariableEx (
   // No Variable Address equals zero, so 0 as initial value is safe.\r
   //\r
   MaxIndex   = NULL;\r
+  VariableHeader = NULL;\r
 \r
   if (IndexTable != NULL) {\r
     //\r
@@ -463,8 +695,9 @@ FindVariableEx (
       ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));\r
       Offset   += IndexTable->Index[Index];\r
       MaxIndex  = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset);\r
-      if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
-        if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);\r
+      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
+        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
           InDeletedVariable = PtrTrack->CurrPtr;\r
         } else {\r
           return EFI_SUCCESS;\r
@@ -486,7 +719,7 @@ FindVariableEx (
     // HOB exists but the variable cannot be found in HOB\r
     // If not found in HOB, then let's start from the MaxIndex we've found.\r
     //\r
-    Variable     = GetNextVariablePtr (MaxIndex);\r
+    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);\r
     LastVariable = MaxIndex;\r
   } else {\r
     //\r
@@ -501,8 +734,8 @@ FindVariableEx (
   // Find the variable by walk through variable store\r
   //\r
   StopRecord = FALSE;\r
-  while ((Variable < PtrTrack->EndPtr) && IsValidVariableHeader (Variable)) {\r
-    if (Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {\r
+    if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
       //\r
       // Record Variable in VariableIndex HOB\r
       //\r
@@ -520,8 +753,8 @@ FindVariableEx (
         }\r
       }\r
 \r
-      if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
-        if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
+        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
           InDeletedVariable = PtrTrack->CurrPtr;\r
         } else {\r
           return EFI_SUCCESS;\r
@@ -529,7 +762,7 @@ FindVariableEx (
       }\r
     }\r
 \r
-    Variable = GetNextVariablePtr (Variable);\r
+    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);\r
   }\r
   //\r
   // If gone through the VariableStore, that means we never find in Firmware any more.\r
@@ -549,6 +782,7 @@ FindVariableEx (
   @param  VariableName  Name of the variable to be found\r
   @param  VendorGuid    Vendor GUID to be found.\r
   @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.\r
+  @param  StoreInfo     Return the store info.\r
 \r
   @retval  EFI_SUCCESS            Variable found successfully\r
   @retval  EFI_NOT_FOUND          Variable not found\r
@@ -558,12 +792,11 @@ EFI_STATUS
 FindVariable (\r
   IN CONST  CHAR16            *VariableName,\r
   IN CONST  EFI_GUID          *VendorGuid,\r
-  OUT VARIABLE_POINTER_TRACK  *PtrTrack\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
+  OUT VARIABLE_STORE_INFO     *StoreInfo\r
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  VARIABLE_STORE_HEADER       *VariableStoreHeader;\r
-  VARIABLE_INDEX_TABLE        *IndexTable;\r
   VARIABLE_STORE_TYPE         Type;\r
 \r
   if (VariableName[0] != 0 && VendorGuid == NULL) {\r
@@ -571,10 +804,9 @@ FindVariable (
   }\r
 \r
   for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
-    VariableStoreHeader = GetVariableStore (Type, &IndexTable);\r
+    GetVariableStore (Type, StoreInfo);\r
     Status = FindVariableEx (\r
-               VariableStoreHeader,\r
-               IndexTable,\r
+               StoreInfo,\r
                VariableName,\r
                VendorGuid, \r
                PtrTrack\r
@@ -627,6 +859,8 @@ PeiGetVariable (
   VARIABLE_POINTER_TRACK  Variable;\r
   UINTN                   VarDataSize;\r
   EFI_STATUS              Status;\r
+  VARIABLE_STORE_INFO     StoreInfo;\r
+  VARIABLE_HEADER         *VariableHeader;\r
 \r
   if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -635,23 +869,25 @@ PeiGetVariable (
   //\r
   // Find existing variable\r
   //\r
-  Status = FindVariable (VariableName, VariableGuid, &Variable);\r
+  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);\r
+\r
   //\r
   // Get data size\r
   //\r
-  VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
+  VarDataSize = DataSizeOfVariable (VariableHeader);\r
   if (*DataSize >= VarDataSize) {\r
     if (Data == NULL) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
 \r
-    CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
+    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader), VarDataSize, Data);\r
 \r
     if (Attributes != NULL) {\r
-      *Attributes = Variable.CurrPtr->Attributes;\r
+      *Attributes = VariableHeader->Attributes;\r
     }\r
 \r
     *DataSize = VarDataSize;\r
@@ -704,16 +940,19 @@ PeiGetNextVariableName (
   VARIABLE_POINTER_TRACK  Variable;\r
   VARIABLE_POINTER_TRACK  VariableInHob;\r
   VARIABLE_POINTER_TRACK  VariablePtrTrack;\r
-  VARIABLE_INDEX_TABLE    *IndexTable;\r
   UINTN                   VarNameSize;\r
   EFI_STATUS              Status;\r
   VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];\r
+  VARIABLE_HEADER         *VariableHeader;\r
+  VARIABLE_STORE_INFO     StoreInfo;\r
+  VARIABLE_STORE_INFO     StoreInfoForNv;\r
+  VARIABLE_STORE_INFO     StoreInfoForHob;\r
 \r
   if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  Status = FindVariable (VariableName, VariableGuid, &Variable);\r
+  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);\r
   if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {\r
     return Status;\r
   }\r
@@ -722,20 +961,18 @@ PeiGetNextVariableName (
     //\r
     // If variable name is not NULL, get next variable\r
     //\r
-    Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);\r
+    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
   }\r
 \r
-  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, NULL);\r
-  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore (VariableStoreTypeNv, NULL);\r
+  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);\r
+  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);\r
 \r
   while (TRUE) {\r
     //\r
     // Switch from HOB to Non-Volatile.\r
     //\r
-    while ((Variable.CurrPtr >= Variable.EndPtr) ||\r
-           (Variable.CurrPtr == NULL)            ||\r
-           !IsValidVariableHeader (Variable.CurrPtr)\r
-          ) {\r
+    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {\r
       //\r
       // Find current storage index\r
       //\r
@@ -764,31 +1001,24 @@ PeiGetNextVariableName (
       Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
       Variable.EndPtr   = GetEndPointer   (VariableStoreHeader[Type]);\r
       Variable.CurrPtr  = Variable.StartPtr;\r
+      GetVariableStore (Type, &StoreInfo);\r
     }\r
 \r
-    if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
-      if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+    if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+      if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
         //\r
         // If it is a IN_DELETED_TRANSITION variable,\r
         // and there is also a same ADDED one at the same time,\r
         // don't return it.\r
         //\r
-        for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
-          if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {\r
-            break;\r
-          }\r
-        }\r
-        ASSERT (Type < VariableStoreTypeMax);\r
-        GetVariableStore (Type, &IndexTable);\r
         Status = FindVariableEx (\r
-                   VariableStoreHeader[Type],\r
-                   IndexTable,\r
+                   &StoreInfo,\r
                    GetVariableNamePtr (Variable.CurrPtr),\r
-                   &Variable.CurrPtr->VendorGuid,\r
+                   &VariableHeader->VendorGuid,\r
                    &VariablePtrTrack\r
                    );\r
-        if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {\r
-          Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+        if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) {\r
+          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
           continue;\r
         }\r
       }\r
@@ -800,25 +1030,24 @@ PeiGetNextVariableName (
           (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))\r
          ) {\r
         Status = FindVariableEx (\r
-                   VariableStoreHeader[VariableStoreTypeHob],\r
-                   NULL,\r
+                   &StoreInfoForHob,\r
                    GetVariableNamePtr (Variable.CurrPtr),\r
-                   &Variable.CurrPtr->VendorGuid, \r
+                   &VariableHeader->VendorGuid, \r
                    &VariableInHob\r
                    );\r
         if (!EFI_ERROR (Status)) {\r
-          Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
           continue;\r
         }\r
       }\r
 \r
-      VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
+      VarNameSize = NameSizeOfVariable (VariableHeader);\r
       ASSERT (VarNameSize != 0);\r
 \r
       if (VarNameSize <= *VariableNameSize) {\r
-        CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
+        GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr), VarNameSize, (UINT8 *) VariableName);\r
 \r
-        CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
+        CopyMem (VariableGuid, &VariableHeader->VendorGuid, sizeof (EFI_GUID));\r
 \r
         Status = EFI_SUCCESS;\r
       } else {\r
@@ -831,7 +1060,7 @@ PeiGetNextVariableName (
       //\r
       return Status;\r
     } else {\r
-      Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
     }\r
   }\r
 }\r
index e0d8679..55277b0 100644 (file)
@@ -3,7 +3,7 @@
   The internal header file includes the common header files, defines\r
   internal structure and functions used by PeiVariable module.\r
 \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\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
@@ -31,6 +31,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Guid/VariableFormat.h>\r
 #include <Guid/VariableIndexTable.h>\r
 #include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/FaultTolerantWrite.h>\r
 \r
 typedef enum {\r
   VariableStoreTypeHob,\r
@@ -38,6 +39,17 @@ typedef enum {
   VariableStoreTypeMax\r
 } VARIABLE_STORE_TYPE;\r
 \r
+typedef struct {\r
+  VARIABLE_STORE_HEADER                   *VariableStoreHeader;\r
+  VARIABLE_INDEX_TABLE                    *IndexTable;\r
+  //\r
+  // If it is not NULL, it means there may be an inconsecutive variable whose\r
+  // partial content is still in NV storage, but another partial content is backed up\r
+  // in spare block.\r
+  //\r
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA    *FtwLastWriteData;\r
+} VARIABLE_STORE_INFO;\r
+\r
 //\r
 // Functions\r
 //\r
index da07cf7..8bae162 100644 (file)
@@ -3,7 +3,7 @@
 #  Implement ReadOnly Variable Services required by PEIM and install\r
 #  PEI ReadOnly Varaiable2 PPI. These services operates the non-volatile storage space.\r
 #\r
-#  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\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
   gEfiVariableGuid\r
   gEfiVariableIndexTableGuid\r
   gEfiSystemNvDataFvGuid\r
+  gEdkiiFaultTolerantWriteGuid\r
 \r
 [Ppis]\r
-  gEfiPeiReadOnlyVariable2PpiGuid                ## SOMETIMES_PRODUCES (Not for boot mode RECOVERY)\r
+  gEfiPeiReadOnlyVariable2PpiGuid                ## PRODUCES\r
 \r
 [Pcd]\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase    ## CONSUMES\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64  ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase      ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64    ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize      ## CONSUMES\r
 \r
 [Depex]\r
-  TRUE\r
+  gEdkiiFaultTolerantWriteGuid\r
 \r
 #\r
 #  [BootMode]\r
index 9f983ff..09b8b4b 100644 (file)
@@ -2582,6 +2582,135 @@ ReclaimForOS(
   }\r
 }\r
 \r
+/**\r
+  Init non-volatile variable store.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+  @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.\r
+\r
+**/\r
+EFI_STATUS\r
+InitNonVolatileVariableStore (\r
+  VOID\r
+  )\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;\r
+  VARIABLE_HEADER                       *NextVariable;\r
+  EFI_PHYSICAL_ADDRESS                  VariableStoreBase;\r
+  UINT64                                VariableStoreLength;\r
+  UINTN                                 VariableSize;\r
+  EFI_HOB_GUID_TYPE                     *GuidHob;\r
+  EFI_PHYSICAL_ADDRESS                  NvStorageBase;\r
+  UINT8                                 *NvStorageData;\r
+  UINT32                                NvStorageSize;\r
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;\r
+  UINT32                                BackUpOffset;\r
+  UINT32                                BackUpSize;\r
+\r
+  mVariableModuleGlobal->FvbInstance = NULL;\r
+\r
+  //\r
+  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+  // is stored with common variable in the same NV region. So the platform integrator should\r
+  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
+  // PcdFlashNvStorageVariableSize.\r
+  //\r
+  ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
+\r
+  //\r
+  // Allocate runtime memory used for a memory copy of the FLASH region.\r
+  // Keep the memory and the FLASH in sync as updates occur.\r
+  //\r
+  NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
+  NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
+  if (NvStorageData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageBase == 0) {\r
+    NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  //\r
+  // Copy NV storage data to the memory buffer.\r
+  //\r
+  CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
+\r
+  //\r
+  // Check the FTW last write data hob.\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
+  if (GuidHob != NULL) {\r
+    FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
+    if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
+      DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+      //\r
+      // Copy the backed up NV storage data to the memory buffer from spare block.\r
+      //\r
+      CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
+    } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
+               (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+      //\r
+      // Flash NV storage from the offset is backed up in spare block.\r
+      //\r
+      BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+      BackUpSize = NvStorageSize - BackUpOffset;\r
+      DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
+      //\r
+      // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
+      //\r
+      CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+    }\r
+  }\r
+\r
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;\r
+\r
+  //\r
+  // Check if the Firmware Volume is not corrupted\r
+  //\r
+  if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
+    FreePool (NvStorageData);\r
+    DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
+  VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
+\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+  mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
+  if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
+    FreePool (NvStorageData);\r
+    DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  ASSERT(mNvVariableCache->Size == VariableStoreLength);\r
+\r
+  //\r
+  // The max variable or hardware error variable size should be < variable store size.\r
+  //\r
+  ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);\r
+\r
+  //\r
+  // Parse non-volatile variable data and get last variable offset.\r
+  //\r
+  NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
+  while (IsValidVariableHeader (NextVariable)) {\r
+    VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+    if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    }\r
+\r
+    NextVariable = GetNextVariablePtr (NextVariable);\r
+  }\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Flush the HOB variable to flash.\r
 \r
@@ -2673,7 +2802,7 @@ FlushHobVariableToFlash (
 }\r
 \r
 /**\r
-  Initializes variable write service after FVB was ready.\r
+  Initializes variable write service after FTW was ready.\r
 \r
   @retval EFI_SUCCESS          Function successfully executed.\r
   @retval Others               Fail to initialize the variable service.\r
@@ -2689,8 +2818,18 @@ VariableWriteServiceInitialize (
   UINTN                           Index;\r
   UINT8                           Data;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  EFI_PHYSICAL_ADDRESS            NvStorageBase;\r
 \r
-  VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+  NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageBase == 0) {\r
+    NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\r
+\r
+  //\r
+  // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
  \r
   //\r
@@ -2737,12 +2876,8 @@ VariableCommonInitialize (
   EFI_STATUS                      Status;\r
   VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
   VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
-  VARIABLE_HEADER                 *NextVariable;\r
-  EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
-  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
   UINT64                          VariableStoreLength;\r
   UINTN                           ScratchSize;\r
-  UINTN                           VariableSize;\r
   EFI_HOB_GUID_TYPE               *GuidHob;\r
 \r
   //\r
@@ -2755,14 +2890,6 @@ VariableCommonInitialize (
 \r
   InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
 \r
-  //\r
-  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
-  // is stored with common variable in the same NV region. So the platform integrator should\r
-  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
-  // PcdFlashNvStorageVariableSize.\r
-  //\r
-  ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
-\r
   //\r
   // Get HOB variable store.\r
   //\r
@@ -2773,6 +2900,7 @@ VariableCommonInitialize (
     if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
       mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
       if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+        FreePool (mVariableModuleGlobal);\r
         return EFI_OUT_OF_RESOURCES;\r
       }\r
     } else {\r
@@ -2786,6 +2914,9 @@ VariableCommonInitialize (
   ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
   VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
   if (VolatileVariableStore == NULL) {\r
+    if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+      FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
+    }\r
     FreePool (mVariableModuleGlobal);\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -2797,7 +2928,6 @@ VariableCommonInitialize (
   //\r
   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
-  mVariableModuleGlobal->FvbInstance = NULL;\r
 \r
   CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
   VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);\r
@@ -2807,74 +2937,13 @@ VariableCommonInitialize (
   VolatileVariableStore->Reserved1   = 0;\r
 \r
   //\r
-  // Get non-volatile variable store.\r
-  //\r
-\r
-  TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
-  if (TempVariableStoreHeader == 0) {\r
-    TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
-  }\r
-\r
-  //\r
-  // Check if the Firmware Volume is not corrupted\r
-  //\r
-  if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||\r
-      (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {\r
-    Status = EFI_VOLUME_CORRUPTED;\r
-    DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
-    goto Done;\r
-  }\r
-\r
-  VariableStoreBase       = TempVariableStoreHeader + \\r
-                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-  VariableStoreLength     = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
-                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-\r
-  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
-  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
-    Status = EFI_VOLUME_CORRUPTED;\r
-    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
-    goto Done;\r
-  }  \r
-  ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
-    \r
-  //\r
-  // The max variable or hardware error variable size should be < variable store size.\r
-  //\r
-  ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);\r
-\r
-  //\r
-  // Parse non-volatile variable data and get last variable offset.\r
-  //\r
-  NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
-  while (IsValidVariableHeader (NextVariable)) {\r
-    VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
-    if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
-    } else {\r
-      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
-    }\r
-\r
-    NextVariable = GetNextVariablePtr (NextVariable);\r
-  }\r
-\r
-  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
-    \r
-  //\r
-  // Allocate runtime memory used for a memory copy of the FLASH region.\r
-  // Keep the memory and the FLASH in sync as updates occur\r
+  // Init non-volatile variable store.\r
   //\r
-  mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
-  if (mNvVariableCache == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
-  }\r
-  CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
-  Status = EFI_SUCCESS;\r
-\r
-Done:\r
+  Status = InitNonVolatileVariableStore ();\r
   if (EFI_ERROR (Status)) {\r
+    if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+      FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
+    }\r
     FreePool (mVariableModuleGlobal);\r
     FreePool (VolatileVariableStore);\r
   }\r
index b5e6ede..264a239 100644 (file)
@@ -39,6 +39,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Guid/EventGroup.h>\r
 #include <Guid/VariableFormat.h>\r
 #include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/FaultTolerantWrite.h>\r
 #include <Guid/HardwareErrorVariable.h>\r
 \r
 #define VARIABLE_RECLAIM_THRESHOLD (1024)\r
index 8cbefef..c712ba0 100644 (file)
@@ -68,6 +68,7 @@
   gEfiSystemNvDataFvGuid                        ## CONSUMES\r
   gEfiHardwareErrorVariableGuid                 ## SOMETIMES_CONSUMES\r
   gEfiEndOfDxeEventGroupGuid                    ## CONSUMES ## Event\r
+  gEdkiiFaultTolerantWriteGuid                  ## CONSUMES\r
 \r
 [Pcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r
index c229805..89ec686 100644 (file)
@@ -77,6 +77,7 @@
   gSmmVariableWriteGuid                         ## PRODUCES ## SMM Variable Write Guid 
   gEfiSystemNvDataFvGuid                        ## CONSUMES
   gEfiHardwareErrorVariableGuid                 ## SOMETIMES_CONSUMES
+  gEdkiiFaultTolerantWriteGuid                  ## CONSUMES
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize