]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
MdeModulePkg: Add MorLock to variable driver.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index 834d2ff7c6db4ee060aaec22ef3956ac7d8241de..5e39d44d4c7a5fc611f8a90193ccfac741f0a157 100644 (file)
@@ -16,7 +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
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015 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
@@ -37,15 +38,14 @@ VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
 VARIABLE_STORE_HEADER  *mNvVariableCache      = NULL;\r
 \r
 ///\r
-/// The memory entry used for variable statistics data.\r
+/// Memory cache of Fv Header.\r
 ///\r
-VARIABLE_INFO_ENTRY    *gVariableInfo         = NULL;\r
+EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache  = NULL;\r
 \r
 ///\r
-/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID\r
-/// or EVT_GROUP_READY_TO_BOOT event.\r
+/// The memory entry used for variable statistics data.\r
 ///\r
-LIST_ENTRY             mLockedVariableList    = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);\r
+VARIABLE_INFO_ENTRY    *gVariableInfo         = NULL;\r
 \r
 ///\r
 /// The flag to indicate whether the platform has left the DXE phase of execution.\r
@@ -53,9 +53,10 @@ LIST_ENTRY             mLockedVariableList    = INITIALIZE_LIST_HEAD_VARIABLE (m
 BOOLEAN                mEndOfDxe              = FALSE;\r
 \r
 ///\r
-/// The flag to indicate whether the variable storage locking is enabled.\r
+/// It indicates the var check request source.\r
+/// In the implementation, DXE is regarded as untrusted, and SMM is trusted.\r
 ///\r
-BOOLEAN                mEnableLocking         = TRUE;\r
+VAR_CHECK_REQUEST_SOURCE mRequestSource       = VarCheckFromUntrusted;\r
 \r
 //\r
 // It will record the current boot error flag before EndOfDxe.\r
@@ -76,7 +77,7 @@ VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {
   },\r
 };\r
 \r
