]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
MdeModulePkg Variable: Add emulated variable NV mode support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index 2dc303834bef79fe95e3243df46af5eb17814725..e8e19508cd9a3037be0033afff141291fcbed632 100644 (file)
@@ -16,8 +16,8 @@
   VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
   integer overflow. It should also check attribute to avoid authentication bypass.\r
 \r
-Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<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
@@ -34,6 +34,7 @@ VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
 \r
 ///\r
 /// Define a memory cache that improves the search performance for a variable.\r
+/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.\r
 ///\r
 VARIABLE_STORE_HEADER  *mNvVariableCache      = NULL;\r
 \r
@@ -97,20 +98,6 @@ AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {
 \r
 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;\r
 \r
-/**\r
-\r
-  SecureBoot Hook for auth variable update.\r
-\r
-  @param[in] VariableName                 Name of Variable to be found.\r
-  @param[in] VendorGuid                   Variable vendor GUID.\r
-**/\r
-VOID\r
-EFIAPI\r
-SecureBootHook (\r
-  IN CHAR16                                 *VariableName,\r
-  IN EFI_GUID                               *VendorGuid\r
-  );\r
-\r
 /**\r
   Routine used to track statistical information about variable usage.\r
   The data is stored in the EFI system table so it can be accessed later.\r
@@ -252,6 +239,8 @@ IsValidVariableHeader (
   @param Buffer                  Pointer to the buffer from which data is written.\r
 \r
   @retval EFI_INVALID_PARAMETER  Parameters not valid.\r
+  @retval EFI_UNSUPPORTED        Fvb is a NULL for Non-Volatile variable update.\r
+  @retval EFI_OUT_OF_RESOURCES   The remaining size is not enough.\r
   @retval EFI_SUCCESS            Variable store successfully updated.\r
 \r
 **/\r
@@ -274,26 +263,24 @@ UpdateVariableStore (
   UINT8                       *CurrBuffer;\r
   EFI_LBA                     LbaNumber;\r
   UINTN                       Size;\r
-  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;\r
   VARIABLE_STORE_HEADER       *VolatileBase;\r
   EFI_PHYSICAL_ADDRESS        FvVolHdr;\r
   EFI_PHYSICAL_ADDRESS        DataPtr;\r
   EFI_STATUS                  Status;\r
 \r
-  FwVolHeader = NULL;\r
+  FvVolHdr    = 0;\r
   DataPtr     = DataPtrIndex;\r
 \r
   //\r
   // Check if the Data is Volatile.\r
   //\r
-  if (!Volatile) {\r
+  if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
     if (Fvb == NULL) {\r
-      return EFI_INVALID_PARAMETER;\r
+      return EFI_UNSUPPORTED;\r
     }\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
     // written.\r
@@ -302,25 +289,38 @@ UpdateVariableStore (
       DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
     }\r
 \r
-    if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
-      return EFI_INVALID_PARAMETER;\r
+    if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
     }\r
   } else {\r
     //\r
     // Data Pointer should point to the actual Address where data is to be\r
     // written.\r
     //\r
-    VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
-    if (SetByIndex) {\r
-      DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
-    }\r
+    if (Volatile) {\r
+      VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+      if (SetByIndex) {\r
+        DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
+      }\r
 \r
-    if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
-      return EFI_INVALID_PARAMETER;\r
+      if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+    } else {\r
+      //\r
+      // Emulated non-volatile variable mode.\r
+      //\r
+      if (SetByIndex) {\r
+        DataPtr += (UINTN) mNvVariableCache;\r
+      }\r
+\r
+      if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
     }\r
 \r
     //\r
-    // If Volatile Variable just do a simple mem copy.\r
+    // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.\r
     //\r
     CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
     return EFI_SUCCESS;\r
@@ -329,7 +329,7 @@ UpdateVariableStore (
   //\r
   // If we are here we are dealing with Non-Volatile Variables.\r
   //\r
-  LinearOffset  = (UINTN) FwVolHeader;\r
+  LinearOffset  = (UINTN) FvVolHdr;\r
   CurrWritePtr  = (UINTN) DataPtr;\r
   CurrWriteSize = DataSize;\r
   CurrBuffer    = Buffer;\r
@@ -693,7 +693,7 @@ GetStartPointer (
   )\r
 {\r
   //\r
-  // The end of variable store.\r
+  // The start of variable store.\r
   //\r
   return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
 }\r
@@ -1001,7 +1001,7 @@ Reclaim (
   CommonUserVariableTotalSize = 0;\r
   HwErrVariableTotalSize  = 0;\r
 \r
-  if (IsVolatile) {\r
+  if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
     //\r
     // Start Pointers for the variable.\r
     //\r
@@ -1133,7 +1133,7 @@ Reclaim (
   // Install the new variable if it is not NULL.\r
   //\r
   if (NewVariable != NULL) {\r
-    if ((UINTN) (CurrPtr - ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
+    if (((UINTN) CurrPtr - (UINTN) ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
       //\r
       // No enough space to store the new variable.\r
       //\r
@@ -1169,13 +1169,21 @@ Reclaim (
     CurrPtr += NewVariableSize;\r
   }\r
 \r
-  if (IsVolatile) {\r
+  if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
     //\r
-    // If volatile variable store, just copy valid buffer.\r
+    // If volatile/emulated non-volatile variable store, just copy valid buffer.\r
     //\r
     SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
-    CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - ValidBuffer));\r
-    *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
+    CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer);\r
+    *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;\r
+    if (!IsVolatile) {\r
+      //\r
+      // Emulated non-volatile variable mode.\r
+      //\r
+      mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+      mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+      mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
+    }\r
     Status  = EFI_SUCCESS;\r
   } else {\r
     //\r
@@ -1186,7 +1194,7 @@ Reclaim (
               (VARIABLE_STORE_HEADER *) ValidBuffer\r
               );\r
     if (!EFI_ERROR (Status)) {\r
-      *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
+      *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;\r
       mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
       mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
       mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
@@ -1214,7 +1222,7 @@ Reclaim (
   }\r
 \r
 Done:\r
-  if (IsVolatile) {\r
+  if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
     FreePool (ValidBuffer);\r
   } else {\r
     //\r
@@ -1545,8 +1553,8 @@ GetLangFromSupportedLangCodes (
   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that\r
                                   contains a set of language codes in the format\r
                                   specified by Iso639Language.\r
-  @param[in]  Iso639Language      If TRUE, then all language codes are assumed to be\r
-                                  in ISO 639-2 format.  If FALSE, then all language\r
+  @param[in]  Iso639Language      If not zero, then all language codes are assumed to be\r
+                                  in ISO 639-2 format.  If zero, then all language\r
                                   codes are assumed to be in RFC 4646 language format\r
   @param[in]  ...                 A variable argument list that contains pointers to\r
                                   Null-terminated ASCII strings that contain one or more\r
@@ -1574,7 +1582,7 @@ CHAR8 *
 EFIAPI\r
 VariableGetBestLanguage (\r
   IN CONST CHAR8  *SupportedLanguages,\r
-  IN BOOLEAN      Iso639Language,\r
+  IN UINTN        Iso639Language,\r
   ...\r
   )\r
 {\r
@@ -1600,7 +1608,7 @@ VariableGetBestLanguage (
     //\r
     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
     //\r
-    if (!Iso639Language) {\r
+    if (Iso639Language == 0) {\r
       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
     }\r
 \r
@@ -1615,7 +1623,7 @@ VariableGetBestLanguage (
         //\r
         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
         //\r
-        if (!Iso639Language) {\r
+        if (Iso639Language == 0) {\r
           //\r
           // Skip ';' characters in Supported\r
           //\r
@@ -1637,13 +1645,13 @@ VariableGetBestLanguage (
         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
           VA_END (Args);\r
 \r
-          Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
+          Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
           Buffer[CompareLength] = '\0';\r
           return CopyMem (Buffer, Supported, CompareLength);\r
         }\r
       }\r
 \r
-      if (Iso639Language) {\r
+      if (Iso639Language != 0) {\r
         //\r
         // If ISO 639 mode, then each language can only be tested once\r
         //\r
@@ -1734,6 +1742,7 @@ CheckRemainingSpaceForConsistencyInternal (
     TotalNeededSize += VariableEntry->VariableSize;\r
     VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
   }\r
+  VA_END  (Args);\r
 \r
   if (RemainingVariableStorageSize >= TotalNeededSize) {\r
     //\r
@@ -1778,6 +1787,7 @@ CheckRemainingSpaceForConsistencyInternal (
       //\r
       // No enough space for Variable[Index].\r
       //\r
+      VA_END (Args);\r
       return FALSE;\r
     }\r
     //\r
@@ -1786,6 +1796,7 @@ CheckRemainingSpaceForConsistencyInternal (
     RemainingVariableStorageSize -= VariableEntry->VariableSize;\r
     VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
   }\r
+  VA_END  (Args);\r
 \r
   return TRUE;\r
 }\r
@@ -2150,7 +2161,6 @@ UpdateVariable (
   VARIABLE_POINTER_TRACK              *Variable;\r
   VARIABLE_POINTER_TRACK              NvVariable;\r
   VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
-  UINTN                               CacheOffset;\r
   UINT8                               *BufferForMerge;\r
   UINTN                               MergedBufSize;\r
   BOOLEAN                             DataReady;\r
@@ -2159,7 +2169,7 @@ UpdateVariable (
   BOOLEAN                             IsCommonUserVariable;\r
   AUTHENTICATED_VARIABLE_HEADER       *AuthVariable;\r
 \r
-  if (mVariableModuleGlobal->FvbInstance == NULL) {\r
+  if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
     //\r
     // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.\r
     //\r
@@ -2356,12 +2366,14 @@ UpdateVariable (
         CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr));\r
 \r
         //\r
-        // Set Max Common/Auth Variable Data Size as default MaxDataSize.\r
+        // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.\r
         //\r
         if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
           MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;\r
-        } else {\r
+        } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
           MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;\r
+        } else {\r
+          MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;\r
         }\r
 \r
         //\r
@@ -2469,6 +2481,8 @@ UpdateVariable (
         if (Variable->CurrPtr != NULL) {\r
           if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {\r
             CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
+          } else {\r
+            CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));\r
           }\r
         }\r
       }\r
@@ -2574,80 +2588,105 @@ UpdateVariable (
       }\r
       goto Done;\r
     }\r
-    //\r
-    // Four steps\r
-    // 1. Write variable header\r
-    // 2. Set variable state to header valid\r
-    // 3. Write variable data\r
-    // 4. Set variable state to valid\r
-    //\r
-    //\r
-    // Step 1:\r
-    //\r
-    CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
-    Status = UpdateVariableStore (\r
-               &mVariableModuleGlobal->VariableGlobal,\r
-               FALSE,\r
-               TRUE,\r
-               Fvb,\r
-               mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
-               (UINT32) GetVariableHeaderSize (),\r
-               (UINT8 *) NextVariable\r
-               );\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      goto Done;\r
-    }\r
+    if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
+      //\r
+      // Four steps\r
+      // 1. Write variable header\r
+      // 2. Set variable state to header valid\r
+      // 3. Write variable data\r
+      // 4. Set variable state to valid\r
+      //\r
+      //\r
+      // Step 1:\r
+      //\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 FALSE,\r
+                 TRUE,\r
+                 Fvb,\r
+                 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                 (UINT32) GetVariableHeaderSize (),\r
+                 (UINT8 *) NextVariable\r
+                 );\r
 \r
-    //\r
-    // Step 2:\r
-    //\r
-    NextVariable->State = VAR_HEADER_VALID_ONLY;\r
-    Status = UpdateVariableStore (\r
-               &mVariableModuleGlobal->VariableGlobal,\r
-               FALSE,\r
-               TRUE,\r
-               Fvb,\r
-               mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
-               sizeof (UINT8),\r
-               &NextVariable->State\r
-               );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      goto Done;\r
-    }\r
-    //\r
-    // Step 3:\r
-    //\r
-    Status = UpdateVariableStore (\r
-               &mVariableModuleGlobal->VariableGlobal,\r
-               FALSE,\r
-               TRUE,\r
-               Fvb,\r
-               mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),\r
-               (UINT32) (VarSize - GetVariableHeaderSize ()),\r
-               (UINT8 *) NextVariable + GetVariableHeaderSize ()\r
-               );\r
+      //\r
+      // Step 2:\r
+      //\r
+      NextVariable->State = VAR_HEADER_VALID_ONLY;\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 FALSE,\r
+                 TRUE,\r
+                 Fvb,\r
+                 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+                 sizeof (UINT8),\r
+                 &NextVariable->State\r
+                 );\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      goto Done;\r
-    }\r
-    //\r
-    // Step 4:\r
-    //\r
-    NextVariable->State = VAR_ADDED;\r
-    Status = UpdateVariableStore (\r
-               &mVariableModuleGlobal->VariableGlobal,\r
-               FALSE,\r
-               TRUE,\r
-               Fvb,\r
-               mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
-               sizeof (UINT8),\r
-               &NextVariable->State\r
-               );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      //\r
+      // Step 3:\r
+      //\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 FALSE,\r
+                 TRUE,\r
+                 Fvb,\r
+                 mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),\r
+                 (UINT32) (VarSize - GetVariableHeaderSize ()),\r
+                 (UINT8 *) NextVariable + GetVariableHeaderSize ()\r
+                 );\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      goto Done;\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      //\r
+      // Step 4:\r
+      //\r
+      NextVariable->State = VAR_ADDED;\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 FALSE,\r
+                 TRUE,\r
+                 Fvb,\r
+                 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+                 sizeof (UINT8),\r
+                 &NextVariable->State\r
+                 );\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+\r
+      //\r
+      // Update the memory copy of Flash region.\r
+      //\r
+      CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);\r
+    } else {\r
+      //\r
+      // Emulated non-volatile variable mode.\r
+      //\r
+      NextVariable->State = VAR_ADDED;\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 FALSE,\r
+                 TRUE,\r
+                 Fvb,\r
+                 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                 (UINT32) VarSize,\r
+                 (UINT8 *) NextVariable\r
+                 );\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
     }\r
 \r
     mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
@@ -2660,10 +2699,6 @@ UpdateVariable (
         mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);\r
       }\r
     }\r
-    //\r
-    // update the memory copy of Flash region.\r
-    //\r
-    CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
   } else {\r
     //\r
     // Create a volatile variable.\r
@@ -2744,7 +2779,7 @@ UpdateVariable (
       }\r
     }\r
 \r
-    State = Variable->CurrPtr->State;\r
+    State = CacheVariable->CurrPtr->State;\r
     State &= VAR_DELETED;\r
 \r
     Status = UpdateVariableStore (\r
@@ -2785,7 +2820,8 @@ Done:
   @param Attributes                 Attribute value of the variable found.\r
   @param DataSize                   Size of Data found. If size is less than the\r
                                     data, this value contains the required size.\r
-  @param Data                       Data pointer.\r
+  @param Data                       The buffer to return the contents of the variable. May be NULL\r
+                                    with a zero DataSize in order to determine the size buffer needed.\r
 \r
   @return EFI_INVALID_PARAMETER     Invalid parameter.\r
   @return EFI_SUCCESS               Find the specified variable.\r
@@ -2800,7 +2836,7 @@ VariableServiceGetVariable (
   IN      EFI_GUID          *VendorGuid,\r
   OUT     UINT32            *Attributes OPTIONAL,\r
   IN OUT  UINTN             *DataSize,\r
-  OUT     VOID              *Data\r
+  OUT     VOID              *Data OPTIONAL\r
   )\r
 {\r
   EFI_STATUS              Status;\r
@@ -2811,6 +2847,10 @@ VariableServiceGetVariable (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (VariableName[0] == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
@@ -2861,8 +2901,11 @@ Done:
   @param[in]  VendorGuid    Variable Vendor Guid.\r
   @param[out] VariablePtr   Pointer to variable header address.\r
 \r
-  @return EFI_SUCCESS       Find the specified variable.\r
-  @return EFI_NOT_FOUND     Not found.\r
+  @retval EFI_SUCCESS           The function completed successfully.\r
+  @retval EFI_NOT_FOUND         The next variable was not found.\r
+  @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.\r
+  @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and\r
+                                GUID of an existing variable.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -2882,6 +2925,19 @@ VariableServiceGetNextVariableInternal (
 \r
   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
+    //\r
+    // For VariableName is an empty string, FindVariable() will try to find and return\r
+    // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND)\r
+    // as no any variable is found, still go to return the error (EFI_NOT_FOUND).\r
+    //\r
+    if (VariableName[0] != 0) {\r
+      //\r
+      // For VariableName is not an empty string, and FindVariable() returns error as\r
+      // VariableName and VendorGuid are not a name and GUID of an existing variable,\r
+      // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.\r
+      //\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
     goto Done;\r
   }\r
 \r
@@ -3002,14 +3058,22 @@ Done:
   Caution: This function may receive untrusted input.\r
   This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
 \r
-  @param VariableNameSize           Size of the variable name.\r
+  @param VariableNameSize           The size of the VariableName buffer. The size must be large\r
+                                    enough to fit input string supplied in VariableName buffer.\r
   @param VariableName               Pointer to variable name.\r
   @param VendorGuid                 Variable Vendor Guid.\r
 \r
-  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
-  @return EFI_SUCCESS               Find the specified variable.\r
-  @return EFI_NOT_FOUND             Not found.\r
-  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+  @retval EFI_SUCCESS               The function completed successfully.\r
+  @retval EFI_NOT_FOUND             The next variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL      The VariableNameSize is too small for the result.\r
+                                    VariableNameSize has been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER     VariableNameSize is NULL.\r
+  @retval EFI_INVALID_PARAMETER     VariableName is NULL.\r
+  @retval EFI_INVALID_PARAMETER     VendorGuid is NULL.\r
+  @retval EFI_INVALID_PARAMETER     The input values of VariableName and VendorGuid are not a name and\r
+                                    GUID of an existing variable.\r
+  @retval EFI_INVALID_PARAMETER     Null-terminator is not found in the first VariableNameSize bytes of\r
+                                    the input VariableName buffer.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -3021,6 +3085,7 @@ VariableServiceGetNextVariableName (
   )\r
 {\r
   EFI_STATUS              Status;\r
+  UINTN                   MaxLen;\r
   UINTN                   VarNameSize;\r
   VARIABLE_HEADER         *VariablePtr;\r
 \r
@@ -3028,6 +3093,18 @@ VariableServiceGetNextVariableName (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  //\r
+  // Calculate the possible maximum length of name string, including the Null terminator.\r
+  //\r
+  MaxLen = *VariableNameSize / sizeof (CHAR16);\r
+  if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {\r
+    //\r
+    // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,\r
+    // follow spec to return EFI_INVALID_PARAMETER.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
   Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr);\r
@@ -3103,8 +3180,11 @@ VariableServiceSetVariable (
 \r
   //\r
   // Check for reserverd bit in variable attribute.\r
+  // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow\r
+  // the delete operation of common authenticated variable at user physical presence.\r
+  // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib\r
   //\r
-  if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) {\r
+  if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -3112,7 +3192,11 @@ VariableServiceSetVariable (
   //  Make sure if runtime bit is set, boot service bit is set also.\r
   //\r
   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
-    return EFI_INVALID_PARAMETER;\r
+    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+      return EFI_UNSUPPORTED;\r
+    } else {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
   } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
     if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {\r
       //\r
@@ -3135,15 +3219,16 @@ VariableServiceSetVariable (
   //\r
   if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
      && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {\r
-    return EFI_INVALID_PARAMETER;\r
+    return EFI_UNSUPPORTED;\r
   }\r
 \r
   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
-    if (DataSize < AUTHINFO_SIZE) {\r
-      //\r
-      // Try to write Authenticated Variable without AuthInfo.\r
-      //\r
-      return EFI_SECURITY_VIOLATION;\r
+    //\r
+    //  If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.\r
+    //  Maybe it's the delete operation of common authenticated variable at user physical presence.\r
+    //\r
+    if (DataSize != AUTHINFO_SIZE) {\r
+      return EFI_UNSUPPORTED;\r
     }\r
     PayloadSize = DataSize - AUTHINFO_SIZE;\r
   } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {\r
@@ -3155,6 +3240,12 @@ VariableServiceSetVariable (
       ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
       return EFI_SECURITY_VIOLATION;\r
     }\r
+    //\r
+    // The VariableSpeculationBarrier() call here is to ensure the above sanity\r
+    // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed\r
+    // before the execution of subsequent codes.\r
+    //\r
+    VariableSpeculationBarrier ();\r
     PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
   } else {\r
     PayloadSize = DataSize;\r
@@ -3179,19 +3270,68 @@ VariableServiceSetVariable (
   } else {\r
     //\r
     //  The size of the VariableName, including the Unicode Null in bytes plus\r
-    //  the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.\r
+    //  the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.\r
     //\r
     if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
       if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) {\r
+        DEBUG ((DEBUG_ERROR,\r
+          "%a: Failed to set variable '%s' with Guid %g\n",\r
+          __FUNCTION__, VariableName, VendorGuid));\r
+        DEBUG ((DEBUG_ERROR,\r
+          "NameSize(0x%x) + PayloadSize(0x%x) > "\r
+          "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
+          StrSize (VariableName), PayloadSize,\r
+          mVariableModuleGlobal->MaxAuthVariableSize,\r
+          GetVariableHeaderSize ()\r
+          ));\r
         return EFI_INVALID_PARAMETER;\r
       }\r
-    } else {\r
+    } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
       if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) {\r
+        DEBUG ((DEBUG_ERROR,\r
+          "%a: Failed to set variable '%s' with Guid %g\n",\r
+          __FUNCTION__, VariableName, VendorGuid));\r
+        DEBUG ((DEBUG_ERROR,\r
+          "NameSize(0x%x) + PayloadSize(0x%x) > "\r
+          "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
+          StrSize (VariableName), PayloadSize,\r
+          mVariableModuleGlobal->MaxVariableSize,\r
+          GetVariableHeaderSize ()\r
+          ));\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    } else {\r
+      if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ()) {\r
+        DEBUG ((DEBUG_ERROR,\r
+          "%a: Failed to set variable '%s' with Guid %g\n",\r
+          __FUNCTION__, VariableName, VendorGuid));\r
+        DEBUG ((DEBUG_ERROR,\r
+          "NameSize(0x%x) + PayloadSize(0x%x) > "\r
+          "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
+          StrSize (VariableName), PayloadSize,\r
+          mVariableModuleGlobal->MaxVolatileVariableSize,\r
+          GetVariableHeaderSize ()\r
+          ));\r
         return EFI_INVALID_PARAMETER;\r
       }\r
     }\r
   }\r
 \r
+  //\r
+  // Special Handling for MOR Lock variable.\r
+  //\r
+  Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    //\r
+    // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().\r
+    // Variable driver can just return SUCCESS.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -3345,12 +3485,14 @@ VariableServiceQueryVariableInfoInternal (
     }\r
 \r
     //\r
-    // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.\r
+    // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.\r
     //\r
     if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
       *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();\r
-    } else {\r
+    } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
       *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ();\r
+    } else {\r
+      *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ();\r
     }\r
   }\r
 \r
@@ -3474,6 +3616,13 @@ VariableServiceQueryVariableInfo (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    //\r
+    //  Deprecated attribute, make this check as highest priority.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
   if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {\r
     //\r
     // Make sure the Attributes combination is supported by the platform.\r
@@ -3597,9 +3746,33 @@ GetNonVolatileMaxVariableSize (
 }\r
 \r
 /**\r
-  Init non-volatile variable store.\r
+  Get maximum variable size, covering both non-volatile and volatile variables.\r
+\r
+  @return Maximum variable size.\r
+\r
+**/\r
+UINTN\r
+GetMaxVariableSize (\r
+  VOID\r
+  )\r
+{\r
+  UINTN MaxVariableSize;\r
+\r
+  MaxVariableSize = GetNonVolatileMaxVariableSize();\r
+  //\r
+  // The condition below fails implicitly if PcdMaxVolatileVariableSize equals\r
+  // the default zero value.\r
+  //\r
+  if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {\r
+    MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);\r
+  }\r
+  return MaxVariableSize;\r
+}\r
+\r
+/**\r
+  Init real non-volatile variable store.\r
 \r
-  @param[out] NvFvHeader        Output pointer to non-volatile FV header address.\r
+  @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.\r
 \r
   @retval EFI_SUCCESS           Function successfully executed.\r
   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
@@ -3607,16 +3780,13 @@ GetNonVolatileMaxVariableSize (
 \r
 **/\r
 EFI_STATUS\r
-InitNonVolatileVariableStore (\r
-  OUT EFI_FIRMWARE_VOLUME_HEADER    **NvFvHeader\r
+InitRealNonVolatileVariableStore (\r
+  OUT EFI_PHYSICAL_ADDRESS              *VariableStoreBase\r
   )\r
 {\r
   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;\r
-  VARIABLE_HEADER                       *Variable;\r
-  VARIABLE_HEADER                       *NextVariable;\r
-  EFI_PHYSICAL_ADDRESS                  VariableStoreBase;\r
-  UINT64                                VariableStoreLength;\r
-  UINTN                                 VariableSize;\r
+  VARIABLE_STORE_HEADER                 *VariableStore;\r
+  UINT32                                VariableStoreLength;\r
   EFI_HOB_GUID_TYPE                     *GuidHob;\r
   EFI_PHYSICAL_ADDRESS                  NvStorageBase;\r
   UINT8                                 *NvStorageData;\r
@@ -3642,10 +3812,9 @@ InitNonVolatileVariableStore (
     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
+  NvStorageBase = NV_STORAGE_VARIABLE_BASE;\r
+  ASSERT (NvStorageBase != 0);\r
+\r
   //\r
   // Copy NV storage data to the memory buffer.\r
   //\r
@@ -3695,24 +3864,23 @@ InitNonVolatileVariableStore (
     return EFI_VOLUME_CORRUPTED;\r
   }\r
 \r
-  VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
-  VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
+  VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
+  VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;\r
+  ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+  ASSERT (VariableStore->Size == VariableStoreLength);\r
 \r
-  mNvFvHeaderCache = FvHeader;\r
-  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-  mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
-  if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
+  //\r
+  // Check if the Variable Store header is not corrupted\r
+  //\r
+  if (GetVariableStoreStatus (VariableStore) != EfiValid) {\r
     FreePool (NvStorageData);\r
-    mNvFvHeaderCache = NULL;\r
-    mNvVariableCache = NULL;\r
     DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
     return EFI_VOLUME_CORRUPTED;\r
   }\r
-  ASSERT(mNvVariableCache->Size == VariableStoreLength);\r
 \r
-  ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+  mNvFvHeaderCache = FvHeader;\r
 \r
-  mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r
+  *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
 \r
   HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
   MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r
@@ -3747,14 +3915,142 @@ InitNonVolatileVariableStore (
   //\r
   ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
 \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Init emulated non-volatile variable store.\r
+\r
+  @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+InitEmuNonVolatileVariableStore (\r
+  EFI_PHYSICAL_ADDRESS  *VariableStoreBase\r
+  )\r
+{\r
+  VARIABLE_STORE_HEADER *VariableStore;\r
+  UINT32                VariableStoreLength;\r
+  BOOLEAN               FullyInitializeStore;\r
+  UINT32                HwErrStorageSize;\r
+\r
+  FullyInitializeStore = TRUE;\r
+\r
+  VariableStoreLength = PcdGet32 (PcdVariableStoreSize);\r
+  ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+\r
+  //\r
+  // Allocate memory for variable store.\r
+  //\r
+  if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {\r
+    VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);\r
+    if (VariableStore == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    //\r
+    // A memory location has been reserved for the NV variable store.  Certain\r
+    // platforms may be able to preserve a memory range across system resets,\r
+    // thereby providing better NV variable emulation.\r
+    //\r
+    VariableStore =\r
+      (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)\r
+        PcdGet64 (PcdEmuVariableNvStoreReserved);\r
+    if ((VariableStore->Size == VariableStoreLength) &&\r
+        (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||\r
+         CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&\r
+        (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&\r
+        (VariableStore->State == VARIABLE_STORE_HEALTHY)) {\r
+      DEBUG((\r
+        DEBUG_INFO,\r
+        "Variable Store reserved at %p appears to be valid\n",\r
+        VariableStore\r
+        ));\r
+      FullyInitializeStore = FALSE;\r
+    }\r
+  }\r
+\r
+  if (FullyInitializeStore) {\r
+    SetMem (VariableStore, VariableStoreLength, 0xff);\r
+    //\r
+    // Use gEfiAuthenticatedVariableGuid for potential auth variable support.\r
+    //\r
+    CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
+    VariableStore->Size       = VariableStoreLength;\r
+    VariableStore->Format     = VARIABLE_STORE_FORMATTED;\r
+    VariableStore->State      = VARIABLE_STORE_HEALTHY;\r
+    VariableStore->Reserved   = 0;\r
+    VariableStore->Reserved1  = 0;\r
+  }\r
+\r
+  *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
+\r
+  HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\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 the value of\r
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
+  //\r
+  ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
+\r
+  mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
+  mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
+  mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
+\r
+  return EFI_SUCCESS;\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
+  VARIABLE_HEADER                       *Variable;\r
+  VARIABLE_HEADER                       *NextVariable;\r
+  EFI_PHYSICAL_ADDRESS                  VariableStoreBase;\r
+  UINTN                                 VariableSize;\r
+  EFI_STATUS                            Status;\r
+\r
+  if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
+    Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r
+    DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r
+  } else {\r
+    Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r
+  }\r
+\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+  mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
+  mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r
+\r
   mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r
   mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r
 \r
   //\r
   // Parse non-volatile variable data and get last variable offset.\r
   //\r
-  Variable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
-  while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase))) {\r
+  Variable  = GetStartPointer (mNvVariableCache);\r
+  while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
     NextVariable = GetNextVariablePtr (Variable);\r
     VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
     if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
@@ -3765,9 +4061,8 @@ InitNonVolatileVariableStore (
 \r
     Variable = NextVariable;\r
   }\r
-  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) VariableStoreBase;\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache;\r
 \r
-  *NvFvHeader = FvHeader;\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -3868,7 +4163,7 @@ FlushHobVariableToFlash (
 }\r
 \r
 /**\r
-  Initializes variable write service after FTW was ready.\r
+  Initializes variable write service.\r
 \r
   @retval EFI_SUCCESS          Function successfully executed.\r
   @retval Others               Fail to initialize the variable service.\r
@@ -3882,23 +4177,10 @@ VariableWriteServiceInitialize (
   EFI_STATUS                      Status;\r
   UINTN                           Index;\r
   UINT8                           Data;\r
-  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
-  EFI_PHYSICAL_ADDRESS            NvStorageBase;\r
   VARIABLE_ENTRY_PROPERTY         *VariableEntry;\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
-  NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
-  if (NvStorageBase == 0) {\r
-    NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
-  }\r
-  VariableStoreBase = NvStorageBase + (mNvFvHeaderCache->HeaderLength);\r
-\r
-  //\r
-  // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
-  //\r
-  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-\r
   //\r
   // Check if the free area is really free.\r
   //\r
@@ -3958,7 +4240,7 @@ VariableWriteServiceInitialize (
   }\r
 \r
   if (!EFI_ERROR (Status)) {\r
-    for (Index = 0; Index < sizeof (mVariableEntryProperty) / sizeof (mVariableEntryProperty[0]); Index++) {\r
+    for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {\r
       VariableEntry = &mVariableEntryProperty[Index];\r
       Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);\r
       ASSERT_EFI_ERROR (Status);\r
@@ -3966,9 +4248,195 @@ VariableWriteServiceInitialize (
   }\r
 \r
   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  //\r
+  // Initialize MOR Lock variable.\r
+  //\r
+  MorLockInit ();\r
+\r
   return Status;\r
 }\r
 \r
+/**\r
+  Convert normal variable storage to the allocated auth variable storage.\r
+\r
+  @param[in]  NormalVarStorage  Pointer to the normal variable storage header\r
+\r
+  @retval the allocated auth variable storage\r
+**/\r
+VOID *\r
+ConvertNormalVarStorageToAuthVarStorage (\r
+  VARIABLE_STORE_HEADER *NormalVarStorage\r
+  )\r
+{\r
+  VARIABLE_HEADER *StartPtr;\r
+  UINT8           *NextPtr;\r
+  VARIABLE_HEADER *EndPtr;\r
+  UINTN           AuthVarStroageSize;\r
+  AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;\r
+  VARIABLE_STORE_HEADER         *AuthVarStorage;\r
+\r
+  AuthVarStroageSize  = sizeof (VARIABLE_STORE_HEADER);\r
+  //\r
+  // Set AuthFormat as FALSE for normal variable storage\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;\r
+\r
+  //\r
+  // Calculate Auth Variable Storage Size\r
+  //\r
+  StartPtr = GetStartPointer (NormalVarStorage);\r
+  EndPtr   = GetEndPointer (NormalVarStorage);\r
+  while (StartPtr < EndPtr) {\r
+    if (StartPtr->State == VAR_ADDED) {\r
+      AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);\r
+      AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);\r
+      AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);\r
+      AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);\r
+    }\r
+    StartPtr  = GetNextVariablePtr (StartPtr);\r
+  }\r
+\r
+  //\r
+  // Allocate Runtime memory for Auth Variable Storage\r
+  //\r
+  AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);\r
+  ASSERT (AuthVarStorage != NULL);\r
+  if (AuthVarStorage == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Copy Variable from Normal storage to Auth storage\r
+  //\r
+  StartPtr = GetStartPointer (NormalVarStorage);\r
+  EndPtr   = GetEndPointer (NormalVarStorage);\r
+  AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) GetStartPointer (AuthVarStorage);\r
+  while (StartPtr < EndPtr) {\r
+    if (StartPtr->State == VAR_ADDED) {\r
+      AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (AuthStartPtr);\r
+      //\r
+      // Copy Variable Header\r
+      //\r
+      AuthStartPtr->StartId     = StartPtr->StartId;\r
+      AuthStartPtr->State       = StartPtr->State;\r
+      AuthStartPtr->Attributes  = StartPtr->Attributes;\r
+      AuthStartPtr->NameSize    = StartPtr->NameSize;\r
+      AuthStartPtr->DataSize    = StartPtr->DataSize;\r
+      CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);\r
+      //\r
+      // Copy Variable Name\r
+      //\r
+      NextPtr = (UINT8 *) (AuthStartPtr + 1);\r
+      CopyMem (NextPtr, GetVariableNamePtr (StartPtr), AuthStartPtr->NameSize);\r
+      //\r
+      // Copy Variable Data\r
+      //\r
+      NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);\r
+      CopyMem (NextPtr, GetVariableDataPtr (StartPtr), AuthStartPtr->DataSize);\r
+      //\r
+      // Go to next variable\r
+      //\r
+      AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));\r
+    }\r
+    StartPtr = GetNextVariablePtr (StartPtr);\r
+  }\r
+  //\r
+  // Update Auth Storage Header\r
+  //\r
+  AuthVarStorage->Format = NormalVarStorage->Format;\r
+  AuthVarStorage->State  = NormalVarStorage->State;\r
+  AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);\r
+  CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);\r
+  ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);\r
+\r
+  //\r
+  // Restore AuthFormat\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;\r
+  return AuthVarStorage;\r
+}\r
+\r
+/**\r
+  Get HOB variable store.\r
+\r
+  @param[in] VariableGuid       NV variable store signature.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GetHobVariableStore (\r
+  IN EFI_GUID                   *VariableGuid\r
+  )\r
+{\r
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;\r
+  UINT64                        VariableStoreLength;\r
+  EFI_HOB_GUID_TYPE             *GuidHob;\r
+  BOOLEAN                       NeedConvertNormalToAuth;\r
+\r
+  //\r
+  // Make sure there is no more than one Variable HOB.\r
+  //\r
+  DEBUG_CODE (\r
+    GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
+    if (GuidHob != NULL) {\r
+      if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
+        DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));\r
+        ASSERT (FALSE);\r
+      } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {\r
+        DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));\r
+        ASSERT (FALSE);\r
+      }\r
+    } else {\r
+      GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
+      if (GuidHob != NULL) {\r
+        if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
+          DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));\r
+          ASSERT (FALSE);\r
+        }\r
+      }\r
+    }\r
+  );\r
+\r
+  //\r
+  // Combinations supported:\r
+  // 1. Normal NV variable store +\r
+  //    Normal HOB variable store\r
+  // 2. Auth NV variable store +\r
+  //    Auth HOB variable store\r
+  // 3. Auth NV variable store +\r
+  //    Normal HOB variable store (code will convert it to Auth Format)\r
+  //\r
+  NeedConvertNormalToAuth = FALSE;\r
+  GuidHob = GetFirstGuidHob (VariableGuid);\r
+  if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) {\r
+    //\r
+    // Try getting it from normal variable HOB\r
+    //\r
+    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
+    NeedConvertNormalToAuth = TRUE;\r
+  }\r
+  if (GuidHob != NULL) {\r
+    VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
+    VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);\r
+    if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
+      if (!NeedConvertNormalToAuth) {\r
+        mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
+      } else {\r
+        mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ConvertNormalVarStorageToAuthVarStorage ((VOID *) VariableStoreHeader);\r
+      }\r
+      if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   Initializes variable store area for non-volatile and volatile variable.\r
@@ -3984,12 +4452,8 @@ VariableCommonInitialize (
 {\r
   EFI_STATUS                      Status;\r
   VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
-  VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
-  UINT64                          VariableStoreLength;\r
   UINTN                           ScratchSize;\r
-  EFI_HOB_GUID_TYPE               *GuidHob;\r
   EFI_GUID                        *VariableGuid;\r
-  EFI_FIRMWARE_VOLUME_HEADER      *NvFvHeader;\r
 \r
   //\r
   // Allocate runtime memory for variable driver global structure.\r
@@ -4004,8 +4468,7 @@ VariableCommonInitialize (
   //\r
   // Init non-volatile variable store.\r
   //\r
-  NvFvHeader = NULL;\r
-  Status = InitNonVolatileVariableStore (&NvFvHeader);\r
+  Status = InitNonVolatileVariableStore ();\r
   if (EFI_ERROR (Status)) {\r
     FreePool (mVariableModuleGlobal);\r
     return Status;\r
@@ -4031,33 +4494,32 @@ VariableCommonInitialize (
   //\r
   // Get HOB variable store.\r
   //\r
-  GuidHob = GetFirstGuidHob (VariableGuid);\r
-  if (GuidHob != NULL) {\r
-    VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
-    VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
-    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 (NvFvHeader);\r
-        FreePool (mVariableModuleGlobal);\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-    } else {\r
-      DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
+  Status = GetHobVariableStore (VariableGuid);\r
+  if (EFI_ERROR (Status)) {\r
+    if (mNvFvHeaderCache != NULL) {\r
+      FreePool (mNvFvHeaderCache);\r
     }\r
+    FreePool (mVariableModuleGlobal);\r
+    return Status;\r
   }\r
 \r
+  mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?\r
+                                                    PcdGet32 (PcdMaxVolatileVariableSize) :\r
+                                                    mVariableModuleGlobal->MaxVariableSize\r
+                                                    );\r
   //\r
   // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
   //\r
-  ScratchSize = GetNonVolatileMaxVariableSize ();\r
+  ScratchSize = GetMaxVariableSize ();\r
   mVariableModuleGlobal->ScratchBufferSize = ScratchSize;\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 (NvFvHeader);\r
+    if (mNvFvHeaderCache != NULL) {\r
+      FreePool (mNvFvHeaderCache);\r
+    }\r
     FreePool (mVariableModuleGlobal);\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r