SecurityPkg: Variable drivers robustly handle crashes during Reclaim().
authorStar Zeng <star.zeng@intel.com>
Wed, 3 Jul 2013 09:09:42 +0000 (09:09 +0000)
committerlzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 3 Jul 2013 09:09:42 +0000 (09:09 +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: PEI variable and early phase(before FTW protocol ready) of DXE variable can check the FTW last write status provided by FaultTolerantWritePei 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@14455 6f19259b-4bc3-4df7-8a09-765794883524

SecurityPkg/VariableAuthenticated/Pei/Variable.c
SecurityPkg/VariableAuthenticated/Pei/Variable.h
SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf
SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf

index 38b9170..274feb3 100644 (file)
@@ -172,7 +172,6 @@ GetVariableNamePtr (
   IN  VARIABLE_HEADER   *Variable\r
   )\r
 {\r
-\r
   return (CHAR16 *) (Variable + 1);\r
 }\r
 \r
@@ -180,14 +179,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
@@ -196,8 +197,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
@@ -206,34 +207,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
@@ -247,7 +262,6 @@ GetVariableStoreStatus (
   IN VARIABLE_STORE_HEADER *VarStoreHeader\r
   )\r
 {\r
-       \r
   if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
       VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
       VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
@@ -271,11 +285,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
@@ -286,7 +374,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
@@ -303,14 +393,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
@@ -321,26 +411,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 Type       The type of the variable store.\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
@@ -355,10 +448,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
@@ -370,23 +495,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
@@ -396,14 +519,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
@@ -415,8 +642,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
@@ -429,6 +655,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
@@ -442,6 +673,7 @@ FindVariableEx (
     return EFI_NOT_FOUND;\r
   }\r
 \r
+  IndexTable = StoreInfo->IndexTable;\r
   PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);\r
   PtrTrack->EndPtr   = GetEndPointer   (VariableStoreHeader);\r
 \r
@@ -451,6 +683,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
@@ -461,8 +694,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
@@ -484,7 +718,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
@@ -499,8 +733,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
@@ -518,8 +752,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
@@ -527,7 +761,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
@@ -547,6 +781,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
@@ -556,12 +791,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
@@ -569,10 +803,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
@@ -625,6 +858,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
@@ -633,23 +868,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
@@ -702,16 +939,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
@@ -720,20 +960,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
@@ -762,31 +1000,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
@@ -798,25 +1029,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
@@ -829,7 +1059,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 a85d3bb..7693522 100644 (file)
@@ -2,7 +2,7 @@
   The internal header file includes the common header files, defines\r
   internal structure and functions used by PeiVariable module.\r
 \r
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 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
@@ -30,6 +30,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Guid/AuthenticatedVariableFormat.h>\r
 #include <Guid/VariableIndexTable.h>\r
 #include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/FaultTolerantWrite.h>\r
 \r
 typedef enum {\r
   VariableStoreTypeHob,\r
@@ -37,6 +38,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 e74143c..16ac97a 100644 (file)
@@ -1,7 +1,7 @@
 ## @file\r
 #  The component description for PEI variable driver. \r
 #\r
-# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 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
   gEfiAuthenticatedVariableGuid\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 576623e..ef123d2 100644 (file)
@@ -3068,6 +3068,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
@@ -3159,7 +3288,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
@@ -3175,8 +3304,18 @@ VariableWriteServiceInitialize (
   UINTN                           Index;\r
   UINT8                           Data;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  EFI_PHYSICAL_ADDRESS            NvStorageBase;\r
+\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
-  VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\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
@@ -3229,12 +3368,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
@@ -3247,14 +3382,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
@@ -3265,6 +3392,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
@@ -3278,6 +3406,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
@@ -3289,7 +3420,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, &gEfiAuthenticatedVariableGuid);\r
   VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);\r
@@ -3299,74 +3429,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
+  // Init non-volatile variable store.\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
-  //\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 f394414..ebd0b50 100644 (file)
@@ -41,6 +41,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Guid/AuthenticatedVariableFormat.h>\r
 #include <Guid/ImageAuthentication.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 dbd7d6e..4904ada 100644 (file)
@@ -6,7 +6,7 @@
 #  This external input must be validated carefully to avoid security issue like\r
 #  buffer overflow, integer overflow.\r
 #\r
-# Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 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
@@ -84,6 +84,7 @@
   gEfiCertDbGuid\r
   gEfiHardwareErrorVariableGuid                 ## SOMETIMES_CONSUMES\r
   gEfiEndOfDxeEventGroupGuid                    ## CONSUMES ## Event\r
+  gEdkiiFaultTolerantWriteGuid                  ## CONSUMES\r
 \r
 [Pcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r
index a9a1097..4180309 100644 (file)
@@ -14,7 +14,7 @@
 #  This external input must be validated carefully to avoid security issue like\r
 #  buffer overflow, integer overflow.\r
 #\r
-# Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2010 - 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
@@ -89,6 +89,7 @@
   gEfiSystemNvDataFvGuid                        ## CONSUMES\r
   gEfiCertDbGuid\r
   gEfiHardwareErrorVariableGuid                 ## SOMETIMES_CONSUMES\r
+  gEdkiiFaultTolerantWriteGuid                  ## CONSUMES\r
 \r
 [Pcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r