-AUTH_VAR_LIB_CONTEXT_IN mContextIn = {\r
+AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {\r
   AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,\r
   //\r
   // StructSize, TO BE FILLED\r
@@ -94,7 +95,7 @@ AUTH_VAR_LIB_CONTEXT_IN mContextIn = {
   VariableExLibAtRuntime,\r
 };\r
 \r
-AUTH_VAR_LIB_CONTEXT_OUT mContextOut;\r
+AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;\r
 \r
 /**\r
 \r
@@ -110,6 +111,43 @@ SecureBootHook (
   IN EFI_GUID                               *VendorGuid\r
   );\r
 \r
+/**\r
+  Initialization for MOR Lock Control.\r
+\r
+  @retval EFI_SUCEESS     MorLock initialization success.\r
+  @return Others          Some error occurs.\r
+**/\r
+EFI_STATUS\r
+MorLockInit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This service is an MOR/MorLock checker handler for the SetVariable().\r
+\r
+  @param  VariableName the name of the vendor's variable, as a\r
+                       Null-Terminated Unicode String\r
+  @param  VendorGuid   Unify identifier for vendor.\r
+  @param  Attributes   Point to memory location to return the attributes of variable. If the point\r
+                       is NULL, the parameter would be ignored.\r
+  @param  DataSize     The size in bytes of Data-Buffer.\r
+  @param  Data         Point to the content of the variable.\r
+\r
+  @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable driver can store the variable data.\r
+  @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or attributes is not allowed for MOR variable.\r
+  @retval  EFI_ACCESS_DENIED      The MOR/MorLock is locked.\r
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this function.\r
+                                  Variable driver can just return EFI_SUCCESS.\r
+**/\r
+EFI_STATUS\r
+SetVariableCheckHandlerMor (\r
+  IN CHAR16     *VariableName,\r
+  IN EFI_GUID   *VendorGuid,\r
+  IN UINT32     Attributes,\r
+  IN UINTN      DataSize,\r
+  IN VOID       *Data\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
@@ -338,7 +376,7 @@ UpdateVariableStore (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
+  for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
     for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
       //\r
       // Check to see if the Variable Writes are spanning through multiple\r
@@ -798,7 +836,7 @@ RecordVarErrorFlag (
       //\r
       // Update the data in NV cache.\r
       //\r
-      *VarErrFlag = Flag;\r
+      *VarErrFlag = TempFlag;\r
     }\r
   }\r
 }\r
@@ -878,7 +916,7 @@ IsUserVariable (
   // then no need to check if the variable is user variable or not specially.\r
   //\r
   if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
-    if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
+    if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
       return TRUE;\r
     }\r
   }\r
@@ -910,7 +948,7 @@ CalculateCommonUserVariableTotalSize (
       NextVariable = GetNextVariablePtr (Variable);\r
       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
       if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
-        if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
+        if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
           //\r
           // No property, it is user variable.\r
           //\r
@@ -932,12 +970,9 @@ InitializeVariableQuota (
   VOID\r
   )\r
 {\r
-  STATIC BOOLEAN    Initialized;\r
-\r
-  if (!mEndOfDxe || Initialized) {\r
+  if (!mEndOfDxe) {\r
     return;\r
   }\r
-  Initialized = TRUE;\r
 \r
   InitializeVarErrorFlag ();\r
   CalculateCommonUserVariableTotalSize ();\r
@@ -1193,6 +1228,9 @@ Reclaim (
       mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
       mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
     } else {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
+      mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+      mVariableModuleGlobal->CommonUserVariableTotalSize = 0;\r
       Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
       while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {\r
         NextVariable = GetNextVariablePtr (Variable);\r
@@ -1718,7 +1756,7 @@ CheckRemainingSpaceForConsistencyInternal (
   ASSERT_EFI_ERROR (Status);\r
 \r
   TotalNeededSize = 0;\r
-  Args = Marker;\r
+  VA_COPY (Args, Marker);\r
   VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
   while (VariableEntry != NULL) {\r
     //\r
@@ -1747,7 +1785,7 @@ CheckRemainingSpaceForConsistencyInternal (
     return FALSE;\r
   }\r
 \r
-  Args = Marker;\r
+  VA_COPY (Args, Marker);\r
   VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
   while (VariableEntry != NULL) {\r
     //\r
@@ -2178,6 +2216,35 @@ UpdateVariable (
     }\r
   }\r
 \r
+  //\r
+  // Check if CacheVariable points to the variable in variable HOB.\r
+  // If yes, let CacheVariable points to the variable in NV variable cache.\r
+  //\r
+  if ((CacheVariable->CurrPtr != NULL) &&\r
+      (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&\r
+      (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase))\r
+     ) {\r
+    CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);\r
+    CacheVariable->EndPtr   = GetEndPointer   (mNvVariableCache);\r
+    CacheVariable->Volatile = FALSE;\r
+    Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable);\r
+    if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) {\r
+      //\r
+      // There is no matched variable in NV variable cache.\r
+      //\r
+      if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {\r
+        //\r
+        // It is to delete variable,\r
+        // go to delete this variable in variable HOB and\r
+        // try to flush other variables from HOB to flash.\r
+        //\r
+        UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE);\r
+        FlushHobVariableToFlash (VariableName, VendorGuid);\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
   if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
     Variable = CacheVariable;\r
   } else {\r
@@ -2189,7 +2256,8 @@ UpdateVariable (
     VariableStoreHeader  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
     Variable = &NvVariable;\r
     Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
-    Variable->EndPtr   = GetEndPointer (VariableStoreHeader);\r
+    Variable->EndPtr   = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));\r
+\r
     Variable->CurrPtr  = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
     if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
       Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
@@ -2227,7 +2295,7 @@ UpdateVariable (
       //\r
       // Only variable that have NV attributes can be updated/deleted in Runtime.\r
       //\r
-      if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+      if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;\r
       }\r
@@ -2235,7 +2303,7 @@ UpdateVariable (
       //\r
       // Only variable that have RT attributes can be updated/deleted in Runtime.\r
       //\r
-      if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
+      if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;\r
       }\r
@@ -2253,7 +2321,8 @@ UpdateVariable (
         // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
         // set IN_DELETED_TRANSITION one to DELETED state first.\r
         //\r
-        State = Variable->InDeletedTransitionPtr->State;\r
+        ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+        State = CacheVariable->InDeletedTransitionPtr->State;\r
         State &= VAR_DELETED;\r
         Status = UpdateVariableStore (\r
                    &mVariableModuleGlobal->VariableGlobal,\r
@@ -2266,7 +2335,6 @@ UpdateVariable (
                    );\r
         if (!EFI_ERROR (Status)) {\r
           if (!Variable->Volatile) {\r
-            ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
             CacheVariable->InDeletedTransitionPtr->State = State;\r
           }\r
         } else {\r
@@ -2274,7 +2342,7 @@ UpdateVariable (
         }\r
       }\r
 \r
-      State = Variable->CurrPtr->State;\r
+      State = CacheVariable->CurrPtr->State;\r
       State &= VAR_DELETED;\r
 \r
       Status = UpdateVariableStore (\r
@@ -2299,8 +2367,8 @@ UpdateVariable (
     // If the variable is marked valid, and the same data has been passed in,\r
     // then return to the caller immediately.\r
     //\r
-    if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
-        (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&\r
+    if (DataSizeOfVariable (CacheVariable->CurrPtr) == DataSize &&\r
+        (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr), DataSize) == 0) &&\r
         ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&\r
         (TimeStamp == NULL)) {\r
       //\r
@@ -2309,8 +2377,8 @@ UpdateVariable (
       UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
       Status = EFI_SUCCESS;\r
       goto Done;\r
-    } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
-               (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+    } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||\r
+               (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
 \r
       //\r
       // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.\r
@@ -2320,9 +2388,9 @@ UpdateVariable (
         // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.\r
         // From DataOffset of NextVariable is to save the existing variable data.\r
         //\r
-        DataOffset = GetVariableDataOffset (Variable->CurrPtr);\r
+        DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr);\r
         BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);\r
-        CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), DataSizeOfVariable (Variable->CurrPtr));\r
+        CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr));\r
 \r
         //\r
         // Set Max Common/Auth Variable Data Size as default MaxDataSize.\r
@@ -2341,15 +2409,15 @@ UpdateVariable (
           MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;\r
         }\r
 \r
-        if (DataSizeOfVariable (Variable->CurrPtr) + DataSize > MaxDataSize) {\r
+        if (DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize > MaxDataSize) {\r
           //\r
           // Existing data size + new data size exceed maximum variable size limitation.\r
           //\r
           Status = EFI_INVALID_PARAMETER;\r
           goto Done;\r
         }\r
-        CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (Variable->CurrPtr)), Data, DataSize);\r
-        MergedBufSize = DataSizeOfVariable (Variable->CurrPtr) + DataSize;\r
+        CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr)), Data, DataSize);\r
+        MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize;\r
 \r
         //\r
         // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.\r
@@ -2362,7 +2430,7 @@ UpdateVariable (
       //\r
       // Mark the old variable as in delete transition.\r
       //\r
-      State = Variable->CurrPtr->State;\r
+      State = CacheVariable->CurrPtr->State;\r
       State &= VAR_IN_DELETED_TRANSITION;\r
 \r
       Status = UpdateVariableStore (\r
@@ -2436,7 +2504,7 @@ UpdateVariable (
         // with the variable, we need associate the new timestamp with the updated value.\r
         //\r
         if (Variable->CurrPtr != NULL) {\r
-          if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) Variable->CurrPtr)->TimeStamp), TimeStamp)) {\r
+          if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {\r
             CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
           }\r
         }\r
@@ -2692,7 +2760,8 @@ UpdateVariable (
       // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
       // set IN_DELETED_TRANSITION one to DELETED state first.\r
       //\r
-      State = Variable->InDeletedTransitionPtr->State;\r
+      ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+      State = CacheVariable->InDeletedTransitionPtr->State;\r
       State &= VAR_DELETED;\r
       Status = UpdateVariableStore (\r
                  &mVariableModuleGlobal->VariableGlobal,\r
@@ -2705,7 +2774,6 @@ UpdateVariable (
                  );\r
       if (!EFI_ERROR (Status)) {\r
         if (!Variable->Volatile) {\r
-          ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
           CacheVariable->InDeletedTransitionPtr->State = State;\r
         }\r
       } else {\r
@@ -2741,131 +2809,6 @@ Done:
   return Status;\r
 }\r
 \r
-/**\r
-  Check if a Unicode character is a hexadecimal character.\r
-\r
-  This function checks if a Unicode character is a\r
-  hexadecimal character.  The valid hexadecimal character is\r
-  L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
-\r
-\r
-  @param Char           The character to check against.\r
-\r
-  @retval TRUE          If the Char is a hexadecmial character.\r
-  @retval FALSE         If the Char is not a hexadecmial character.\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-IsHexaDecimalDigitCharacter (\r
-  IN CHAR16             Char\r
-  )\r
-{\r
-  return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
-}\r
-\r
-/**\r
-\r
-  This code checks if variable is hardware error record variable or not.\r
-\r
-  According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
-  and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
-\r
-  @param VariableName   Pointer to variable name.\r
-  @param VendorGuid     Variable Vendor Guid.\r
-\r
-  @retval TRUE          Variable is hardware error record variable.\r
-  @retval FALSE         Variable is not hardware error record variable.\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-IsHwErrRecVariable (\r
-  IN CHAR16             *VariableName,\r
-  IN EFI_GUID           *VendorGuid\r
-  )\r
-{\r
-  if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
-      (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
-      (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
-      !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
-      !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
-      !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
-      !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
-    return FALSE;\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-/**\r
-  Mark a variable that will become read-only after leaving the DXE phase of execution.\r
-\r
-\r
-  @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.\r
-  @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.\r
-  @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.\r
-\r
-  @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked\r
-                                as pending to be read-only.\r
-  @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
-                                Or VariableName is an empty string.\r
-  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
-                                already been signaled.\r
-  @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock request.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-VariableLockRequestToLock (\r
-  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
-  IN       CHAR16                       *VariableName,\r
-  IN       EFI_GUID                     *VendorGuid\r
-  )\r
-{\r
-  VARIABLE_ENTRY                  *Entry;\r
-  CHAR16                          *Name;\r
-  LIST_ENTRY                      *Link;\r
-  VARIABLE_ENTRY                  *LockedEntry;\r
-\r
-  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (mEndOfDxe) {\r
-    return EFI_ACCESS_DENIED;\r
-  }\r
-\r
-  Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (VariableName));\r
-  if (Entry == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));\r
-\r
-  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
-\r
-  for ( Link = GetFirstNode (&mLockedVariableList)\r
-      ; !IsNull (&mLockedVariableList, Link)\r
-      ; Link = GetNextNode (&mLockedVariableList, Link)\r
-      ) {\r
-    LockedEntry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
-    Name = (CHAR16 *) ((UINTN) LockedEntry + sizeof (*LockedEntry));\r
-    if (CompareGuid (&LockedEntry->Guid, VendorGuid) && (StrCmp (Name, VariableName) == 0)) {\r
-      goto Done;\r
-    }\r
-  }\r
-\r
-  Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
-  StrCpyS (Name, StrSize (VariableName)/sizeof(CHAR16), VariableName);\r
-  CopyGuid (&Entry->Guid, VendorGuid);\r
-  InsertTailList (&mLockedVariableList, &Entry->Link);\r
-\r
-Done:\r
-  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
 /**\r
 \r
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
@@ -3183,9 +3126,6 @@ VariableServiceSetVariable (
   VARIABLE_HEADER                     *NextVariable;\r
   EFI_PHYSICAL_ADDRESS                Point;\r
   UINTN                               PayloadSize;\r
-  LIST_ENTRY                          *Link;\r
-  VARIABLE_ENTRY                      *Entry;\r
-  CHAR16                              *Name;\r
 \r
   //\r
   // Check input parameters.\r
@@ -3273,9 +3213,6 @@ VariableServiceSetVariable (
     if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
-    if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
   } else {\r
     //\r
     //  The size of the VariableName, including the Unicode Null in bytes plus\r
@@ -3292,7 +3229,22 @@ VariableServiceSetVariable (
     }\r
   }\r
 \r
-  Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\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
   }\r
@@ -3314,24 +3266,6 @@ VariableServiceSetVariable (
     mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
   }\r
 \r
-  if (mEndOfDxe && mEnableLocking) {\r
-    //\r
-    // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.\r
-    //\r
-    for ( Link = GetFirstNode (&mLockedVariableList)\r
-        ; !IsNull (&mLockedVariableList, Link)\r
-        ; Link = GetNextNode (&mLockedVariableList, Link)\r
-        ) {\r
-      Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
-      Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
-      if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Name, VariableName) == 0)) {\r
-        Status = EFI_WRITE_PROTECTED;\r
-        DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));\r
-        goto Done;\r
-      }\r
-    }\r
-  }\r
-\r
   //\r
   // Check whether the input variable is already existed.\r
   //\r
@@ -3745,6 +3679,8 @@ InitNonVolatileVariableStore (
   UINT32                                HwErrStorageSize;\r
   UINT32                                MaxUserNvVariableSpaceSize;\r
   UINT32                                BoottimeReservedNvVariableSpaceSize;\r
+  EFI_STATUS                            Status;\r
+  VOID                                  *FtwProtocol;\r
 \r
   mVariableModuleGlobal->FvbInstance = NULL;\r
 \r
@@ -3767,30 +3703,36 @@ InitNonVolatileVariableStore (
   //\r
   CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
 \r
+  Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
   //\r
-  // Check the FTW last write data hob.\r
+  // If FTW protocol has been installed, no need to check FTW last write data hob.\r
   //\r
-  GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
-  if (GuidHob != NULL) {\r
-    FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
-    if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
-      DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
-      //\r
-      // Copy the backed up NV storage data to the memory buffer from spare block.\r
-      //\r
-      CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
-    } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
-               (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
-      //\r
-      // Flash NV storage from the Offset is backed up in spare block.\r
-      //\r
-      BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
-      BackUpSize = NvStorageSize - BackUpOffset;\r
-      DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
-      //\r
-      // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
-      //\r
-      CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Check the FTW last write data hob.\r
+    //\r
+    GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
+    if (GuidHob != NULL) {\r
+      FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
+      if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
+        DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+        //\r
+        // Copy the backed up NV storage data to the memory buffer from spare block.\r
+        //\r
+        CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
+      } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
+                 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+        //\r
+        // Flash NV storage from the Offset is backed up in spare block.\r
+        //\r
+        BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+        BackUpSize = NvStorageSize - BackUpOffset;\r
+        DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
+        //\r
+        // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
+        //\r
+        CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+      }\r
     }\r
   }\r
 \r
@@ -3808,10 +3750,13 @@ InitNonVolatileVariableStore (
   VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
   VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
 \r
+  mNvFvHeaderCache = FvHeader;\r
   mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
   mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
   if (GetVariableStoreStatus (mNvVariableCache) != 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
@@ -3895,6 +3840,7 @@ FlushHobVariableToFlash (
   VARIABLE_STORE_HEADER         *VariableStoreHeader;\r
   VARIABLE_HEADER               *Variable;\r
   VOID                          *VariableData;\r
+  VARIABLE_POINTER_TRACK        VariablePtrTrack;\r
   BOOLEAN                       ErrorFlag;\r
 \r
   ErrorFlag = FALSE;\r
@@ -3923,17 +3869,22 @@ FlushHobVariableToFlash (
           !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) ||\r
           StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
         VariableData = GetVariableDataPtr (Variable);\r
-        Status = VariableServiceSetVariable (\r
+        FindVariable (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &VariablePtrTrack, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+        Status = UpdateVariable (\r
                    GetVariableNamePtr (Variable),\r
                    GetVendorGuidPtr (Variable),\r
-                   Variable->Attributes,\r
+                   VariableData,\r
                    DataSizeOfVariable (Variable),\r
-                   VariableData\r
-                   );\r
+                   Variable->Attributes,\r
+                   0,\r
+                   0,\r
+                   &VariablePtrTrack,\r
+                   NULL\r
+                 );\r
         DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status));\r
       } else {\r
         //\r
-        // The updated or deleted variable is matched with the HOB variable.\r
+        // The updated or deleted variable is matched with this HOB variable.\r
         // Don't break here because we will try to set other HOB variables\r
         // since this variable could be set successfully.\r
         //\r
@@ -3981,29 +3932,29 @@ VariableWriteServiceInitialize (
   )\r
 {\r
   EFI_STATUS                      Status;\r
-  VARIABLE_STORE_HEADER           *VariableStoreHeader;\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 + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\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
-  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
 \r
   //\r
   // Check if the free area is really free.\r
   //\r
-  for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
+  for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {\r
     Data = ((UINT8 *) mNvVariableCache)[Index];\r
     if (Data != 0xff) {\r
       //\r
@@ -4018,6 +3969,7 @@ VariableWriteServiceInitialize (
                  0\r
                  );\r
       if (EFI_ERROR (Status)) {\r
+        ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
         return Status;\r
       }\r
       break;\r
@@ -4027,21 +3979,21 @@ VariableWriteServiceInitialize (
   FlushHobVariableToFlash (NULL, NULL);\r
 \r
   Status = EFI_SUCCESS;\r
-  ZeroMem (&mContextOut, sizeof (mContextOut));\r
+  ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));\r
   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {\r
     //\r
     // Authenticated variable initialize.\r
     //\r
-    mContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);\r
-    mContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();\r
-    Status = AuthVariableLibInitialize (&mContextIn, &mContextOut);\r
+    mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);\r
+    mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();\r
+    Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);\r
     if (!EFI_ERROR (Status)) {\r
       DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n"));\r
       mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;\r
-      if (mContextOut.AuthVarEntry != NULL) {\r
-        for (Index = 0; Index < mContextOut.AuthVarEntryCount; Index++) {\r
-          VariableEntry = &mContextOut.AuthVarEntry[Index];\r
-          Status = InternalVarCheckVariablePropertySet (\r
+      if (mAuthContextOut.AuthVarEntry != NULL) {\r
+        for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {\r
+          VariableEntry = &mAuthContextOut.AuthVarEntry[Index];\r
+          Status = VarCheckLibVariablePropertySet (\r
                      VariableEntry->Name,\r
                      VariableEntry->Guid,\r
                      &VariableEntry->VariableProperty\r
@@ -4060,11 +4012,18 @@ VariableWriteServiceInitialize (
   if (!EFI_ERROR (Status)) {\r
     for (Index = 0; Index < sizeof (mVariableEntryProperty) / sizeof (mVariableEntryProperty[0]); Index++) {\r
       VariableEntry = &mVariableEntryProperty[Index];\r
-      Status = InternalVarCheckVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);\r
+      Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);\r
       ASSERT_EFI_ERROR (Status);\r
     }\r
   }\r
 \r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  //\r
+  // Initialize MOR Lock variable.\r
+  //\r
+  MorLockInit ();\r
+\r
   return Status;\r
 }\r
 \r