]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
1. The original code has a bug on calculate the size of SCRATCH_SIZE. It should be...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index f2e3121513845d62ec6156535a424bad388d4335..62025c9ee1dc0471f09ff7ccd9121c0aef3b29ad 100644 (file)
@@ -3,7 +3,7 @@
   Implement all four UEFI Runtime Variable services for the nonvolatile\r
   and volatile storage space and install variable architecture protocol.\r
   \r
-Copyright (c) 2006 - 2008, Intel Corporation                                                         \r
+Copyright (c) 2006 - 2009, Intel Corporation                                                         \r
 All rights reserved. This program and the accompanying materials                          \r
 are licensed and made available under the terms and conditions of the BSD License         \r
 which accompanies this distribution.  The full text of the license may be found at        \r
@@ -37,6 +37,8 @@ VARIABLE_CACHE_ENTRY mVariableCache[] = {
 };\r
 \r
 VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+EFI_EVENT          mFvbRegistration = NULL;\r
+\r
 \r
 /**\r
   Acquires lock only at boot time. Simply returns at runtime.\r
@@ -137,7 +139,7 @@ UpdateVariableInfo (
       StrCpy (gVariableInfo->Name, VariableName);\r
       gVariableInfo->Volatile = Volatile;\r
 \r
-      gBS->InstallConfigurationTable (&gEfiVariableInfoGuid, gVariableInfo);\r
+      gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
     }\r
 \r
     \r
@@ -213,7 +215,7 @@ IsValidVariableHeader (
   @param Volatile                Point out the Variable is Volatile or Non-Volatile\r
   @param SetByIndex              TRUE if target pointer is given as index\r
                                  FALSE if target pointer is absolute\r
-  @param Instance                Instance of FV Block services\r
+  @param Fvb                     Pointer to the writable FVB protocol\r
   @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
                                  structure\r
   @param DataSize                Size of data to be written\r
@@ -225,13 +227,13 @@ IsValidVariableHeader (
 **/\r
 EFI_STATUS\r
 UpdateVariableStore (\r
-  IN  VARIABLE_GLOBAL         *Global,\r
-  IN  BOOLEAN                 Volatile,\r
-  IN  BOOLEAN                 SetByIndex,\r
-  IN  UINTN                   Instance,\r
-  IN  UINTN                   DataPtrIndex,\r
-  IN  UINT32                  DataSize,\r
-  IN  UINT8                   *Buffer\r
+  IN  VARIABLE_GLOBAL                     *Global,\r
+  IN  BOOLEAN                             Volatile,\r
+  IN  BOOLEAN                             SetByIndex,\r
+  IN  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb,\r
+  IN  UINTN                               DataPtrIndex,\r
+  IN  UINT32                              DataSize,\r
+  IN  UINT8                               *Buffer\r
   )\r
 {\r
   EFI_FV_BLOCK_MAP_ENTRY      *PtrBlockMapEntry;\r
@@ -255,7 +257,9 @@ UpdateVariableStore (
   // Check if the Data is Volatile\r
   //\r
   if (!Volatile) {\r
-    EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);\r
+    Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
     //\r
     // Data Pointer should point to the actual Address where data is to be\r
@@ -310,18 +314,18 @@ UpdateVariableStore (
       //\r
       if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
         if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
-          Status = EfiFvbWriteBlock (\r
-                    Instance,\r
+          Status = Fvb->Write (\r
+                    Fvb,\r
                     LbaNumber,\r
                     (UINTN) (CurrWritePtr - LinearOffset),\r
                     &CurrWriteSize,\r
                     CurrBuffer\r
                     );\r
-            return Status;\r
+          return Status;\r
         } else {\r
           Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
-          Status = EfiFvbWriteBlock (\r
-                    Instance,\r
+          Status = Fvb->Write (\r
+                    Fvb,\r
                     LbaNumber,\r
                     (UINTN) (CurrWritePtr - LinearOffset),\r
                     &Size,\r
@@ -362,16 +366,19 @@ GetVariableStoreStatus (
   IN VARIABLE_STORE_HEADER *VarStoreHeader\r
   )\r
 {\r
-  if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&\r
+  if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
       VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
       VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
       ) {\r
 \r
     return EfiValid;\r
-  } else if (VarStoreHeader->Signature == 0xffffffff &&\r
-           VarStoreHeader->Size == 0xffffffff &&\r
-           VarStoreHeader->Format == 0xff &&\r
-           VarStoreHeader->State == 0xff\r
+  } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
+             VarStoreHeader->Size == 0xffffffff &&\r
+             VarStoreHeader->Format == 0xff &&\r
+             VarStoreHeader->State == 0xff\r
           ) {\r
 \r
     return EfiRaw;\r
@@ -589,6 +596,13 @@ Reclaim (
   CHAR16                *UpdatingVariableNamePtr;\r
 \r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
+  //\r
+  // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
+  //\r
+  if (!IsVolatile) {\r
+    mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+    mVariableModuleGlobal->HwErrVariableTotalSize  = 0;\r
+  }\r
 \r
   //\r
   // Start Pointers for the variable.\r
@@ -654,6 +668,11 @@ Reclaim (
       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
       CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
       CurrPtr += VariableSize;\r
+      if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+      } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+      }\r
     }\r
     Variable = NextVariable;\r
   }\r
@@ -665,6 +684,11 @@ Reclaim (
     VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
     CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
     CurrPtr += VariableSize;\r
+    if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+    } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+    }\r
   }\r
 \r
   //\r
@@ -706,6 +730,11 @@ Reclaim (
         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
         ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
         CurrPtr += VariableSize;\r
+        if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+        } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+        }\r
       }\r
     }\r
 \r
@@ -765,7 +794,9 @@ UpdateVariableCache (
   UINTN                     Index;\r
 \r
   if (EfiAtRuntime ()) {\r
+    //\r
     // Don't use the cache at runtime\r
+    // \r
     return;\r
   }\r
 \r
@@ -774,7 +805,9 @@ UpdateVariableCache (
       if (StrCmp (VariableName, Entry->Name) == 0) { \r
         Entry->Attributes = Attributes;\r
         if (DataSize == 0) {\r
+          //\r
           // Delete Case\r
+          //\r
           if (Entry->DataSize != 0) {\r
             FreePool (Entry->Data);\r
           }\r
@@ -783,6 +816,8 @@ UpdateVariableCache (
           CopyMem (Entry->Data, Data, DataSize);\r
         } else {\r
           Entry->Data = AllocatePool (DataSize);\r
+          ASSERT (Entry->Data != NULL);\r
+\r
           Entry->DataSize = DataSize;\r
           CopyMem (Entry->Data, Data, DataSize);\r
         }\r
@@ -917,7 +952,7 @@ FindVariable (
   InDeletedVariable     = NULL;\r
   InDeletedStorageIndex = 0;\r
   for (Index = 0; Index < 2; Index++) {\r
-    while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
+    while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
       if (Variable[Index]->State == VAR_ADDED || \r
           Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
          ) {\r
@@ -1189,20 +1224,22 @@ RuntimeServiceSetVariable (
   IN VOID                    *Data\r
   )\r
 {\r
-  VARIABLE_POINTER_TRACK  Variable;\r
-  EFI_STATUS              Status;\r
-  VARIABLE_HEADER         *NextVariable;\r
-  UINTN                   VarNameSize;\r
-  UINTN                   VarNameOffset;\r
-  UINTN                   VarDataOffset;\r
-  UINTN                   VarSize;\r
-  UINT8                   State;\r
-  BOOLEAN                 Reclaimed;\r
-  UINTN                   *VolatileOffset;\r
-  UINTN                   *NonVolatileOffset;\r
-  UINT32                  Instance;\r
-  BOOLEAN                 Volatile;\r
-  EFI_PHYSICAL_ADDRESS    Point;\r
+  VARIABLE_POINTER_TRACK              Variable;\r
+  EFI_STATUS                          Status;\r
+  VARIABLE_HEADER                     *NextVariable;\r
+  UINTN                               VarNameSize;\r
+  UINTN                               VarNameOffset;\r
+  UINTN                               VarDataOffset;\r
+  UINTN                               VarSize;\r
+  UINT8                               State;\r
+  BOOLEAN                             Reclaimed;\r
+  UINTN                               *VolatileOffset;\r
+  UINTN                               *NonVolatileOffset;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  BOOLEAN                             Volatile;\r
+  EFI_PHYSICAL_ADDRESS                Point;\r
+  UINTN                               ScratchSize;\r
+  UINTN                               NonVolatileVarableStoreSize;\r
 \r
   //\r
   // Check input parameters\r
@@ -1241,7 +1278,7 @@ RuntimeServiceSetVariable (
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
   Reclaimed         = FALSE;\r
-  Instance          = mVariableModuleGlobal->FvbInstance;\r
+  Fvb               = mVariableModuleGlobal->FvbInstance;\r
   VolatileOffset    = &mVariableModuleGlobal->VolatileLastVariableOffset;\r
 \r
   //\r
@@ -1303,7 +1340,7 @@ RuntimeServiceSetVariable (
                  &mVariableModuleGlobal->VariableGlobal,\r
                  Variable.Volatile,\r
                  FALSE,\r
-                 Instance,\r
+                 Fvb,\r
                  (UINTN) &Variable.CurrPtr->State,\r
                  sizeof (UINT8),\r
                  &State\r
@@ -1337,7 +1374,7 @@ RuntimeServiceSetVariable (
                  &mVariableModuleGlobal->VariableGlobal,\r
                  Variable.Volatile,\r
                  FALSE,\r
-                 Instance,\r
+                 Fvb,\r
                  (UINTN) &Variable.CurrPtr->State,\r
                  sizeof (UINT8),\r
                  &State\r
@@ -1384,8 +1421,9 @@ RuntimeServiceSetVariable (
   // as a temporary storage.\r
   //\r
   NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
+  ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));\r
 \r
-  SetMem (NextVariable, FixedPcdGet32(PcdMaxVariableSize), 0xff);\r
+  SetMem (NextVariable, ScratchSize, 0xff);\r
 \r
   NextVariable->StartId     = VARIABLE_DATA;\r
   NextVariable->Attributes  = Attributes;\r
@@ -1425,10 +1463,11 @@ RuntimeServiceSetVariable (
     // Create a nonvolatile variable\r
     //\r
     Volatile = FALSE;\r
-    \r
-    if ((UINT32) (VarSize +*NonVolatileOffset) >\r
-          ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
-          ) {\r
+    NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
+    if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+      && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
+      || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+      && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
       if (EfiAtRuntime ()) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
@@ -1443,9 +1482,10 @@ RuntimeServiceSetVariable (
       //\r
       // If still no enough space, return out of resources\r
       //\r
-      if ((UINT32) (VarSize +*NonVolatileOffset) >\r
-            ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
-            ) {\r
+      if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+        && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
+        || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+        && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
@@ -1466,7 +1506,7 @@ RuntimeServiceSetVariable (
                &mVariableModuleGlobal->VariableGlobal,\r
                FALSE,\r
                TRUE,\r
-               Instance,\r
+               Fvb,\r
                *NonVolatileOffset,\r
                sizeof (VARIABLE_HEADER),\r
                (UINT8 *) NextVariable\r
@@ -1484,7 +1524,7 @@ RuntimeServiceSetVariable (
                &mVariableModuleGlobal->VariableGlobal,\r
                FALSE,\r
                TRUE,\r
-               Instance,\r
+               Fvb,\r
                *NonVolatileOffset,\r
                sizeof (VARIABLE_HEADER),\r
                (UINT8 *) NextVariable\r
@@ -1500,7 +1540,7 @@ RuntimeServiceSetVariable (
                &mVariableModuleGlobal->VariableGlobal,\r
                FALSE,\r
                TRUE,\r
-               Instance,\r
+               Fvb,\r
                *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
                (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
                (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
@@ -1517,7 +1557,7 @@ RuntimeServiceSetVariable (
                &mVariableModuleGlobal->VariableGlobal,\r
                FALSE,\r
                TRUE,\r
-               Instance,\r
+               Fvb,\r
                *NonVolatileOffset,\r
                sizeof (VARIABLE_HEADER),\r
                (UINT8 *) NextVariable\r
@@ -1529,6 +1569,11 @@ RuntimeServiceSetVariable (
 \r
     *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize);\r
 \r
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
+    }\r
   } else {\r
     //\r
     // Create a volatile variable\r
@@ -1562,7 +1607,7 @@ RuntimeServiceSetVariable (
                &mVariableModuleGlobal->VariableGlobal,\r
                TRUE,\r
                TRUE,\r
-               Instance,\r
+               Fvb,\r
                *VolatileOffset,\r
                (UINT32) VarSize,\r
                (UINT8 *) NextVariable\r
@@ -1585,7 +1630,7 @@ RuntimeServiceSetVariable (
                &mVariableModuleGlobal->VariableGlobal,\r
                Variable.Volatile,\r
                FALSE,\r
-               Instance,\r
+               Fvb,\r
                (UINTN) &Variable.CurrPtr->State,\r
                sizeof (UINT8),\r
                &State\r
@@ -1640,11 +1685,16 @@ RuntimeServiceQueryVariableInfo (
   VARIABLE_HEADER        *NextVariable;\r
   UINT64                 VariableSize;\r
   VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
+  UINT64                 CommonVariableTotalSize;\r
+  UINT64                 HwErrVariableTotalSize;\r
+\r
+  CommonVariableTotalSize = 0;\r
+  HwErrVariableTotalSize = 0;\r
 \r
   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
     //\r
     // Make sure the Attributes combination is supported by the platform.\r
@@ -1660,6 +1710,11 @@ RuntimeServiceQueryVariableInfo (
     // Make sure RT Attribute is set if we are in Runtime phase.\r
     //\r
     return EFI_INVALID_PARAMETER;\r
+  } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+    //\r
+    // Make sure Hw Attribute is set with NV.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
@@ -1681,18 +1736,23 @@ RuntimeServiceQueryVariableInfo (
   // with the storage size (excluding the storage header size).\r
   //\r
   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
-  *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
-\r
-  //\r
-  // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
-  //\r
-  *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
 \r
   //\r
   // Harware error record variable needs larger size.\r
   //\r
-  if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+  if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+    *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);\r
     *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
+  } else {\r
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+      ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
+      *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);\r
+    }\r
+\r
+    //\r
+    // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
+    //\r
+    *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
   }\r
 \r
   //\r
@@ -1703,7 +1763,7 @@ RuntimeServiceQueryVariableInfo (
   //\r
   // Now walk through the related variable store.\r
   //\r
-  while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {\r
+  while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
     NextVariable = GetNextVariablePtr (Variable);\r
     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
 \r
@@ -1714,14 +1774,22 @@ RuntimeServiceQueryVariableInfo (
       // since the space occupied by variables not marked with\r
       // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
       //\r
-      *RemainingVariableStorageSize -= VariableSize;\r
+      if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+        HwErrVariableTotalSize += VariableSize;\r
+      } else {\r
+        CommonVariableTotalSize += VariableSize;\r
+      }\r
     } else {\r
       //\r
       // Only care about Variables with State VAR_ADDED,because\r
       // the space not marked as VAR_ADDED is reclaimable now.\r
       //\r
       if (Variable->State == VAR_ADDED) {\r
-        *RemainingVariableStorageSize -= VariableSize;\r
+        if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          HwErrVariableTotalSize += VariableSize;\r
+        } else {\r
+          CommonVariableTotalSize += VariableSize;\r
+        }\r
       }\r
     }\r
 \r
@@ -1731,6 +1799,12 @@ RuntimeServiceQueryVariableInfo (
     Variable = NextVariable;\r
   }\r
 \r
+  if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
+  }else {\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+  }\r
+\r
   if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
     *MaximumVariableSize = 0;\r
   } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
@@ -1760,22 +1834,29 @@ ReclaimForOS(
   VOID       *Context\r
   )\r
 {\r
-  UINT32                          VarSize;\r
   EFI_STATUS                      Status;\r
+  UINTN                          CommonVariableSpace;\r
+  UINTN                          RemainingCommonVariableSpace;\r
+  UINTN                          RemainingHwErrVariableSpace;\r
 \r
-  VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
   Status  = EFI_SUCCESS; \r
 \r
+  CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
+\r
+  RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
+\r
+  RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
   //\r
   // Check if the free area is blow a threshold\r
   //\r
-  if ((VarSize - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
+  if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
+    || (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))){\r
     Status = Reclaim (\r
-              mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
-              &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
-              FALSE,\r
-              NULL\r
-              );\r
+            mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+            &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+            FALSE,\r
+            NULL\r
+            );\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
 }\r
@@ -1783,7 +1864,6 @@ ReclaimForOS(
 /**\r
   Initializes variable store area for non-volatile and volatile variable.\r
 \r
-  @param  ImageHandle           The Image handle of this driver.\r
   @param  SystemTable           The pointer of EFI_SYSTEM_TABLE.\r
 \r
   @retval EFI_SUCCESS           Function successfully executed.\r
@@ -1792,27 +1872,23 @@ ReclaimForOS(
 **/\r
 EFI_STATUS\r
 VariableCommonInitialize (\r
-  IN EFI_HANDLE         ImageHandle,\r
-  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
-  EFI_FIRMWARE_VOLUME_HEADER      *FwVolHeader;\r
-  CHAR8                           *CurrPtr;\r
   VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
   VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
   VARIABLE_HEADER                 *NextVariable;\r
-  UINT32                          Instance;\r
-  EFI_PHYSICAL_ADDRESS            FvVolHdr;\r
-  UINT64                          TempVariableStoreHeader;\r
+  EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
   EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
-  UINT64                          BaseAddress;\r
+  EFI_PHYSICAL_ADDRESS            BaseAddress;\r
   UINT64                          Length;\r
   UINTN                           Index;\r
   UINT8                           Data;\r
-  UINT64                          VariableStoreBase;\r
+  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
   UINT64                          VariableStoreLength;\r
   EFI_EVENT                       ReadyToBootEvent;\r
+  UINTN                           ScratchSize;\r
 \r
   Status = EFI_SUCCESS;\r
   //\r
@@ -1825,25 +1901,29 @@ VariableCommonInitialize (
 \r
   EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
   mVariableModuleGlobal->VariableGlobal.ReentrantState = 0;\r
+  mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+  mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
 \r
   //\r
-  // Allocate memory for volatile variable store\r
+  // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
   //\r
-  VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + FixedPcdGet32(PcdMaxVariableSize));\r
+  ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));\r
+  VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + ScratchSize);\r
   if (VolatileVariableStore == NULL) {\r
     FreePool (mVariableModuleGlobal);\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + FixedPcdGet32(PcdMaxVariableSize), 0xff);\r
+  SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + ScratchSize, 0xff);\r
 \r
   //\r
   //  Variable Specific Data\r
   //\r
   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
 \r
-  VolatileVariableStore->Signature                  = VARIABLE_STORE_SIGNATURE;\r
+  CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
   VolatileVariableStore->Size                       = FixedPcdGet32(PcdVariableStoreSize);\r
   VolatileVariableStore->Format                     = VARIABLE_STORE_FORMATTED;\r
   VolatileVariableStore->State                      = VARIABLE_STORE_HEALTHY;\r
@@ -1854,11 +1934,11 @@ VariableCommonInitialize (
   // Get non volatile varaible store\r
   //\r
 \r
-  TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
   VariableStoreBase = TempVariableStoreHeader + \\r
-                              (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
+                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
   VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
-                                (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
+                                (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
   //\r
   // Mark the variable storage region of the FLASH as RUNTIME\r
   //\r
@@ -1883,26 +1963,7 @@ VariableCommonInitialize (
   // Get address of non volatile variable store base\r
   //\r
   mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-\r
-  //\r
-  // Check Integrity\r
-  //\r
-  //\r
-  // Find the Correct Instance of the FV Block Service.\r
-  //\r
-  Instance  = 0;\r
-  CurrPtr   = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
-  while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {\r
-    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
-    if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {\r
-      mVariableModuleGlobal->FvbInstance = Instance;\r
-      break;\r
-    }\r
-\r
-    Instance++;\r
-  }\r
-\r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
   if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
     if (~VariableStoreHeader->Size == 0) {\r
       Status = UpdateVariableStore (\r
@@ -1929,18 +1990,25 @@ VariableCommonInitialize (
       }\r
     }\r
 \r
-    mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
     //\r
     // Parse non-volatile variable data and get last variable offset\r
     //\r
-    NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) CurrPtr);\r
+    NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
     Status        = EFI_SUCCESS;\r
 \r
     while (IsValidVariableHeader (NextVariable)) {\r
+      UINTN VariableSize = 0;\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) CurrPtr;\r
+    mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
 \r
     //\r
     // Check if the free area is really free.\r
@@ -1975,6 +2043,9 @@ VariableCommonInitialize (
                NULL, \r
                &ReadyToBootEvent\r
                );\r
+  } else {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
   }\r
 \r
 Done:\r
@@ -2003,6 +2074,14 @@ VariableClassAddressChangeEvent (
   IN VOID             *Context\r
   )\r
 {\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
   EfiConvertPointer (\r
     0x0,\r
     (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
@@ -2014,6 +2093,117 @@ VariableClassAddressChangeEvent (
   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
 }\r
 \r
+VOID\r
+EFIAPI\r
+FvbNotificationEvent (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          *HandleBuffer;\r
+  UINTN                               HandleCount;\r
+  UINTN                               Index;\r
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
+  EFI_FVB_ATTRIBUTES_2                Attributes;\r
+  EFI_SYSTEM_TABLE                    *SystemTable;\r
+  EFI_PHYSICAL_ADDRESS                NvStorageVariableBase;\r
+\r
+  SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
+  Fvb         = NULL;\r
+  \r
+  //\r
+  // Locate all handles of Fvb protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Get the FVB to access variable store\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                    (VOID **) &Fvb\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_NOT_FOUND;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Ensure this FVB protocol supported Write operation.\r
+    //\r
+    Status = Fvb->GetAttributes (Fvb, &Attributes);\r
+    if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
+      continue;     \r
+    }\r
+    //\r
+    // Compare the address and select the right one\r
+    //\r
+    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+    if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+      Status      = EFI_SUCCESS;\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+  if (!EFI_ERROR (Status) && Fvb != NULL) {\r
+    //\r
+    // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
+    //\r
+    Status = gBS->CloseEvent (Event);  \r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    Status = VariableCommonInitialize (Fvb);\r
+    ASSERT_EFI_ERROR (Status);\r
+  \r
+    SystemTable->RuntimeServices->GetVariable         = RuntimeServiceGetVariable;\r
+    SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
+    SystemTable->RuntimeServices->SetVariable         = RuntimeServiceSetVariable;\r
+    SystemTable->RuntimeServices->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
+  \r
+    //\r
+    // Now install the Variable Runtime Architectural Protocol on a new handle\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &mHandle,\r
+                  &gEfiVariableArchProtocolGuid, NULL,\r
+                  &gEfiVariableWriteArchProtocolGuid, NULL,\r
+                  NULL\r
+                  );\r
+    ASSERT_EFI_ERROR (Status);\r
+  \r
+    Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  VariableClassAddressChangeEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mVirtualAddressChangeEvent\r
+                  );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+}\r
 \r
 /**\r
   Variable Driver main entry point. The Variable driver places the 4 EFI\r
@@ -2034,36 +2224,16 @@ VariableServiceInitialize (
   IN EFI_SYSTEM_TABLE   *SystemTable\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-\r
-  Status = VariableCommonInitialize (ImageHandle, SystemTable);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  SystemTable->RuntimeServices->GetVariable         = RuntimeServiceGetVariable;\r
-  SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
-  SystemTable->RuntimeServices->SetVariable         = RuntimeServiceSetVariable;\r
-  SystemTable->RuntimeServices->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
-\r
   //\r
-  // Now install the Variable Runtime Architectural Protocol on a new handle\r
-  //\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &mHandle,\r
-                  &gEfiVariableArchProtocolGuid,        NULL,\r
-                  &gEfiVariableWriteArchProtocolGuid,   NULL,\r
-                  NULL\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  Status = gBS->CreateEventEx (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  VariableClassAddressChangeEvent,\r
-                  NULL,\r
-                  &gEfiEventVirtualAddressChangeGuid,\r
-                  &mVirtualAddressChangeEvent\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
+  // Register FvbNotificationEvent () notify function.\r
+  // \r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiFirmwareVolumeBlockProtocolGuid,\r
+    TPL_CALLBACK,\r
+    FvbNotificationEvent,\r
+    (VOID *)SystemTable,\r
+    &mFvbRegistration\r
+    );\r
 \r
   return EFI_SUCCESS;\r
 }\r