[edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables

Judah Vang judah.vang at intel.com
Sun Nov 6 07:34:58 UTC 2022


REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594

V5: Add RuntimeDxe Variable Protection into a new directory and
keep existing Variable for RuntimeDxe unchanged.

v4: Applied code review - remove unreferenced library from .inf.
Updated some function description and parameters.

V3: Fix 'NextVariableStore' parameter for CopyMem.  It was causing
an exception. Need to correctly cast 'NextVariableStore' so all
platforms build.  Add code to initialize 'ContextIn' structure in
SmmVariableReay() to fix issue with NULL function pointer.

V1: Add support for Protected Variables.
Add new API to retrieve Variable Infomation and data.
Add new API to update variable in non-volatile storage or
cached copy.

Cc: Jian J Wang <jian.j.wang at intel.com>
Cc: Liming Gao <gaoliming at byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu at intel.com>
Cc: Nishant C Mistry <nishant.c.mistry at intel.com>
Signed-off-by: Jian J Wang <jian.j.wang at intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry at intel.com>
Signed-off-by: Judah Vang <judah.vang at intel.com>
---
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf |   36 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.inf                                   |  151 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf                                          |  153 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.inf                                |  119 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.inf                                 |  143 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphic.h                                   |  158 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h                                               |  948 +++++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.h                                    |   67 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h                                        |  424 ++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.h                                   |   51 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c                                            |  343 ++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c                                                |  504 +++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c   |  607 +++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierDxe.c                                  |   27 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierSmm.c                                  |   26 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c                                          |  153 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm.c                                          |  569 +++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c                                               |  101 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c                                               | 4037 ++++++++++++++++++++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c                                            |  670 ++++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c                                          |  417 ++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequestToLock.c                              |   96 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.c                                    |  537 +++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c                                        | 1110 ++++++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmmDxe.c                                   |  575 +++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.c                                   |  158 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c                                            | 1268 ++++++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.c                                  | 1895 +++++++++
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.c                                   |   89 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditionalMm.c                                  |  130 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.uni                                   |   22 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxeExtra.uni                              |   14 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni                                          |   27 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.uni                                     |   14 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.uni                                |   23 +
 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni                           |   14 +
 36 files changed, 15676 insertions(+)

diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf
new file mode 100644
index 000000000000..586d877fca90
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf
@@ -0,0 +1,36 @@
+## @file
+# This is a host-based unit test for the VariableLockRequestToLock shim.
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION         = 0x00010017
+  BASE_NAME           = VariableLockRequestToLockUnitTest
+  FILE_GUID           = A657FCD8-4A0D-46B4-8DC9-F089626383AD
+  VERSION_STRING      = 1.0
+  MODULE_TYPE         = HOST_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  VariableLockRequestToLockUnitTest.c
+  ../VariableLockRequestToLock.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+  UnitTestLib
+  DebugLib
+  VariablePolicyLib
+  VariablePolicyHelperLib
+  BaseMemoryLib
+  MemoryAllocationLib
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.inf
new file mode 100644
index 000000000000..6adc2c636e84
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.inf
@@ -0,0 +1,151 @@
+## @file
+#  Provides variable service.
+#
+#  This module installs variable arch protocol and variable write arch protocol to provide
+#  variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+#
+#  Caution: This module requires additional review when modified.
+#  This driver will have external input - variable data.
+#  This external input must be validated carefully to avoid security issues such as
+#  buffer overflow or integer overflow.
+#
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VariableRuntimeDxe
+  MODULE_UNI_FILE                = VariableRuntimeDxe.uni
+  FILE_GUID                      = 146F4448-56BF-405C-A8C4-B77FFD24BE00
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#  VIRTUAL_ADDRESS_MAP_CALLBACK  =  VariableClassAddressChangeEvent
+#
+
+[Sources]
+  Reclaim.c
+  Variable.c
+  VariableDxe.c
+  Variable.h
+  VariableNonVolatile.c
+  VariableNonVolatile.h
+  VariableParsing.c
+  VariableParsing.h
+  VariableRuntimeCache.c
+  VariableRuntimeCache.h
+  PrivilegePolymorphic.h
+  Measurement.c
+  TcgMorLockDxe.c
+  VarCheck.c
+  VariableExLib.c
+  SpeculationBarrierDxe.c
+  VariableLockRequestToLock.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  SynchronizationLib
+  UefiLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  UefiRuntimeLib
+  DxeServicesTableLib
+  UefiDriverEntryPoint
+  PcdLib
+  HobLib
+  TpmMeasurementLib
+  AuthVariableLib
+  VarCheckLib
+  VariableFlashInfoLib
+  VariablePolicyLib
+  VariablePolicyHelperLib
+  SafeIntLib
+  ProtectedVariableLib
+
+[Protocols]
+  gEfiFirmwareVolumeBlockProtocolGuid           ## CONSUMES
+  ## CONSUMES
+  ## NOTIFY
+  gEfiFaultTolerantWriteProtocolGuid
+  gEfiVariableWriteArchProtocolGuid             ## PRODUCES
+  gEfiVariableArchProtocolGuid                  ## PRODUCES
+  gEdkiiVariableLockProtocolGuid                ## PRODUCES
+  gEdkiiVariablePolicyProtocolGuid              ## CONSUMES
+  gEdkiiVarCheckProtocolGuid                    ## PRODUCES
+
+[Guids]
+  ## SOMETIMES_CONSUMES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiAuthenticatedVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"PlatformLang"
+  ## SOMETIMES_PRODUCES   ## Variable:L"PlatformLang"
+  ## SOMETIMES_CONSUMES   ## Variable:L"Lang"
+  ## SOMETIMES_PRODUCES   ## Variable:L"Lang"
+  ## SOMETIMES_CONSUMES   ## Variable:L"PK"
+  ## SOMETIMES_CONSUMES   ## Variable:L"KEK"
+  ## SOMETIMES_CONSUMES   ## Variable:L"SecureBoot"
+  gEfiGlobalVariableGuid
+
+  gEfiMemoryOverwriteControlDataGuid            ## SOMETIMES_CONSUMES   ## Variable:L"MemoryOverwriteRequestControl"
+  gEfiMemoryOverwriteRequestControlLockGuid     ## SOMETIMES_PRODUCES   ## Variable:L"MemoryOverwriteRequestControlLock"
+
+  gEfiEventVirtualAddressChangeGuid             ## CONSUMES             ## Event
+  gEfiSystemNvDataFvGuid                        ## CONSUMES             ## GUID
+  gEfiEndOfDxeEventGroupGuid                    ## CONSUMES             ## Event
+  gEdkiiFaultTolerantWriteGuid                  ## SOMETIMES_CONSUMES   ## HOB
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"VarErrorFlag"
+  ## SOMETIMES_PRODUCES   ## Variable:L"VarErrorFlag"
+  gEdkiiVarErrorFlagGuid
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"db"
+  ## SOMETIMES_CONSUMES   ## Variable:L"dbx"
+  ## SOMETIMES_CONSUMES   ## Variable:L"dbt"
+  gEfiImageSecurityDatabaseGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize                 ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize             ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize         ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize                ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize           ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved      ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics  ## CONSUMES # statistic the information of variable.
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang
+
+[Depex]
+  TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  VariableRuntimeDxeExtra.uni
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
new file mode 100644
index 000000000000..2651ec514df3
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
@@ -0,0 +1,153 @@
+## @file
+#  Provides SMM variable service.
+#
+#  This module installs SMM variable protocol into SMM protocol database,
+#  which can be used by SMM driver, and installs SMM variable protocol
+#  into BS protocol database, which can be used to notify the SMM Runtime
+#  Dxe driver that the SMM variable service is ready.
+#  This module should be used with SMM Runtime DXE module together. The
+#  SMM Runtime DXE module would install variable arch protocol and variable
+#  write arch protocol based on SMM variable module.
+#
+#  Caution: This module requires additional review when modified.
+#  This driver will have external input - variable data and communicate buffer in SMM mode.
+#  This external input must be validated carefully to avoid security issues such as
+#  buffer overflow or integer overflow.
+#    The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+#  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory
+#  may not be modified without authorization. If platform fails to protect these resources,
+#  the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VariableSmm
+  MODULE_UNI_FILE                = VariableSmm.uni
+  FILE_GUID                      = 1C32FDDF-7FF1-4EE5-BDA0-ED9AAC623D3C
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x0001000A
+  ENTRY_POINT                    = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+
+[Sources]
+  Reclaim.c
+  Variable.c
+  VariableTraditionalMm.c
+  VariableSmm.c
+  VariableNonVolatile.c
+  VariableNonVolatile.h
+  VariableParsing.c
+  VariableParsing.h
+  VariableRuntimeCache.c
+  VariableRuntimeCache.h
+  VarCheck.c
+  Variable.h
+  PrivilegePolymorphic.h
+  VariableExLib.c
+  TcgMorLockSmm.c
+  SpeculationBarrierSmm.c
+  VariableLockRequestToLock.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  MemoryAllocationLib
+  BaseLib
+  SynchronizationLib
+  UefiLib
+  MmServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  DxeServicesTableLib
+  HobLib
+  PcdLib
+  SmmMemLib
+  AuthVariableLib
+  VarCheckLib
+  UefiBootServicesTableLib
+  VariableFlashInfoLib
+  VariablePolicyLib
+  VariablePolicyHelperLib
+  SafeIntLib
+  ProtectedVariableLib
+
+[Protocols]
+  gEfiSmmFirmwareVolumeBlockProtocolGuid        ## CONSUMES
+  ## CONSUMES
+  ## NOTIFY
+  gEfiSmmFaultTolerantWriteProtocolGuid
+  ## PRODUCES
+  ## UNDEFINED # SmiHandlerRegister
+  gEfiSmmVariableProtocolGuid
+  gEfiMmEndOfDxeProtocolGuid                    ## NOTIFY
+  gEdkiiSmmVarCheckProtocolGuid                 ## PRODUCES
+  gEfiTcgProtocolGuid                           ## SOMETIMES_CONSUMES
+  gEfiTcg2ProtocolGuid                          ## SOMETIMES_CONSUMES
+
+[Guids]
+  ## SOMETIMES_CONSUMES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiAuthenticatedVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"PlatformLang"
+  ## SOMETIMES_PRODUCES   ## Variable:L"PlatformLang"
+  ## SOMETIMES_CONSUMES   ## Variable:L"Lang"
+  ## SOMETIMES_PRODUCES   ## Variable:L"Lang"
+  gEfiGlobalVariableGuid
+
+  gEfiMemoryOverwriteControlDataGuid            ## SOMETIMES_CONSUMES   ## Variable:L"MemoryOverwriteRequestControl"
+  gEfiMemoryOverwriteRequestControlLockGuid     ## SOMETIMES_PRODUCES   ## Variable:L"MemoryOverwriteRequestControlLock"
+
+  gSmmVariableWriteGuid                         ## PRODUCES             ## GUID # Install protocol
+  gEfiSystemNvDataFvGuid                        ## CONSUMES             ## GUID
+  gEdkiiFaultTolerantWriteGuid                  ## SOMETIMES_CONSUMES   ## HOB
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"VarErrorFlag"
+  ## SOMETIMES_PRODUCES   ## Variable:L"VarErrorFlag"
+  gEdkiiVarErrorFlagGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize                  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize              ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize          ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize     ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize                ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize                 ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize           ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe   ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable          ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved       ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics        ## CONSUMES  # statistic the information of variable.
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate       ## CONSUMES  # Auto update PlatformLang/Lang
+
+[Depex]
+  TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  VariableSmmExtra.uni
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.inf
new file mode 100644
index 000000000000..0d169913c9c9
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -0,0 +1,119 @@
+## @file
+#  Runtime DXE part corresponding to SMM authenticated variable module.
+#
+#  This module installs variable arch protocol and variable write arch protocol to provide
+#  variable service. This module need work together with SMM authenticated variable module.
+#
+#  Caution: This module requires additional review when modified.
+#  This driver will have external input - variable data.
+#  This external input must be validated carefully to avoid security issues such as
+#  buffer overflow or integer overflow.
+#    The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+#  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory
+#  may not be modified without authorization. If platform fails to protect these resources,
+#  the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VariableSmmRuntimeDxe
+  MODULE_UNI_FILE                = VariableSmmRuntimeDxe.uni
+  FILE_GUID                      = 3C9DF4B3-559F-4AE4-AEA3-E4B0C3D9D3EE
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = VariableSmmRuntimeInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+#  VIRTUAL_ADDRESS_MAP_CALLBACK  =  VariableAddressChangeEvent
+#
+
+[Sources]
+  VariableSmmRuntimeDxe.c
+  PrivilegePolymorphic.h
+  Measurement.c
+  VariableParsing.c
+  VariableParsing.h
+  Variable.h
+  VariablePolicySmmDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiBootServicesTableLib
+  DebugLib
+  UefiRuntimeLib
+  DxeServicesTableLib
+  UefiDriverEntryPoint
+  TpmMeasurementLib
+  SafeIntLib
+  PcdLib
+  MmUnblockMemoryLib
+  ProtectedVariableLib
+
+[Protocols]
+  gEfiVariableWriteArchProtocolGuid             ## PRODUCES
+  gEfiVariableArchProtocolGuid                  ## PRODUCES
+  gEfiMmCommunication2ProtocolGuid              ## CONSUMES
+  ## CONSUMES
+  ## NOTIFY
+  ## UNDEFINED # Used to do smm communication
+  gEfiSmmVariableProtocolGuid
+  gEdkiiVariableLockProtocolGuid                ## PRODUCES
+  gEdkiiVarCheckProtocolGuid                    ## PRODUCES
+  gEdkiiVariablePolicyProtocolGuid              ## PRODUCES
+
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache           ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics            ## CONSUMES
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES
+
+[Guids]
+  ## PRODUCES             ## GUID # Signature of Variable store header
+  ## CONSUMES             ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiAuthenticatedVariableGuid
+
+  ## PRODUCES             ## GUID # Signature of Variable store header
+  ## CONSUMES             ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiVariableGuid
+
+  gEfiEventVirtualAddressChangeGuid             ## CONSUMES ## Event
+  gEfiEventExitBootServicesGuid                 ## CONSUMES ## Event
+  ## CONSUMES ## GUID # Locate protocol
+  ## CONSUMES ## GUID # Protocol notify
+  gSmmVariableWriteGuid
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"PK"
+  ## SOMETIMES_CONSUMES   ## Variable:L"KEK"
+  ## SOMETIMES_CONSUMES   ## Variable:L"SecureBoot"
+  gEfiGlobalVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"db"
+  ## SOMETIMES_CONSUMES   ## Variable:L"dbx"
+  ## SOMETIMES_CONSUMES   ## Variable:L"dbt"
+  gEfiImageSecurityDatabaseGuid
+
+  gVarCheckPolicyLibMmiHandlerGuid
+  gEfiEndOfDxeEventGroupGuid
+
+[Depex]
+  gEfiMmCommunication2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  VariableSmmRuntimeDxeExtra.uni
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.inf b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.inf
new file mode 100644
index 000000000000..fb5a6c947890
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.inf
@@ -0,0 +1,143 @@
+## @file
+#  Provides SMM variable service.
+#
+#  This module installs SMM variable protocol into SMM protocol database,
+#  which can be used by SMM driver, and installs SMM variable protocol
+#  into BS protocol database, which can be used to notify the SMM Runtime
+#  Dxe driver that the SMM variable service is ready.
+#  This module should be used with SMM Runtime DXE module together. The
+#  SMM Runtime DXE module would install variable arch protocol and variable
+#  write arch protocol based on SMM variable module.
+#
+#  Caution: This module requires additional review when modified.
+#  This driver will have external input - variable data and communicate buffer in SMM mode.
+#  This external input must be validated carefully to avoid security issues such as
+#  buffer overflow or integer overflow.
+#    The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+#  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory
+#  may not be modified without authorization. If platform fails to protect these resources,
+#  the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = VariableStandaloneMm
+  FILE_GUID                      = 417E6192-7678-4A75-B638-305A86D82936
+  MODULE_TYPE                    = MM_STANDALONE
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x00010032
+  ENTRY_POINT                    = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+
+[Sources]
+  Reclaim.c
+  Variable.c
+  VariableSmm.c
+  VariableStandaloneMm.c
+  VariableNonVolatile.c
+  VariableNonVolatile.h
+  VariableParsing.c
+  VariableParsing.h
+  VariableRuntimeCache.c
+  VariableRuntimeCache.h
+  VarCheck.c
+  Variable.h
+  PrivilegePolymorphic.h
+  VariableExLib.c
+  TcgMorLockSmm.c
+  SpeculationBarrierSmm.c
+  VariableLockRequestToLock.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+  AuthVariableLib
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  HobLib
+  MemoryAllocationLib
+  MmServicesTableLib
+  SafeIntLib
+  StandaloneMmDriverEntryPoint
+  SynchronizationLib
+  VarCheckLib
+  VariableFlashInfoLib
+  VariablePolicyLib
+  VariablePolicyHelperLib
+  ProtectedVariableLib
+
+[Protocols]
+  gEfiSmmFirmwareVolumeBlockProtocolGuid        ## CONSUMES
+  ## CONSUMES
+  ## NOTIFY
+  gEfiSmmFaultTolerantWriteProtocolGuid
+  ## PRODUCES
+  ## UNDEFINED # SmiHandlerRegister
+  gEfiSmmVariableProtocolGuid
+  gEfiMmEndOfDxeProtocolGuid                   ## NOTIFY
+  gEdkiiSmmVarCheckProtocolGuid                ## PRODUCES
+
+[Guids]
+  ## SOMETIMES_CONSUMES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiAuthenticatedVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_PRODUCES   ## GUID # Signature of Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## SOMETIMES_PRODUCES   ## SystemTable
+  gEfiVariableGuid
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"PlatformLang"
+  ## SOMETIMES_PRODUCES   ## Variable:L"PlatformLang"
+  ## SOMETIMES_CONSUMES   ## Variable:L"Lang"
+  ## SOMETIMES_PRODUCES   ## Variable:L"Lang"
+  gEfiGlobalVariableGuid
+
+  gEfiMemoryOverwriteControlDataGuid            ## SOMETIMES_CONSUMES   ## Variable:L"MemoryOverwriteRequestControl"
+  gEfiMemoryOverwriteRequestControlLockGuid     ## SOMETIMES_PRODUCES   ## Variable:L"MemoryOverwriteRequestControlLock"
+
+  gEfiSystemNvDataFvGuid                        ## CONSUMES             ## GUID
+  gEdkiiFaultTolerantWriteGuid                  ## SOMETIMES_CONSUMES   ## HOB
+
+  ## SOMETIMES_CONSUMES   ## Variable:L"VarErrorFlag"
+  ## SOMETIMES_PRODUCES   ## Variable:L"VarErrorFlag"
+  gEdkiiVarErrorFlagGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize                  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize              ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize          ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize     ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize                ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize                 ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize           ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe   ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable          ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved       ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics        ## CONSUMES  # statistic the information of variable.
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate       ## CONSUMES  # Auto update PlatformLang/Lang
+
+[Depex]
+  TRUE
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphic.h b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphic.h
new file mode 100644
index 000000000000..7f14515b694f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphic.h
@@ -0,0 +1,158 @@
+/** @file
+  Polymorphic functions that are called from both the privileged driver (i.e.,
+  the DXE_SMM variable module) and the non-privileged drivers (i.e., one or
+  both of the DXE_RUNTIME variable modules).
+
+  Each of these functions has two implementations, appropriate for privileged
+  vs. non-privileged driver code.
+
+  Copyright (c) 2017, Red Hat, Inc.<BR>
+  Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef PRIVILEGE_POLYMORPHIC_H_
+#define PRIVILEGE_POLYMORPHIC_H_
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  SecureBoot Hook for auth variable update.
+
+  @param[in] VariableName                 Name of Variable to be found.
+  @param[in] VendorGuid                   Variable vendor GUID.
+**/
+VOID
+EFIAPI
+SecureBootHook (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  );
+
+/**
+  Initialization for MOR Control Lock.
+
+  @retval EFI_SUCCESS     MorLock initialization success.
+  @return Others          Some error occurs.
+**/
+EFI_STATUS
+MorLockInit (
+  VOID
+  );
+
+/**
+  Delayed initialization for MOR Control Lock at EndOfDxe.
+
+  This function performs any operations queued by MorLockInit().
+**/
+VOID
+MorLockInitAtEndOfDxe (
+  VOID
+  );
+
+/**
+  This service is an MOR/MorLock checker handler for the SetVariable().
+
+  @param[in]  VariableName the name of the vendor's variable, as a
+                           Null-Terminated Unicode String
+  @param[in]  VendorGuid   Unify identifier for vendor.
+  @param[in]  Attributes   Attributes bitmask to set for the variable.
+  @param[in]  DataSize     The size in bytes of Data-Buffer.
+  @param[in]  Data         Point to the content of the variable.
+
+  @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable
+                                  driver can store the variable data.
+  @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or
+                                  attributes is not allowed for MOR variable.
+  @retval  EFI_ACCESS_DENIED      The MOR/MorLock is locked.
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this
+                                  function. Variable driver can just return
+                                  EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  );
+
+/**
+  This service is consumed by the variable modules to place a barrier to stop
+  speculative execution.
+
+  Ensures that no later instruction will execute speculatively, until all prior
+  instructions have completed.
+
+**/
+VOID
+VariableSpeculationBarrier (
+  VOID
+  );
+
+/**
+  Notify the system that the SMM variable driver is ready.
+**/
+VOID
+VariableNotifySmmReady (
+  VOID
+  );
+
+/**
+  Notify the system that the SMM variable write driver is ready.
+**/
+VOID
+VariableNotifySmmWriteReady (
+  VOID
+  );
+
+/**
+  Variable Driver main entry point. The Variable driver places the 4 EFI
+  runtime services in the EFI System Table and installs arch protocols
+  for variable read and write services being available. It also registers
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+  @retval EFI_SUCCESS       Variable service successfully initialized.
+**/
+EFI_STATUS
+EFIAPI
+MmVariableServiceInitialize (
+  VOID
+  );
+
+/**
+  This function checks if the buffer is valid per processor architecture and
+  does not overlap with SMRAM.
+
+  @param Buffer The buffer start address to be checked.
+  @param Length The buffer length to be checked.
+
+  @retval TRUE  This buffer is valid per processor architecture and does not
+                overlap with SMRAM.
+  @retval FALSE This buffer is not valid per processor architecture or overlaps
+                with SMRAM.
+**/
+BOOLEAN
+VariableSmmIsBufferOutsideSmmValid (
+  IN EFI_PHYSICAL_ADDRESS  Buffer,
+  IN UINT64                Length
+  );
+
+/**
+  Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
+  This information is used by the MorLock code to infer whether an existing
+  MOR variable is legitimate or not.
+
+  @retval TRUE  Either the TCG or TCG2 protocol is installed in the UEFI
+                protocol database
+  @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
+                protocol database
+**/
+BOOLEAN
+VariableHaveTcgProtocols (
+  VOID
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
new file mode 100644
index 000000000000..c679e524043f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
@@ -0,0 +1,948 @@
+/** @file
+  The internal header file includes the common header files, defines
+  internal structure and functions used by Variable modules.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VARIABLE_H_
+#define VARIABLE_H_
+
+#include <PiDxe.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Variable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/VarCheck.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/AuthVariableLib.h>
+#include <Library/VarCheckLib.h>
+#include <Library/VariableFlashInfoLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/ProtectedVariableLib.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
+#include <Guid/VariableFormat.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+#include <Guid/VarErrorFlag.h>
+
+#include "PrivilegePolymorphic.h"
+
+#define EFI_VARIABLE_ATTRIBUTES_MASK  (EFI_VARIABLE_NON_VOLATILE |\
+                                      EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+                                      EFI_VARIABLE_RUNTIME_ACCESS | \
+                                      EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
+                                      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+                                      EFI_VARIABLE_APPEND_WRITE)
+
+///
+/// The size of a 3 character ISO639 language code.
+///
+#define ISO_639_2_ENTRY_SIZE  3
+
+typedef enum {
+  VariableStoreTypeVolatile,
+  VariableStoreTypeHob,
+  VariableStoreTypeNv,
+  VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+  UINT32                   PendingUpdateOffset;
+  UINT32                   PendingUpdateLength;
+  VARIABLE_STORE_HEADER    *Store;
+} VARIABLE_RUNTIME_CACHE;
+
+typedef struct {
+  BOOLEAN                   *ReadLock;
+  BOOLEAN                   *PendingUpdate;
+  BOOLEAN                   *HobFlushComplete;
+  VARIABLE_RUNTIME_CACHE    VariableRuntimeHobCache;
+  VARIABLE_RUNTIME_CACHE    VariableRuntimeNvCache;
+  VARIABLE_RUNTIME_CACHE    VariableRuntimeVolatileCache;
+} VARIABLE_RUNTIME_CACHE_CONTEXT;
+
+typedef struct {
+  VARIABLE_HEADER    *CurrPtr;
+  //
+  // If both ADDED and IN_DELETED_TRANSITION variable are present,
+  // InDeletedTransitionPtr will point to the IN_DELETED_TRANSITION one.
+  // Otherwise, CurrPtr will point to the ADDED or IN_DELETED_TRANSITION one,
+  // and InDeletedTransitionPtr will be NULL at the same time.
+  //
+  VARIABLE_HEADER    *InDeletedTransitionPtr;
+  VARIABLE_HEADER    *EndPtr;
+  VARIABLE_HEADER    *StartPtr;
+  BOOLEAN            Volatile;
+} VARIABLE_POINTER_TRACK;
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS              HobVariableBase;
+  EFI_PHYSICAL_ADDRESS              VolatileVariableBase;
+  EFI_PHYSICAL_ADDRESS              NonVolatileVariableBase;
+  VARIABLE_RUNTIME_CACHE_CONTEXT    VariableRuntimeCacheContext;
+  EFI_LOCK                          VariableServicesLock;
+  UINT32                            ReentrantState;
+  BOOLEAN                           AuthFormat;
+  BOOLEAN                           AuthSupport;
+  BOOLEAN                           EmuNvMode;
+} VARIABLE_GLOBAL;
+
+typedef struct {
+  VARIABLE_GLOBAL                       VariableGlobal;
+  UINTN                                 VolatileLastVariableOffset;
+  UINTN                                 NonVolatileLastVariableOffset;
+  UINTN                                 CommonVariableSpace;
+  UINTN                                 CommonMaxUserVariableSpace;
+  UINTN                                 CommonRuntimeVariableSpace;
+  UINTN                                 CommonVariableTotalSize;
+  UINTN                                 CommonUserVariableTotalSize;
+  UINTN                                 HwErrVariableTotalSize;
+  UINTN                                 MaxVariableSize;
+  UINTN                                 MaxAuthVariableSize;
+  UINTN                                 MaxVolatileVariableSize;
+  UINTN                                 ScratchBufferSize;
+  CHAR8                                 *PlatformLangCodes;
+  CHAR8                                 *LangCodes;
+  CHAR8                                 *PlatformLang;
+  CHAR8                                 Lang[ISO_639_2_ENTRY_SIZE + 1];
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *FvbInstance;
+} VARIABLE_MODULE_GLOBAL;
+
+/**
+  Flush the HOB variable to flash.
+
+  @param[in] VariableName       Name of variable has been updated or deleted.
+  @param[in] VendorGuid         Guid of variable has been updated or deleted.
+
+**/
+VOID
+FlushHobVariableToFlash (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  );
+
+/**
+  Writes a buffer to variable storage space, in the working block.
+
+  This function writes a buffer to variable storage space into a firmware
+  volume block device. The destination is specified by the parameter
+  VariableBase. Fault Tolerant Write protocol is used for writing.
+
+  @param  VariableBase   Base address of the variable to write.
+  @param  VariableBuffer Point to the variable data buffer.
+
+  @retval EFI_SUCCESS    The function completed successfully.
+  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.
+  @retval EFI_ABORTED    The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+  IN EFI_PHYSICAL_ADDRESS   VariableBase,
+  IN VARIABLE_STORE_HEADER  *VariableBuffer
+  );
+
+/**
+  Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.
+  If VariableName is an empty string, then we just return the first
+  qualified variable without comparing VariableName and VendorGuid.
+  If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
+  at runtime when searching existing variable, only VariableName and VendorGuid are compared.
+  Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
+
+  @param[in]   VariableName           Name of the variable to be found.
+  @param[in]   VendorGuid             Vendor GUID to be found.
+  @param[out]  PtrTrack               VARIABLE_POINTER_TRACK structure for output,
+                                      including the range searched and the target position.
+  @param[in]   Global                 Pointer to VARIABLE_GLOBAL structure, including
+                                      base of volatile variable storage area, base of
+                                      NV variable storage area, and a lock.
+  @param[in]   IgnoreRtCheck          Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+                                      check at runtime when searching variable.
+
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while
+                                      VendorGuid is NULL.
+  @retval EFI_SUCCESS                 Variable successfully found.
+  @retval EFI_NOT_FOUND               Variable not found
+
+**/
+EFI_STATUS
+FindVariable (
+  IN  CHAR16                  *VariableName,
+  IN  EFI_GUID                *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
+  IN  VARIABLE_GLOBAL         *Global,
+  IN  BOOLEAN                 IgnoreRtCheck
+  );
+
+/**
+  This function is to check if the remaining variable space is enough to set
+  all Variables from argument list successfully. The purpose of the check
+  is to keep the consistency of the Variables to be in variable storage.
+
+  Note: Variables are assumed to be in same storage.
+  The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+  so follow the argument sequence to check the Variables.
+
+  @param[in] Attributes         Variable attributes for Variable entries.
+  @param[in] Marker             VA_LIST style variable argument list.
+                                The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+                                A NULL terminates the list. The VariableSize of
+                                VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+                                It will be changed to variable total size as output.
+
+  @retval TRUE                  Have enough variable space to set the Variables successfully.
+  @retval FALSE                 No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistencyInternal (
+  IN UINT32   Attributes,
+  IN VA_LIST  Marker
+  );
+
+/**
+  Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+  index of associated public key is needed.
+
+  @param[in] VariableName       Name of variable.
+  @param[in] VendorGuid         Guid of variable.
+  @param[in] Data               Variable data.
+  @param[in] DataSize           Size of data. 0 means delete.
+  @param[in] Attributes         Attributes of the variable.
+  @param[in] KeyIndex           Index of associated public key.
+  @param[in] MonotonicCount     Value of associated monotonic count.
+  @param[in, out] Variable      The variable information that is used to keep track of variable usage.
+
+  @param[in] TimeStamp          Value of associated TimeStamp.
+
+  @retval EFI_SUCCESS           The update operation is success.
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, cannot write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariable (
+  IN      CHAR16                  *VariableName,
+  IN      EFI_GUID                *VendorGuid,
+  IN      VOID                    *Data,
+  IN      UINTN                   DataSize,
+  IN      UINT32                  Attributes OPTIONAL,
+  IN      UINT32                  KeyIndex  OPTIONAL,
+  IN      UINT64                  MonotonicCount  OPTIONAL,
+  IN OUT  VARIABLE_POINTER_TRACK  *Variable,
+  IN      EFI_TIME                *TimeStamp  OPTIONAL
+  );
+
+/**
+  Return TRUE if ExitBootServices () has been called.
+
+  @retval TRUE If ExitBootServices () has been called.
+**/
+BOOLEAN
+AtRuntime (
+  VOID
+  );
+
+/**
+  Initializes a basic mutual exclusion lock.
+
+  This function initializes a basic mutual exclusion lock to the released state
+  and returns the lock.  Each lock provides mutual exclusion access at its task
+  priority level.  Since there is no preemption or multiprocessor support in EFI,
+  acquiring the lock only consists of raising to the locks TPL.
+  If Lock is NULL, then ASSERT().
+  If Priority is not a valid TPL value, then ASSERT().
+
+  @param  Lock       A pointer to the lock data structure to initialize.
+  @param  Priority   EFI TPL is associated with the lock.
+
+  @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+  IN OUT EFI_LOCK  *Lock,
+  IN EFI_TPL       Priority
+  );
+
+/**
+  Acquires lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function that will be removed when
+  EfiAcquireLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiAcquireLock() at boot time, and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  );
+
+/**
+  Releases lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function which will be removed when
+  EfiReleaseLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiReleaseLock() at boot time and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  );
+
+/**
+  Retrieve the FVB protocol interface by HANDLE.
+
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for
+                                reading, writing, and erasing the target block.
+  @param[out] FvBlock           The interface of FVB protocol
+
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+GetFvbByHandle (
+  IN  EFI_HANDLE                          FvBlockHandle,
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock
+  );
+
+/**
+  Function returns an array of handles that support the FVB protocol
+  in a buffer allocated from pool.
+
+  @param[out]  NumberHandles    The number of handles returned in Buffer.
+  @param[out]  Buffer           A pointer to the buffer to return the requested
+                                array of  handles that support FVB protocol.
+
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of
+                                handles in Buffer was returned in NumberHandles.
+  @retval EFI_NOT_FOUND         No FVB handle was found.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+  OUT UINTN       *NumberHandles,
+  OUT EFI_HANDLE  **Buffer
+  );
+
+/**
+  Initializes variable store area for non-volatile and volatile variable.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+  VOID
+  );
+
+/**
+  This function reclaims variable storage if free size is below the threshold.
+
+**/
+VOID
+ReclaimForOS (
+  VOID
+  );
+
+/**
+  Get maximum variable size, covering both non-volatile and volatile variables.
+
+  @return Maximum variable size.
+
+**/
+UINTN
+GetMaxVariableSize (
+  VOID
+  );
+
+/**
+  Initializes variable write service.
+
+  @retval EFI_SUCCESS          Function successfully executed.
+  @retval Others               Fail to initialize the variable service.
+
+**/
+EFI_STATUS
+VariableWriteServiceInitialize (
+  VOID
+  );
+
+/**
+  Retrieve the SMM Fault Tolerent Write protocol interface.
+
+  @param[out] FtwProtocol       The interface of SMM Ftw protocol
+
+  @retval EFI_SUCCESS           The SMM SAR protocol instance was found and returned in SarProtocol.
+  @retval EFI_NOT_FOUND         The SMM SAR protocol instance was not found.
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+GetFtwProtocol (
+  OUT VOID  **FtwProtocol
+  );
+
+/**
+  Get the proper fvb handle and/or fvb protocol by the given Flash address.
+
+  @param[in] Address        The Flash address.
+  @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.
+  @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.
+
+**/
+EFI_STATUS
+GetFvbInfoByAddress (
+  IN  EFI_PHYSICAL_ADDRESS                Address,
+  OUT EFI_HANDLE                          *FvbHandle OPTIONAL,
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL
+  );
+
+/**
+
+  This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode, and datasize and data are external input.
+  This function will do basic validation, before parse the data.
+
+  @param VariableName               Name of Variable to be found.
+  @param VendorGuid                 Variable vendor GUID.
+  @param Attributes                 Attribute value of the variable found.
+  @param DataSize                   Size of Data found. If size is less than the
+                                    data, this value contains the required size.
+  @param Data                       The buffer to return the contents of the variable. May be NULL
+                                    with a zero DataSize in order to determine the size buffer needed.
+
+  @return EFI_INVALID_PARAMETER     Invalid parameter.
+  @return EFI_SUCCESS               Find the specified variable.
+  @return EFI_NOT_FOUND             Not found.
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetVariable (
+  IN      CHAR16    *VariableName,
+  IN      EFI_GUID  *VendorGuid,
+  OUT     UINT32    *Attributes OPTIONAL,
+  IN OUT  UINTN     *DataSize,
+  OUT     VOID      *Data OPTIONAL
+  );
+
+/**
+
+  This code Finds the Next available variable.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param VariableNameSize           The size of the VariableName buffer. The size must be large
+                                    enough to fit input string supplied in VariableName buffer.
+  @param VariableName               Pointer to variable name.
+  @param VendorGuid                 Variable Vendor Guid.
+
+  @retval EFI_SUCCESS               The function completed successfully.
+  @retval EFI_NOT_FOUND             The next variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL      The VariableNameSize is too small for the result.
+                                    VariableNameSize has been updated with the size needed to complete the request.
+  @retval EFI_INVALID_PARAMETER     VariableNameSize is NULL.
+  @retval EFI_INVALID_PARAMETER     VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER     VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER     The input values of VariableName and VendorGuid are not a name and
+                                    GUID of an existing variable.
+  @retval EFI_INVALID_PARAMETER     Null-terminator is not found in the first VariableNameSize bytes of
+                                    the input VariableName buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableName (
+  IN OUT  UINTN     *VariableNameSize,
+  IN OUT  CHAR16    *VariableName,
+  IN OUT  EFI_GUID  *VendorGuid
+  );
+
+/**
+
+  This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode, and datasize and data are external input.
+  This function will do basic validation, before parse the data.
+  This function will parse the authentication carefully to avoid security issues, like
+  buffer overflow, integer overflow.
+  This function will check attribute carefully to avoid authentication bypass.
+
+  @param VariableName                     Name of Variable to be found.
+  @param VendorGuid                       Variable vendor GUID.
+  @param Attributes                       Attribute value of the variable found
+  @param DataSize                         Size of Data found. If size is less than the
+                                          data, this value contains the required size.
+  @param Data                             Data pointer.
+
+  @return EFI_INVALID_PARAMETER           Invalid parameter.
+  @return EFI_SUCCESS                     Set successfully.
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
+  @return EFI_NOT_FOUND                   Not found.
+  @return EFI_WRITE_PROTECTED             Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceSetVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  );
+
+/**
+
+  This code returns information about the EFI variables.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param Attributes                     Attributes bitmask to specify the type of variables
+                                        on which to return information.
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available
+                                        for the EFI variables associated with the attributes specified.
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available
+                                        for EFI variables associated with the attributes specified.
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables
+                                        associated with the attributes specified.
+
+  @return EFI_SUCCESS                   Query successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfoInternal (
+  IN  UINT32  Attributes,
+  OUT UINT64  *MaximumVariableStorageSize,
+  OUT UINT64  *RemainingVariableStorageSize,
+  OUT UINT64  *MaximumVariableSize
+  );
+
+/**
+
+  This code returns information about the EFI variables.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param Attributes                     Attributes bitmask to specify the type of variables
+                                        on which to return information.
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available
+                                        for the EFI variables associated with the attributes specified.
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available
+                                        for EFI variables associated with the attributes specified.
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables
+                                        associated with the attributes specified.
+
+  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.
+  @return EFI_SUCCESS                   Query successfully.
+  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfo (
+  IN  UINT32  Attributes,
+  OUT UINT64  *MaximumVariableStorageSize,
+  OUT UINT64  *RemainingVariableStorageSize,
+  OUT UINT64  *MaximumVariableSize
+  );
+
+/**
+  Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+  @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.
+  @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.
+  @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.
+
+  @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked
+                                as pending to be read-only.
+  @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+                                Or VariableName is an empty string.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL  *This,
+  IN       CHAR16                        *VariableName,
+  IN       EFI_GUID                      *VendorGuid
+  );
+
+/**
+  Register SetVariable check handler.
+
+  @param[in] Handler            Pointer to check handler.
+
+  @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
+  @retval EFI_INVALID_PARAMETER Handler is NULL.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
+  @retval EFI_UNSUPPORTED       This interface is not implemented.
+                                For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+  IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER  Handler
+  );
+
+/**
+  Variable property set.
+
+  @param[in] Name               Pointer to the variable name.
+  @param[in] Guid               Pointer to the vendor GUID.
+  @param[in] VariableProperty   Pointer to the input variable property.
+
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+                                or the fields of VariableProperty are not valid.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+  IN CHAR16                       *Name,
+  IN EFI_GUID                     *Guid,
+  IN VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty
+  );
+
+/**
+  Variable property get.
+
+  @param[in]  Name              Pointer to the variable name.
+  @param[in]  Guid              Pointer to the vendor GUID.
+  @param[out] VariableProperty  Pointer to the output variable property.
+
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+  @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+  IN CHAR16                        *Name,
+  IN EFI_GUID                      *Guid,
+  OUT VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty
+  );
+
+/**
+  Initialize variable quota.
+
+**/
+VOID
+InitializeVariableQuota (
+  VOID
+  );
+
+extern VARIABLE_MODULE_GLOBAL      *mVariableModuleGlobal;
+extern EFI_FIRMWARE_VOLUME_HEADER  *mNvFvHeaderCache;
+extern VARIABLE_STORE_HEADER       *mNvVariableCache;
+extern VARIABLE_INFO_ENTRY         *gVariableInfo;
+extern BOOLEAN                     mEndOfDxe;
+extern VAR_CHECK_REQUEST_SOURCE    mRequestSource;
+
+extern AUTH_VAR_LIB_CONTEXT_OUT  mAuthContextOut;
+
+/**
+  Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.
+  If VariableName is an empty string, then we just return the first
+  qualified variable without comparing VariableName and VendorGuid.
+
+  @param[in]  VariableName          Name of the variable to be found.
+  @param[in]  VendorGuid            Variable vendor GUID to be found.
+  @param[out] AuthVariableInfo      Pointer to AUTH_VARIABLE_INFO structure for
+                                    output of the variable found.
+
+  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
+                                    while VendorGuid is NULL.
+  @retval EFI_SUCCESS               Variable successfully found.
+  @retval EFI_NOT_FOUND             Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindVariable (
+  IN  CHAR16              *VariableName,
+  IN  EFI_GUID            *VendorGuid,
+  OUT AUTH_VARIABLE_INFO  *AuthVariableInfo
+  );
+
+/**
+  Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+  This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+  If VariableName is an empty string, then we just return the first
+  qualified variable without comparing VariableName and VendorGuid.
+
+  @param[in]  VariableName          Name of the variable to be found.
+  @param[in]  VendorGuid            Variable vendor GUID to be found.
+  @param[out] AuthVariableInfo      Pointer to AUTH_VARIABLE_INFO structure for
+                                    output of the next variable.
+
+  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
+                                    while VendorGuid is NULL.
+  @retval EFI_SUCCESS               Variable successfully found.
+  @retval EFI_NOT_FOUND             Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindNextVariable (
+  IN  CHAR16              *VariableName,
+  IN  EFI_GUID            *VendorGuid,
+  OUT AUTH_VARIABLE_INFO  *AuthVariableInfo
+  );
+
+/**
+  Update the variable region with Variable information.
+
+  @param[in] AuthVariableInfo       Pointer AUTH_VARIABLE_INFO structure for
+                                    input of the variable.
+
+  @retval EFI_SUCCESS               The update operation is success.
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateVariable (
+  IN AUTH_VARIABLE_INFO  *AuthVariableInfo
+  );
+
+/**
+  Get scratch buffer.
+
+  @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+                                    the maximum supported buffer size, this value contains
+                                    the maximum supported buffer size as output.
+  @param[out]     ScratchBuffer     Pointer to scratch buffer address.
+
+  @retval EFI_SUCCESS       Get scratch buffer successfully.
+  @retval EFI_UNSUPPORTED   If input size is greater than the maximum supported buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibGetScratchBuffer (
+  IN OUT UINTN  *ScratchBufferSize,
+  OUT    VOID   **ScratchBuffer
+  );
+
+/**
+  This function is to check if the remaining variable space is enough to set
+  all Variables from argument list successfully. The purpose of the check
+  is to keep the consistency of the Variables to be in variable storage.
+
+  Note: Variables are assumed to be in same storage.
+  The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+  so follow the argument sequence to check the Variables.
+
+  @param[in] Attributes         Variable attributes for Variable entries.
+  @param ...                    The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+                                A NULL terminates the list. The VariableSize of
+                                VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+                                It will be changed to variable total size as output.
+
+  @retval TRUE                  Have enough variable space to set the Variables successfully.
+  @retval FALSE                 No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibCheckRemainingSpaceForConsistency (
+  IN UINT32  Attributes,
+  ...
+  );
+
+/**
+  Return TRUE if at OS runtime.
+
+  @retval TRUE If at OS runtime.
+  @retval FALSE If at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibAtRuntime (
+  VOID
+  );
+
+/**
+  Is user variable?
+
+  @param[in] Variable   Pointer to variable header.
+
+  @retval TRUE          User variable.
+  @retval FALSE         System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+  IN VARIABLE_HEADER  *Variable
+  );
+
+/**
+
+  Variable store garbage collection and reclaim operation.
+
+  @param[in]      VariableBase            Base address of variable store.
+  @param[out]     LastVariableOffset      Offset of last variable.
+  @param[in]      IsVolatile              The variable store is volatile or not;
+                                          if it is non-volatile, need FTW.
+  @param[in, out] UpdatingPtrTrack        Pointer to updating variable pointer track structure.
+  @param[in]      NewVariable             Pointer to new variable.
+  @param[in]      NewVariableSize         New variable size.
+
+  @return EFI_SUCCESS                  Reclaim operation has finished successfully.
+  @return EFI_OUT_OF_RESOURCES         No enough memory resources or variable space.
+  @return Others                       Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+  IN     EFI_PHYSICAL_ADDRESS    VariableBase,
+  OUT    UINTN                   *LastVariableOffset,
+  IN     BOOLEAN                 IsVolatile,
+  IN OUT VARIABLE_POINTER_TRACK  *UpdatingPtrTrack,
+  IN     VARIABLE_HEADER         *NewVariable,
+  IN     UINTN                   NewVariableSize
+  );
+
+/**
+
+  This function writes data to the FWH at the correct LBA even if the LBAs
+  are fragmented.
+
+  @param Global                  Pointer to VARIABLE_GLOBAL structure.
+  @param Volatile                Point out the Variable is Volatile or Non-Volatile.
+  @param SetByIndex              TRUE if target pointer is given as index.
+                                 FALSE if target pointer is absolute.
+  @param Fvb                     Pointer to the writable FVB protocol.
+  @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER
+                                 structure.
+  @param DataSize                Size of data to be written.
+  @param Buffer                  Pointer to the buffer from which data is written.
+
+  @retval EFI_INVALID_PARAMETER  Parameters not valid.
+  @retval EFI_UNSUPPORTED        Fvb is a NULL for Non-Volatile variable update.
+  @retval EFI_OUT_OF_RESOURCES   The remaining size is not enough.
+  @retval EFI_SUCCESS            Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+  IN VARIABLE_GLOBAL                     *Global,
+  IN BOOLEAN                             Volatile,
+  IN BOOLEAN                             SetByIndex,
+  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb,
+  IN UINTN                               DataPtrIndex,
+  IN UINT32                              DataSize,
+  IN UINT8                               *Buffer
+  );
+
+/**
+  Update partial data of a variable on NV storage and/or cached copy.
+
+  @param[in]  VariableInfo  Pointer to a variable with detailed information.
+  @param[in]  Offset        Offset to write from.
+  @param[in]  Size          Size of data Buffer to update.
+  @param[in]  Buffer        Pointer to data buffer to update.
+
+  @retval EFI_SUCCESS             The variable data was updated successfully.
+  @retval EFI_UNSUPPORTED         If this function is called directly in runtime.
+  @retval EFI_INVALID_PARAMETER   If VariableInfo, Buffer or Size are not valid.
+  @retval Others                  Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+  IN  PROTECTED_VARIABLE_INFO  *VariableInfo,
+  IN  UINTN                    Offset,
+  IN  UINT32                   Size,
+  IN  UINT8                    *Buffer
+  );
+
+/**
+  Finds the given variable in a variable store in SMM.
+
+  Caution: This function may receive untrusted input.
+  The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+  @param[in]      VariableName       Name of Variable to be found.
+  @param[in]      VendorGuid         Variable vendor GUID.
+  @param[out]     Attributes         Attribute value of the variable found.
+  @param[in, out] DataSize           Size of Data found. If size is less than the
+                                     data, this value contains the required size.
+  @param[out]     Data               Data pointer.
+
+  @retval EFI_SUCCESS                Found the specified variable.
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_NOT_FOUND              The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+FindVariableInSmm (
+  IN      CHAR16    *VariableName,
+  IN      EFI_GUID  *VendorGuid,
+  OUT     UINT32    *Attributes OPTIONAL,
+  IN OUT  UINTN     *DataSize,
+  OUT     VOID      *Data OPTIONAL
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.h b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.h
new file mode 100644
index 000000000000..a84db4877c13
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.h
@@ -0,0 +1,67 @@
+/** @file
+  Common variable non-volatile store routines.
+
+Copyright (c) 2019-2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VARIABLE_NON_VOLATILE_H_
+#define VARIABLE_NON_VOLATILE_H_
+
+#include "Variable.h"
+
+/**
+  Get non-volatile maximum variable size.
+
+  @return Non-volatile maximum variable size.
+
+**/
+UINTN
+GetNonVolatileMaxVariableSize (
+  VOID
+  );
+
+/**
+  Init emulated non-volatile variable store.
+
+  @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+InitEmuNonVolatileVariableStore (
+  EFI_PHYSICAL_ADDRESS  *VariableStoreBase
+  );
+
+/**
+  Init real non-volatile variable store.
+
+  @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+  @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitRealNonVolatileVariableStore (
+  OUT EFI_PHYSICAL_ADDRESS  *VariableStoreBase
+  );
+
+/**
+  Init non-volatile variable store.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+  @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+  VOID
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h
new file mode 100644
index 000000000000..5b040e00982f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h
@@ -0,0 +1,424 @@
+/** @file
+  Functions in this module are associated with variable parsing operations and
+  are intended to be usable across variable driver source files.
+
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VARIABLE_PARSING_H_
+#define VARIABLE_PARSING_H_
+
+#include <Guid/ImageAuthentication.h>
+#include "Variable.h"
+
+/**
+
+  This code checks if variable header is valid or not.
+
+  @param[in] Variable           Pointer to the Variable Header.
+  @param[in] VariableStoreEnd   Pointer to the Variable Store End.
+  @param[in] AuthFormat         Auth-variable indicator.
+
+  @retval TRUE              Variable header is valid.
+  @retval FALSE             Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  VARIABLE_HEADER  *VariableStoreEnd,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+
+  This code gets the current status of Variable Store.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @retval EfiRaw         Variable store status is raw.
+  @retval EfiValid       Variable store status is valid.
+  @retval EfiInvalid     Variable store status is invalid.
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+  This code gets the size of variable header.
+
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+  @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+  IN  BOOLEAN  AuthFormat
+  );
+
+/**
+
+  This code gets the size of name of variable.
+
+  @param[in]  Variable      Pointer to the variable header.
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+  @return UINTN          Size of variable in bytes.
+
+**/
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+  This code sets the size of name of variable.
+
+  @param[in]  Variable      Pointer to the Variable Header.
+  @param[in]  NameSize      Name size to set.
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetNameSizeOfVariable (
+  IN VARIABLE_HEADER  *Variable,
+  IN UINTN            NameSize,
+  IN BOOLEAN          AuthFormat
+  );
+
+/**
+
+  This code gets the size of variable data.
+
+  @param[in]  Variable      Pointer to the Variable Header.
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+  @return Size of variable in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+  This code sets the size of variable data.
+
+  @param[in] Variable   Pointer to the Variable Header.
+  @param[in] DataSize   Data size to set.
+  @param[in] AuthFormat TRUE indicates authenticated variables are used.
+                        FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetDataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  UINTN            DataSize,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+
+  This code gets the pointer to the variable name.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+  This code gets the pointer to the variable guid.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+
+  This code gets the pointer to the variable data.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+  This code gets the variable data offset related to variable header.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Variable Data offset.
+
+**/
+UINTN
+GetVariableDataOffset (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+  Get variable data payload.
+
+  @param[in]      Variable     Pointer to the Variable Header.
+  @param[out]     Data         Pointer to buffer used to store the variable data.
+  @param[in]      DataSize     Size of buffer passed by Data.
+  @param[out]     DataSize     Size of data copied into Data buffer.
+  @param[in]      AuthFlag     Auth-variable indicator.
+
+  @return EFI_SUCCESS             Data was fetched.
+  @return EFI_INVALID_PARAMETER   DataSize is NULL.
+  @return EFI_BUFFER_TOO_SMALL    DataSize is smaller than size of variable data.
+
+**/
+EFI_STATUS
+GetVariableData (
+  IN      VARIABLE_HEADER  *Variable,
+  IN  OUT VOID             *Data,
+  IN  OUT UINT32           *DataSize,
+  IN      BOOLEAN          AuthFlag
+  );
+
+/**
+
+  This code gets the pointer to the next variable header.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  );
+
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+  Compare two EFI_TIME data.
+
+
+  @param[in] FirstTime       A pointer to the first EFI_TIME data.
+  @param[in] SecondTime      A pointer to the second EFI_TIME data.
+
+  @retval  TRUE              The FirstTime is not later than the SecondTime.
+  @retval  FALSE             The FirstTime is later than the SecondTime.
+
+**/
+BOOLEAN
+VariableCompareTimeStampInternal (
+  IN EFI_TIME  *FirstTime,
+  IN EFI_TIME  *SecondTime
+  );
+
+/**
+  Find the variable in the specified variable store.
+
+  @param[in]       VariableName        Name of the variable to be found
+  @param[in]       VendorGuid          Vendor GUID to be found.
+  @param[in]       IgnoreRtCheck       Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+                                       check at runtime when searching variable.
+  @param[in, out]  PtrTrack            Variable Track Pointer structure that contains Variable Information.
+  @param[in]       AuthFormat          TRUE indicates authenticated variables are used.
+                                       FALSE indicates authenticated variables are not used.
+
+  @retval          EFI_SUCCESS         Variable found successfully
+  @retval          EFI_NOT_FOUND       Variable not found
+**/
+EFI_STATUS
+FindVariableEx (
+  IN     CHAR16                  *VariableName,
+  IN     EFI_GUID                *VendorGuid,
+  IN     BOOLEAN                 IgnoreRtCheck,
+  IN OUT VARIABLE_POINTER_TRACK  *PtrTrack,
+  IN     BOOLEAN                 AuthFormat
+  );
+
+/**
+  This code finds the next available variable.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param[in]  VariableName      Pointer to variable name.
+  @param[in]  VendorGuid        Variable Vendor Guid.
+  @param[in]  VariableStoreList A list of variable stores that should be used to get the next variable.
+                                The maximum number of entries is the max value of VARIABLE_STORE_TYPE.
+  @param[out] VariablePtr       Pointer to variable header address.
+  @param[in]  AuthFormat        TRUE indicates authenticated variables are used.
+                                FALSE indicates authenticated variables are not used.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+  @retval EFI_NOT_FOUND         The next variable was not found.
+  @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
+                                GUID of an existing variable.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableInternal (
+  IN  CHAR16                 *VariableName,
+  IN  EFI_GUID               *VendorGuid,
+  IN  VARIABLE_STORE_HEADER  **VariableStoreList,
+  OUT VARIABLE_HEADER        **VariablePtr,
+  IN  BOOLEAN                AuthFormat
+  );
+
+/**
+  Routine used to track statistical information about variable usage.
+  The data is stored in the EFI system table so it can be accessed later.
+  VariableInfo.efi can dump out the table. Only Boot Services variable
+  accesses are tracked by this code. The PcdVariableCollectStatistics
+  build flag controls if this feature is enabled.
+
+  A read that hits in the cache will have Read and Cache true for
+  the transaction. Data is allocated by this routine, but never
+  freed.
+
+  @param[in]      VariableName   Name of the Variable to track.
+  @param[in]      VendorGuid     Guid of the Variable to track.
+  @param[in]      Volatile       TRUE if volatile FALSE if non-volatile.
+  @param[in]      Read           TRUE if GetVariable() was called.
+  @param[in]      Write          TRUE if SetVariable() was called.
+  @param[in]      Delete         TRUE if deleted via SetVariable().
+  @param[in]      Cache          TRUE for a cache hit.
+  @param[in,out]  VariableInfo   Pointer to a pointer of VARIABLE_INFO_ENTRY structures.
+
+**/
+VOID
+UpdateVariableInfo (
+  IN  CHAR16                  *VariableName,
+  IN  EFI_GUID                *VendorGuid,
+  IN  BOOLEAN                 Volatile,
+  IN  BOOLEAN                 Read,
+  IN  BOOLEAN                 Write,
+  IN  BOOLEAN                 Delete,
+  IN  BOOLEAN                 Cache,
+  IN OUT VARIABLE_INFO_ENTRY  **VariableInfo
+  );
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VariableInfo->StoreIndex is invalid, the first one in VariableStore is returned.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
+  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
+  @retval EFI_SUCCESS            The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+  IN OUT  PROTECTED_VARIABLE_INFO  *VariableInfo
+  );
+
+/**
+
+  Retrieve details about a variable and return them in VariableInfo->Header.
+
+  If VariableInfo->Buffer is given, this function will calculate its offset
+  relative to given variable storage via VariableStore; Otherwise, it will try
+  other internal variable storages or cached copies. It's assumed that, for all
+  copies of NV variable storage, all variables are stored in the same relative
+  position. If VariableInfo->Buffer is found in the range of any storage copies,
+  its offset relative to that storage should be the same in other copies.
+
+  If VariableInfo->Offset is given (non-zero) but not VariableInfo->Buffer,
+  this function will return the variable memory address inside VariableStore,
+  if given, via VariableInfo->Address; Otherwise, the address of other storage
+  copies will be returned, if any.
+
+  For a new variable whose offset has not been determined, a value of -1 as
+  VariableInfo->Offset should be passed to skip the offset calculation.
+
+  @param VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo->Address
+                                 and VariableInfo->Offset are NULL (0).
+  @retval EFI_NOT_FOUND          If given Address or Offset is out of range of
+                                 any given or internal storage copies.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+  IN OUT  PROTECTED_VARIABLE_INFO  *VariableInfo
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.h b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.h
new file mode 100644
index 000000000000..77dbce0f907c
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.h
@@ -0,0 +1,51 @@
+/** @file
+  The common variable volatile store routines shared by the DXE_RUNTIME variable
+  module and the DXE_SMM variable module.
+
+Copyright (c) 2019-2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VARIABLE_RUNTIME_CACHE_H_
+#define VARIABLE_RUNTIME_CACHE_H_
+
+#include "Variable.h"
+
+/**
+  Copies any pending updates to runtime variable caches.
+
+  @retval EFI_UNSUPPORTED         The volatile store to be updated is not initialized properly.
+  @retval EFI_SUCCESS             The volatile store was updated successfully.
+
+**/
+EFI_STATUS
+FlushPendingRuntimeVariableCacheUpdates (
+  VOID
+  );
+
+/**
+  Synchronizes the runtime variable caches with all pending updates outside runtime.
+
+  Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt
+  to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the
+  update is added as a pending update for the given variable store and it will be flushed to the runtime cache
+  at the next opportunity the ReadLock is available.
+
+  @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized.
+  @param[in] Offset               Offset in bytes to apply the update.
+  @param[in] Length               Length of data in bytes of the update.
+
+  @retval EFI_SUCCESS             The update was added as a pending update successfully. If the variable runtime
+                                  cache ReadLock was available, the runtime cache was updated successfully.
+  @retval EFI_UNSUPPORTED         The volatile store to be updated is not initialized properly.
+
+**/
+EFI_STATUS
+SynchronizeRuntimeVariableCache (
+  IN  VARIABLE_RUNTIME_CACHE  *VariableRuntimeCache,
+  IN  UINTN                   Offset,
+  IN  UINTN                   Length
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
new file mode 100644
index 000000000000..c15cce97165d
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
@@ -0,0 +1,343 @@
+/** @file
+  Measure TCG required variable.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/ImageAuthentication.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+#include "PrivilegePolymorphic.h"
+
+typedef struct {
+  CHAR16      *VariableName;
+  EFI_GUID    *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE  mVariableType[] = {
+  { EFI_SECURE_BOOT_MODE_NAME,    &gEfiGlobalVariableGuid        },
+  { EFI_PLATFORM_KEY_NAME,        &gEfiGlobalVariableGuid        },
+  { EFI_KEY_EXCHANGE_KEY_NAME,    &gEfiGlobalVariableGuid        },
+  { EFI_IMAGE_SECURITY_DATABASE,  &gEfiImageSecurityDatabaseGuid },
+  { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid },
+  { EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid },
+};
+
+//
+// "SecureBoot" may update following PK Del/Add
+//  Cache its value to detect value update
+//
+UINT8  *mSecureBootVarData    = NULL;
+UINTN  mSecureBootVarDataSize = 0;
+
+/**
+  This function will return if this variable is SecureBootPolicy Variable.
+
+  @param[in]  VariableName      A Null-terminated string that is the name of the vendor's variable.
+  @param[in]  VendorGuid        A unique identifier for the vendor.
+
+  @retval TRUE  This is SecureBootPolicy Variable
+  @retval FALSE This is not SecureBootPolicy Variable
+**/
+BOOLEAN
+IsSecureBootPolicyVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0]); Index++) {
+    if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
+        (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid)))
+    {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Measure and log an EFI variable, and extend the measurement result into a specific PCR.
+
+  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
+  @param[in]  VendorGuid        A unique identifier for the vendor.
+  @param[in]  VarData           The content of the variable data.
+  @param[in]  VarSize           The size of the variable data.
+
+  @retval EFI_SUCCESS           Operation completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureVariable (
+  IN      CHAR16    *VarName,
+  IN      EFI_GUID  *VendorGuid,
+  IN      VOID      *VarData,
+  IN      UINTN     VarSize
+  )
+{
+  EFI_STATUS          Status;
+  UINTN               VarNameLength;
+  UEFI_VARIABLE_DATA  *VarLog;
+  UINT32              VarLogSize;
+
+  ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL));
+
+  VarNameLength = StrLen (VarName);
+  VarLogSize    = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
+                           - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
+
+  VarLog = (UEFI_VARIABLE_DATA *)AllocateZeroPool (VarLogSize);
+  if (VarLog == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CopyMem (&VarLog->VariableName, VendorGuid, sizeof (VarLog->VariableName));
+  VarLog->UnicodeNameLength  = VarNameLength;
+  VarLog->VariableDataLength = VarSize;
+  CopyMem (
+    VarLog->UnicodeName,
+    VarName,
+    VarNameLength * sizeof (*VarName)
+    );
+  if (VarSize != 0) {
+    CopyMem (
+      (CHAR16 *)VarLog->UnicodeName + VarNameLength,
+      VarData,
+      VarSize
+      );
+  }
+
+  DEBUG ((DEBUG_INFO, "VariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_DRIVER_CONFIG));
+  DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+  Status = TpmMeasureAndLogData (
+             7,
+             EV_EFI_VARIABLE_DRIVER_CONFIG,
+             VarLog,
+             VarLogSize,
+             VarLog,
+             VarLogSize
+             );
+  FreePool (VarLog);
+  return Status;
+}
+
+/**
+  Returns the status whether get the variable success. The function retrieves
+  variable  through the UEFI Runtime Service GetVariable().  The
+  returned buffer is allocated using AllocatePool().  The caller is responsible
+  for freeing this buffer with FreePool().
+
+  This API is only invoked in boot time. It may NOT be invoked at runtime.
+
+  @param[in]  Name  The pointer to a Null-terminated Unicode string.
+  @param[in]  Guid  The pointer to an EFI_GUID structure
+  @param[out] Value The buffer point saved the variable info.
+  @param[out] Size  The buffer size of the variable.
+
+  @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
+  @return EFI_SUCCESS               Find the specified variable.
+  @return Others Errors             Return errors from call to gRT->GetVariable.
+
+**/
+EFI_STATUS
+InternalGetVariable (
+  IN CONST CHAR16    *Name,
+  IN CONST EFI_GUID  *Guid,
+  OUT VOID           **Value,
+  OUT UINTN          *Size
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+
+  //
+  // Try to get the variable size.
+  //
+  BufferSize = 0;
+  *Value     = NULL;
+  if (Size != NULL) {
+    *Size = 0;
+  }
+
+  Status = gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, NULL, &BufferSize, *Value);
+  if (Status != EFI_BUFFER_TOO_SMALL) {
+    return Status;
+  }
+
+  //
+  // Allocate buffer to get the variable.
+  //
+  *Value = AllocatePool (BufferSize);
+  ASSERT (*Value != NULL);
+  if (*Value == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Get the variable data.
+  //
+  Status = gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, NULL, &BufferSize, *Value);
+  if (EFI_ERROR (Status)) {
+    FreePool (*Value);
+    *Value = NULL;
+  }
+
+  if (Size != NULL) {
+    *Size = BufferSize;
+  }
+
+  return Status;
+}
+
+/**
+  SecureBoot Hook for SetVariable.
+
+  @param[in] VariableName                 Name of Variable to be found.
+  @param[in] VendorGuid                   Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       VariableDataSize;
+  VOID        *VariableData;
+
+  if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) {
+    return;
+  }
+
+  //
+  // We should NOT use Data and DataSize here,because it may include signature,
+  // or is just partial with append attributes, or is deleted.
+  // We should GetVariable again, to get full variable content.
+  //
+  Status = InternalGetVariable (
+             VariableName,
+             VendorGuid,
+             &VariableData,
+             &VariableDataSize
+             );
+  if (EFI_ERROR (Status)) {
+    //
+    // Measure DBT only if present and not empty
+    //
+    if ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) &&
+        CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid))
+    {
+      DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2));
+      return;
+    } else {
+      VariableData     = NULL;
+      VariableDataSize = 0;
+    }
+  }
+
+  Status = MeasureVariable (
+             VariableName,
+             VendorGuid,
+             VariableData,
+             VariableDataSize
+             );
+  DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status));
+
+  if (VariableData != NULL) {
+    FreePool (VariableData);
+  }
+
+  //
+  // "SecureBoot" is 8bit & read-only. It can only be changed according to PK update
+  //
+  if ((StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0) &&
+      CompareGuid (VendorGuid, &gEfiGlobalVariableGuid))
+  {
+    Status = InternalGetVariable (
+               EFI_SECURE_BOOT_MODE_NAME,
+               &gEfiGlobalVariableGuid,
+               &VariableData,
+               &VariableDataSize
+               );
+    if (EFI_ERROR (Status)) {
+      return;
+    }
+
+    //
+    // If PK update is successful. "SecureBoot" shall always exist ever since variable write service is ready
+    //
+    ASSERT (mSecureBootVarData != NULL);
+
+    if (CompareMem (mSecureBootVarData, VariableData, VariableDataSize) != 0) {
+      FreePool (mSecureBootVarData);
+      mSecureBootVarData     = VariableData;
+      mSecureBootVarDataSize = VariableDataSize;
+
+      DEBUG ((DEBUG_INFO, "%s variable updated according to PK change. Remeasure the value!\n", EFI_SECURE_BOOT_MODE_NAME));
+      Status = MeasureVariable (
+                 EFI_SECURE_BOOT_MODE_NAME,
+                 &gEfiGlobalVariableGuid,
+                 mSecureBootVarData,
+                 mSecureBootVarDataSize
+                 );
+      DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status));
+    } else {
+      //
+      // "SecureBoot" variable is not changed
+      //
+      FreePool (VariableData);
+    }
+  }
+
+  return;
+}
+
+/**
+  Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+  Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Record initial "SecureBoot" variable value.
+  // It is used to detect SecureBoot variable change in SecureBootHook.
+  //
+  Status = InternalGetVariable (
+             EFI_SECURE_BOOT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             (VOID **)&mSecureBootVarData,
+             &mSecureBootVarDataSize
+             );
+  if (EFI_ERROR (Status)) {
+    //
+    // Read could fail when Auth Variable solution is not supported
+    //
+    DEBUG ((DEBUG_INFO, "RecordSecureBootPolicyVarData GetVariable %s Status %x\n", EFI_SECURE_BOOT_MODE_NAME, Status));
+  }
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
new file mode 100644
index 000000000000..a5b7f8a1fbe2
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
@@ -0,0 +1,504 @@
+/** @file
+  Handles non-volatile variable store garbage collection, using FTW
+  (Fault Tolerant Write) protocol.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+/**
+  Gets LBA of block and offset by given address.
+
+  This function gets the Logical Block Address (LBA) of a firmware
+  volume block containing the given address, and the offset of the
+  address on the block.
+
+  @param  Address        Address which should be contained
+                         by returned FVB handle.
+  @param  Lba            Pointer to LBA for output.
+  @param  Offset         Pointer to offset for output.
+
+  @retval EFI_SUCCESS    LBA and offset successfully returned.
+  @retval EFI_NOT_FOUND  Fail to find FVB handle by address.
+  @retval EFI_ABORTED    Fail to find valid LBA and offset.
+
+**/
+EFI_STATUS
+GetLbaAndOffsetByAddress (
+  IN  EFI_PHYSICAL_ADDRESS  Address,
+  OUT EFI_LBA               *Lba,
+  OUT UINTN                 *Offset
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
+  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
+  EFI_FV_BLOCK_MAP_ENTRY              *FvbMapEntry;
+  UINT32                              LbaIndex;
+
+  Fvb     = NULL;
+  *Lba    = (EFI_LBA)(-1);
+  *Offset = 0;
+
+  //
+  // Get the proper FVB protocol.
+  //
+  Status = GetFvbInfoByAddress (Address, NULL, &Fvb);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the Base Address of FV.
+  //
+  Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbBaseAddress);
+
+  //
+  // Get the (LBA, Offset) of Address.
+  //
+  if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
+    //
+    // BUGBUG: Assume one FV has one type of BlockLength.
+    //
+    FvbMapEntry = &FwVolHeader->BlockMap[0];
+    for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
+      if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
+        //
+        // Found the (Lba, Offset).
+        //
+        *Lba    = LbaIndex - 1;
+        *Offset = (UINTN)(Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_ABORTED;
+}
+
+/**
+  Writes a buffer to variable storage space, in the working block.
+
+  This function writes a buffer to variable storage space into a firmware
+  volume block device. The destination is specified by parameter
+  VariableBase. Fault Tolerant Write protocol is used for writing.
+
+  @param  VariableBase   Base address of variable to write
+  @param  VariableBuffer Point to the variable data buffer.
+
+  @retval EFI_SUCCESS    The function completed successfully.
+  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.
+  @retval EFI_ABORTED    The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+  IN EFI_PHYSICAL_ADDRESS   VariableBase,
+  IN VARIABLE_STORE_HEADER  *VariableBuffer
+  )
+{
+  EFI_STATUS                         Status;
+  EFI_HANDLE                         FvbHandle;
+  EFI_LBA                            VarLba;
+  UINTN                              VarOffset;
+  UINTN                              FtwBufferSize;
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol;
+
+  //
+  // Locate fault tolerant write protocol.
+  //
+  Status = GetFtwProtocol ((VOID **)&FtwProtocol);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Locate Fvb handle by address.
+  //
+  Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get LBA and Offset by address.
+  //
+  Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
+  if (EFI_ERROR (Status)) {
+    return EFI_ABORTED;
+  }
+
+  FtwBufferSize = ((VARIABLE_STORE_HEADER *)((UINTN)VariableBase))->Size;
+  ASSERT (FtwBufferSize == VariableBuffer->Size);
+
+  //
+  // FTW write record.
+  //
+  Status = FtwProtocol->Write (
+                          FtwProtocol,
+                          VarLba,                // LBA
+                          VarOffset,             // Offset
+                          FtwBufferSize,         // NumBytes
+                          NULL,                  // PrivateData NULL
+                          FvbHandle,             // Fvb Handle
+                          (VOID *)VariableBuffer // write buffer
+                          );
+
+  return Status;
+}
+
+/**
+
+  Variable store garbage collection and reclaim operation.
+
+  @param[in]      VariableBase            Base address of variable store.
+  @param[out]     LastVariableOffset      Offset of last variable.
+  @param[in]      IsVolatile              The variable store is volatile or not;
+                                          if it is non-volatile, need FTW.
+  @param[in, out] UpdatingPtrTrack        Pointer to updating variable pointer track structure.
+  @param[in]      NewVariable             Pointer to new variable.
+  @param[in]      NewVariableSize         New variable size.
+
+  @return EFI_SUCCESS                  Reclaim operation has finished successfully.
+  @return EFI_OUT_OF_RESOURCES         No enough memory resources or variable space.
+  @return Others                       Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+  IN     EFI_PHYSICAL_ADDRESS    VariableBase,
+  OUT    UINTN                   *LastVariableOffset,
+  IN     BOOLEAN                 IsVolatile,
+  IN OUT VARIABLE_POINTER_TRACK  *UpdatingPtrTrack,
+  IN     VARIABLE_HEADER         *NewVariable,
+  IN     UINTN                   NewVariableSize
+  )
+{
+  VARIABLE_HEADER        *Variable;
+  VARIABLE_HEADER        *AddedVariable;
+  VARIABLE_HEADER        *NextVariable;
+  VARIABLE_HEADER        *NextAddedVariable;
+  VARIABLE_STORE_HEADER  *VariableStoreHeader;
+  UINT8                  *ValidBuffer;
+  UINTN                  MaximumBufferSize;
+  UINTN                  VariableSize;
+  UINTN                  NameSize;
+  UINT8                  *CurrPtr;
+  VOID                   *Point0;
+  VOID                   *Point1;
+  BOOLEAN                FoundAdded;
+  EFI_STATUS             Status;
+  EFI_STATUS             DoneStatus;
+  UINTN                  CommonVariableTotalSize;
+  UINTN                  CommonUserVariableTotalSize;
+  UINTN                  HwErrVariableTotalSize;
+  VARIABLE_HEADER        *UpdatingVariable;
+  VARIABLE_HEADER        *UpdatingInDeletedTransition;
+  BOOLEAN                AuthFormat;
+
+  AuthFormat                  = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+  UpdatingVariable            = NULL;
+  UpdatingInDeletedTransition = NULL;
+  if (UpdatingPtrTrack != NULL) {
+    UpdatingVariable            = UpdatingPtrTrack->CurrPtr;
+    UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
+  }
+
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
+
+  CommonVariableTotalSize     = 0;
+  CommonUserVariableTotalSize = 0;
+  HwErrVariableTotalSize      = 0;
+
+  if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+    //
+    // Start Pointers for the variable.
+    //
+    Variable          = GetStartPointer (VariableStoreHeader);
+    MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+    while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+      NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+      if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
+          (Variable != UpdatingVariable) &&
+          (Variable != UpdatingInDeletedTransition)
+          )
+      {
+        VariableSize       = (UINTN)NextVariable - (UINTN)Variable;
+        MaximumBufferSize += VariableSize;
+      }
+
+      Variable = NextVariable;
+    }
+
+    if (NewVariable != NULL) {
+      //
+      // Add the new variable size.
+      //
+      MaximumBufferSize += NewVariableSize;
+    }
+
+    //
+    // Reserve the 1 Bytes with Oxff to identify the
+    // end of the variable buffer.
+    //
+    MaximumBufferSize += 1;
+    ValidBuffer        = AllocatePool (MaximumBufferSize);
+    if (ValidBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
+    // as the buffer to reduce SMRAM consumption for SMM variable driver.
+    //
+    MaximumBufferSize = mNvVariableCache->Size;
+    ValidBuffer       = (UINT8 *)mNvVariableCache;
+  }
+
+  SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+  //
+  // Copy variable store header.
+  //
+  CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
+  CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+
+  //
+  // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
+  //
+  Variable = GetStartPointer (VariableStoreHeader);
+  while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+    NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+    if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
+      VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+      CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+      if (!IsVolatile) {
+        (VOID)ProtectedVariableLibRefresh (
+                (VARIABLE_HEADER *)CurrPtr,
+                VariableSize,
+                (UINTN)CurrPtr - (UINTN)ValidBuffer,
+                FALSE
+                );
+
+        if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+            == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+        {
+          HwErrVariableTotalSize += VariableSize;
+        } else {
+          CommonVariableTotalSize += VariableSize;
+          if (IsUserVariable (Variable)) {
+            CommonUserVariableTotalSize += VariableSize;
+          }
+        }
+      }
+
+      CurrPtr += VariableSize;
+    }
+
+    Variable = NextVariable;
+  }
+
+  //
+  // Reinstall all in delete transition variables.
+  //
+  Variable = GetStartPointer (VariableStoreHeader);
+  while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)) {
+    NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+    if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
+        (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthFormat)) == FALSE))
+    {
+      FoundAdded    = FALSE;
+      AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
+      while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer), AuthFormat)) {
+        NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
+        NameSize          = NameSizeOfVariable (AddedVariable, AuthFormat);
+        if (CompareGuid (
+              GetVendorGuidPtr (AddedVariable, AuthFormat),
+              GetVendorGuidPtr (Variable, AuthFormat)
+              ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
+        {
+          Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
+          Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
+          if (CompareMem (Point0, Point1, NameSize) == 0) {
+            FoundAdded = TRUE;
+            break;
+          }
+        }
+
+        AddedVariable = NextAddedVariable;
+      }
+
+      if (!FoundAdded) {
+        //
+        // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
+        //
+        VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+        CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
+        ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+        if (!IsVolatile) {
+          (VOID)ProtectedVariableLibRefresh (
+                  (VARIABLE_HEADER *)CurrPtr,
+                  VariableSize,
+                  (UINTN)CurrPtr - (UINTN)ValidBuffer,
+                  FALSE
+                  );
+
+          if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+              == EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+          {
+            HwErrVariableTotalSize += VariableSize;
+          } else {
+            CommonVariableTotalSize += VariableSize;
+            if (IsUserVariable (Variable)) {
+              CommonUserVariableTotalSize += VariableSize;
+            }
+          }
+        }
+
+        CurrPtr += VariableSize;
+      }
+    }
+
+    Variable = NextVariable;
+  }
+
+  //
+  // Install the new variable if it is not NULL.
+  //
+  if (NewVariable != NULL) {
+    if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
+      //
+      // No enough space to store the new variable.
+      //
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+
+    if (!IsVolatile) {
+      if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+        HwErrVariableTotalSize += NewVariableSize;
+      } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+        CommonVariableTotalSize += NewVariableSize;
+        if (IsUserVariable (NewVariable)) {
+          CommonUserVariableTotalSize += NewVariableSize;
+        }
+      }
+
+      if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
+          (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
+          (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+      {
+        //
+        // No enough space to store the new variable by NV or NV+HR attribute.
+        //
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Done;
+      }
+    }
+
+    CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
+    ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
+    if (UpdatingVariable != NULL) {
+      UpdatingPtrTrack->CurrPtr                = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
+      UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
+    }
+
+    CurrPtr += NewVariableSize;
+  }
+
+  if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+    //
+    // If volatile/emulated non-volatile variable store, just copy valid buffer.
+    //
+    SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
+    CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);
+    *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+    if (!IsVolatile) {
+      //
+      // Emulated non-volatile variable mode.
+      //
+      mVariableModuleGlobal->HwErrVariableTotalSize      = HwErrVariableTotalSize;
+      mVariableModuleGlobal->CommonVariableTotalSize     = CommonVariableTotalSize;
+      mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+    }
+
+    Status = EFI_SUCCESS;
+  } else {
+    //
+    // If non-volatile variable store, perform FTW here.
+    //
+    Status = FtwVariableSpace (
+               VariableBase,
+               (VARIABLE_STORE_HEADER *)ValidBuffer
+               );
+    if (!EFI_ERROR (Status)) {
+      *LastVariableOffset                                = (UINTN)CurrPtr - (UINTN)ValidBuffer;
+      mVariableModuleGlobal->HwErrVariableTotalSize      = HwErrVariableTotalSize;
+      mVariableModuleGlobal->CommonVariableTotalSize     = CommonVariableTotalSize;
+      mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+    } else {
+      mVariableModuleGlobal->HwErrVariableTotalSize      = 0;
+      mVariableModuleGlobal->CommonVariableTotalSize     = 0;
+      mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
+      Variable                                           = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
+      while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase), AuthFormat)) {
+        NextVariable = GetNextVariablePtr (Variable, AuthFormat);
+        VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+        if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+        } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+          mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+          if (IsUserVariable (Variable)) {
+            mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+          }
+        }
+
+        Variable = NextVariable;
+      }
+
+      *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
+    }
+  }
+
+Done:
+  DoneStatus = EFI_SUCCESS;
+  if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+    DoneStatus = SynchronizeRuntimeVariableCache (
+                   &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,
+                   0,
+                   VariableStoreHeader->Size
+                   );
+    ASSERT_EFI_ERROR (DoneStatus);
+    FreePool (ValidBuffer);
+  } else {
+    //
+    // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
+    //
+    CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
+    DoneStatus = SynchronizeRuntimeVariableCache (
+                   &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+                   0,
+                   VariableStoreHeader->Size
+                   );
+    ASSERT_EFI_ERROR (DoneStatus);
+  }
+
+  if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
+    Status = DoneStatus;
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c
new file mode 100644
index 000000000000..b2bcb97932ba
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c
@@ -0,0 +1,607 @@
+/** @file
+  This is a host-based unit test for the VariableLockRequestToLock shim.
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UnitTestLib.h>
+#include <Library/VariablePolicyLib.h>
+#include <Library/VariablePolicyHelperLib.h>
+
+#include <Protocol/VariableLock.h>
+
+#define UNIT_TEST_NAME     "VarPol/VarLock Shim Unit Test"
+#define UNIT_TEST_VERSION  "1.0"
+
+/// === CODE UNDER TEST ===========================================================================
+
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL  *This,
+  IN       CHAR16                        *VariableName,
+  IN       EFI_GUID                      *VendorGuid
+  );
+
+/// === TEST DATA ==================================================================================
+
+//
+// Test GUID 1 {F955BA2D-4A2C-480C-BFD1-3CC522610592}
+//
+EFI_GUID  mTestGuid1 = {
+  0xf955ba2d, 0x4a2c, 0x480c, { 0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5, 0x92 }
+};
+
+//
+// Test GUID 2 {2DEA799E-5E73-43B9-870E-C945CE82AF3A}
+//
+EFI_GUID  mTestGuid2 = {
+  0x2dea799e, 0x5e73, 0x43b9, { 0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf, 0x3a }
+};
+
+//
+// Test GUID 3 {698A2BFD-A616-482D-B88C-7100BD6682A9}
+//
+EFI_GUID  mTestGuid3 = {
+  0x698a2bfd, 0xa616, 0x482d, { 0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82, 0xa9 }
+};
+
+#define TEST_VAR_1_NAME  L"TestVar1"
+#define TEST_VAR_2_NAME  L"TestVar2"
+#define TEST_VAR_3_NAME  L"TestVar3"
+
+#define TEST_POLICY_ATTRIBUTES_NULL  0
+#define TEST_POLICY_MIN_SIZE_NULL    0
+#define TEST_POLICY_MAX_SIZE_NULL    MAX_UINT32
+
+#define TEST_POLICY_MIN_SIZE_10   10
+#define TEST_POLICY_MAX_SIZE_200  200
+
+/// === HELPER FUNCTIONS ===========================================================================
+
+/**
+  Mocked version of GetVariable, for testing.
+
+  @param  VariableName
+  @param  VendorGuid
+  @param  Attributes
+  @param  DataSize
+  @param  Data
+**/
+EFI_STATUS
+EFIAPI
+StubGetVariableNull (
+  IN     CHAR16    *VariableName,
+  IN     EFI_GUID  *VendorGuid,
+  OUT    UINT32    *Attributes   OPTIONAL,
+  IN OUT UINTN     *DataSize,
+  OUT    VOID      *Data         OPTIONAL
+  )
+{
+  UINT32      MockedAttr;
+  UINTN       MockedDataSize;
+  VOID        *MockedData;
+  EFI_STATUS  MockedReturn;
+
+  check_expected_ptr (VariableName);
+  check_expected_ptr (VendorGuid);
+  check_expected_ptr (DataSize);
+
+  MockedAttr     = (UINT32)mock ();
+  MockedDataSize = (UINTN)mock ();
+  MockedData     = (VOID *)(UINTN)mock ();
+  MockedReturn   = (EFI_STATUS)mock ();
+
+  if (Attributes != NULL) {
+    *Attributes = MockedAttr;
+  }
+
+  if ((Data != NULL) && !EFI_ERROR (MockedReturn)) {
+    CopyMem (Data, MockedData, MockedDataSize);
+  }
+
+  *DataSize = MockedDataSize;
+
+  return MockedReturn;
+}
+
+//
+// Anything you think might be helpful that isn't a test itself.
+//
+
+/**
+  This is a common setup function that will ensure the library is always
+  initialized with the stubbed GetVariable.
+
+  Not used by all test cases, but by most.
+
+  @param[in]  Context  Unit test case context
+**/
+STATIC
+UNIT_TEST_STATUS
+EFIAPI
+LibInitMocked (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  return EFI_ERROR (InitVariablePolicyLib (StubGetVariableNull)) ? UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;
+}
+
+/**
+  Common cleanup function to make sure that the library is always de-initialized
+  prior to the next test case.
+
+  @param[in]  Context  Unit test case context
+**/
+STATIC
+VOID
+EFIAPI
+LibCleanup (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  DeinitVariablePolicyLib ();
+}
+
+/// === TEST CASES =================================================================================
+
+/// ===== SHIM SUITE ===========================================================
+
+/**
+  Test Case that locks a single variable using the Variable Lock Protocol.
+  The call is expected to succeed.
+
+  @param[in]  Context  Unit test case context
+**/
+UNIT_TEST_STATUS
+EFIAPI
+LockingWithoutAnyPoliciesShouldSucceed (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Test Case that locks the same variable twice using the Variable Lock Protocol.
+  Both calls are expected to succeed.
+
+  @param[in]  Context  Unit test case context
+  **/
+UNIT_TEST_STATUS
+EFIAPI
+LockingTwiceShouldSucceed (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Test Case that locks a variable using the Variable Policy Protocol then locks
+  the same variable using the Variable Lock Protocol.
+  Both calls are expected to succeed.
+
+  @param[in]  Context  Unit test case context
+  **/
+UNIT_TEST_STATUS
+EFIAPI
+LockingALockedVariableShouldSucceed (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewEntry;
+
+  //
+  // Create a variable policy that locks the variable.
+  //
+  Status = CreateBasicVariablePolicy (
+             &mTestGuid1,
+             TEST_VAR_1_NAME,
+             TEST_POLICY_MIN_SIZE_NULL,
+             TEST_POLICY_MAX_SIZE_200,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             VARIABLE_POLICY_TYPE_LOCK_NOW,
+             &NewEntry
+             );
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  //
+  // Register the new policy.
+  //
+  Status = RegisterVariablePolicy (NewEntry);
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  FreePool (NewEntry);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Test Case that locks a variable using the Variable Policy Protocol with a
+  policy other than LOCK_NOW then attempts to lock the same variable using the
+  Variable Lock Protocol.  The call to Variable Policy is expected to succeed
+  and the call to Variable Lock is expected to fail.
+
+  @param[in]  Context  Unit test case context
+  **/
+UNIT_TEST_STATUS
+EFIAPI
+LockingAnUnlockedVariableShouldFail (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewEntry;
+
+  // Create a variable policy that locks the variable.
+  Status = CreateVarStateVariablePolicy (
+             &mTestGuid1,
+             TEST_VAR_1_NAME,
+             TEST_POLICY_MIN_SIZE_NULL,
+             TEST_POLICY_MAX_SIZE_200,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             &mTestGuid2,
+             1,
+             TEST_VAR_2_NAME,
+             &NewEntry
+             );
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  // Register the new policy.
+  Status = RegisterVariablePolicy (NewEntry);
+
+  // Configure the stub to not care about parameters. We're testing errors.
+  expect_any_always (StubGetVariableNull, VariableName);
+  expect_any_always (StubGetVariableNull, VendorGuid);
+  expect_any_always (StubGetVariableNull, DataSize);
+
+  // With a policy, make sure that writes still work, since the variable doesn't exist.
+  will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL);     // Attributes
+  will_return (StubGetVariableNull, 0);                               // Size
+  will_return (StubGetVariableNull, (UINTN)NULL);                     // DataPtr
+  will_return (StubGetVariableNull, EFI_NOT_FOUND);                   // Status
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_TRUE (EFI_ERROR (Status));
+
+  FreePool (NewEntry);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Test Case that locks a variable using the Variable Policy Protocol with a
+  policy other than LOCK_NOW, but is currently locked.  Then attempts to lock
+  the same variable using the Variable Lock Protocol.  The call to Variable
+  Policy is expected to succeed and the call to Variable Lock also expected to
+  succeed.
+
+  @param[in]  Context  Unit test case context
+  **/
+UNIT_TEST_STATUS
+EFIAPI
+LockingALockedVariableWithMatchingDataShouldSucceed (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewEntry;
+  UINT8                  Data;
+
+  // Create a variable policy that locks the variable.
+  Status = CreateVarStateVariablePolicy (
+             &mTestGuid1,
+             TEST_VAR_1_NAME,
+             TEST_POLICY_MIN_SIZE_NULL,
+             TEST_POLICY_MAX_SIZE_200,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             &mTestGuid2,
+             1,
+             TEST_VAR_2_NAME,
+             &NewEntry
+             );
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  // Register the new policy.
+  Status = RegisterVariablePolicy (NewEntry);
+
+  // Configure the stub to not care about parameters. We're testing errors.
+  expect_any_always (StubGetVariableNull, VariableName);
+  expect_any_always (StubGetVariableNull, VendorGuid);
+  expect_any_always (StubGetVariableNull, DataSize);
+
+  // With a policy, make sure that writes still work, since the variable doesn't exist.
+  Data = 1;
+  will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL);     // Attributes
+  will_return (StubGetVariableNull, sizeof (Data));                   // Size
+  will_return (StubGetVariableNull, (UINTN)&Data);                    // DataPtr
+  will_return (StubGetVariableNull, EFI_SUCCESS);                     // Status
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_TRUE (!EFI_ERROR (Status));
+
+  FreePool (NewEntry);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Test Case that locks a variable using the Variable Policy Protocol with a
+  policy other than LOCK_NOW, but variable data does not match.  Then attempts
+  to lock the same variable using the Variable Lock Protocol.  The call to
+  Variable Policy is expected to succeed and the call to Variable Lock is
+  expected to fail.
+
+  @param[in]  Context  Unit test case context
+  **/
+UNIT_TEST_STATUS
+EFIAPI
+LockingALockedVariableWithNonMatchingDataShouldFail (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewEntry;
+  UINT8                  Data;
+
+  // Create a variable policy that locks the variable.
+  Status = CreateVarStateVariablePolicy (
+             &mTestGuid1,
+             TEST_VAR_1_NAME,
+             TEST_POLICY_MIN_SIZE_NULL,
+             TEST_POLICY_MAX_SIZE_200,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             &mTestGuid2,
+             1,
+             TEST_VAR_2_NAME,
+             &NewEntry
+             );
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  // Register the new policy.
+  Status = RegisterVariablePolicy (NewEntry);
+
+  // Configure the stub to not care about parameters. We're testing errors.
+  expect_any_always (StubGetVariableNull, VariableName);
+  expect_any_always (StubGetVariableNull, VendorGuid);
+  expect_any_always (StubGetVariableNull, DataSize);
+
+  // With a policy, make sure that writes still work, since the variable doesn't exist.
+  Data = 2;
+  will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL);     // Attributes
+  will_return (StubGetVariableNull, sizeof (Data));                   // Size
+  will_return (StubGetVariableNull, (UINTN)&Data);                    // DataPtr
+  will_return (StubGetVariableNull, EFI_SUCCESS);                     // Status
+
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_TRUE (EFI_ERROR (Status));
+
+  FreePool (NewEntry);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Test Case that locks a variable using Variable Lock Protocol Policy Protocol
+  then and then attempts to lock the same variable using the Variable Policy
+  Protocol.  The call to Variable Lock is expected to succeed and the call to
+  Variable Policy is expected to fail.
+
+  @param[in]  Context  Unit test case context
+  **/
+UNIT_TEST_STATUS
+EFIAPI
+SettingPolicyForALockedVariableShouldFail (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewEntry;
+
+  // Lock the variable.
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  // Create a variable policy that locks the variable.
+  Status = CreateVarStateVariablePolicy (
+             &mTestGuid1,
+             TEST_VAR_1_NAME,
+             TEST_POLICY_MIN_SIZE_NULL,
+             TEST_POLICY_MAX_SIZE_200,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             TEST_POLICY_ATTRIBUTES_NULL,
+             &mTestGuid2,
+             1,
+             TEST_VAR_2_NAME,
+             &NewEntry
+             );
+  UT_ASSERT_NOT_EFI_ERROR (Status);
+
+  // Register the new policy.
+  Status = RegisterVariablePolicy (NewEntry);
+  UT_ASSERT_TRUE (EFI_ERROR (Status));
+
+  FreePool (NewEntry);
+
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Main entry point to this unit test application.
+
+  Sets up and runs the test suites.
+**/
+VOID
+EFIAPI
+UnitTestMain (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  UNIT_TEST_FRAMEWORK_HANDLE  Framework;
+  UNIT_TEST_SUITE_HANDLE      ShimTests;
+
+  Framework = NULL;
+
+  DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));
+
+  //
+  // Start setting up the test framework for running the tests.
+  //
+  Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
+    goto EXIT;
+  }
+
+  //
+  // Add all test suites and tests.
+  //
+  Status = CreateUnitTestSuite (
+             &ShimTests,
+             Framework,
+             "Variable Lock Shim Tests",
+             "VarPolicy.VarLockShim",
+             NULL,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ShimTests\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto EXIT;
+  }
+
+  AddTestCase (
+    ShimTests,
+    "Locking a variable with no matching policies should always work",
+    "EmptyPolicies",
+    LockingWithoutAnyPoliciesShouldSucceed,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+  AddTestCase (
+    ShimTests,
+    "Locking a variable twice should always work",
+    "DoubleLock",
+    LockingTwiceShouldSucceed,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+  AddTestCase (
+    ShimTests,
+    "Locking a variable that's already locked by another policy should work",
+    "LockAfterPolicy",
+    LockingALockedVariableShouldSucceed,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+  AddTestCase (
+    ShimTests,
+    "Locking a variable that already has an unlocked policy should fail",
+    "LockAfterUnlockedPolicy",
+    LockingAnUnlockedVariableShouldFail,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+  AddTestCase (
+    ShimTests,
+    "Locking a variable that already has an locked policy should succeed",
+    "LockAfterLockedPolicyMatchingData",
+    LockingALockedVariableWithMatchingDataShouldSucceed,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+  AddTestCase (
+    ShimTests,
+    "Locking a variable that already has an locked policy with matching data should succeed",
+    "LockAfterLockedPolicyNonMatchingData",
+    LockingALockedVariableWithNonMatchingDataShouldFail,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+  AddTestCase (
+    ShimTests,
+    "Adding a policy for a variable that has previously been locked should always fail",
+    "SetPolicyAfterLock",
+    SettingPolicyForALockedVariableShouldFail,
+    LibInitMocked,
+    LibCleanup,
+    NULL
+    );
+
+  //
+  // Execute the tests.
+  //
+  Status = RunAllTestSuites (Framework);
+
+EXIT:
+  if (Framework != NULL) {
+    FreeUnitTestFramework (Framework);
+  }
+
+  return;
+}
+
+///
+/// Avoid ECC error for function name that starts with lower case letter
+///
+#define Main  main
+
+/**
+  Standard POSIX C entry point for host based unit test execution.
+
+  @param[in] Argc  Number of arguments
+  @param[in] Argv  Array of pointers to arguments
+
+  @retval 0      Success
+  @retval other  Error
+**/
+INT32
+Main (
+  IN INT32  Argc,
+  IN CHAR8  *Argv[]
+  )
+{
+  UnitTestMain ();
+  return 0;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierDxe.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierDxe.c
new file mode 100644
index 000000000000..b219ea9ec074
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierDxe.c
@@ -0,0 +1,27 @@
+/** @file
+  Barrier to stop speculative execution (DXE version).
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+  This service is consumed by the variable modules to place a barrier to stop
+  speculative execution.
+
+  Ensures that no later instruction will execute speculatively, until all prior
+  instructions have completed.
+
+**/
+VOID
+VariableSpeculationBarrier (
+  VOID
+  )
+{
+  //
+  // Do nothing.
+  //
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierSmm.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierSmm.c
new file mode 100644
index 000000000000..7107c042928e
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierSmm.c
@@ -0,0 +1,26 @@
+/** @file
+  Barrier to stop speculative execution (SMM version).
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include "Variable.h"
+
+/**
+  This service is consumed by the variable modules to place a barrier to stop
+  speculative execution.
+
+  Ensures that no later instruction will execute speculatively, until all prior
+  instructions have completed.
+
+**/
+VOID
+VariableSpeculationBarrier (
+  VOID
+  )
+{
+  SpeculationBarrier ();
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c
new file mode 100644
index 000000000000..88984c31ab4f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c
@@ -0,0 +1,153 @@
+/** @file
+  TCG MOR (Memory Overwrite Request) Lock Control support (DXE version).
+
+  This module clears MemoryOverwriteRequestControlLock variable to indicate
+  MOR lock control unsupported.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "Variable.h"
+
+#include <Protocol/VariablePolicy.h>
+#include <Library/VariablePolicyHelperLib.h>
+
+/**
+  This service is an MOR/MorLock checker handler for the SetVariable().
+
+  @param[in]  VariableName the name of the vendor's variable, as a
+                           Null-Terminated Unicode String
+  @param[in]  VendorGuid   Unify identifier for vendor.
+  @param[in]  Attributes   Attributes bitmask to set for the variable.
+  @param[in]  DataSize     The size in bytes of Data-Buffer.
+  @param[in]  Data         Point to the content of the variable.
+
+  @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable
+                                  driver can store the variable data.
+  @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or
+                                  attributes is not allowed for MOR variable.
+  @retval  EFI_ACCESS_DENIED      The MOR/MorLock is locked.
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this
+                                  function. Variable driver can just return
+                                  EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  //
+  // Just let it pass. No need provide protection for DXE version.
+  //
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialization for MOR Control Lock.
+
+  @retval EFI_SUCCESS     MorLock initialization success.
+  @return Others          Some error occurs.
+**/
+EFI_STATUS
+MorLockInit (
+  VOID
+  )
+{
+  //
+  // Always clear variable to report unsupported to OS.
+  // The reason is that the DXE version is not proper to provide *protection*.
+  // BIOS should use SMM version variable driver to provide such capability.
+  //
+  VariableServiceSetVariable (
+    MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+    &gEfiMemoryOverwriteRequestControlLockGuid,
+    0,                                          // Attributes
+    0,                                          // DataSize
+    NULL                                        // Data
+    );
+
+  //
+  // The MOR variable can effectively improve platform security only when the
+  // MorLock variable protects the MOR variable. In turn MorLock cannot be made
+  // secure without SMM support in the platform firmware (see above).
+  //
+  // Thus, delete the MOR variable, should it exist for any reason (some OSes
+  // are known to create MOR unintentionally, in an attempt to set it), then
+  // also lock the MOR variable, in order to prevent other modules from
+  // creating it.
+  //
+  VariableServiceSetVariable (
+    MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+    &gEfiMemoryOverwriteControlDataGuid,
+    0,                                      // Attributes
+    0,                                      // DataSize
+    NULL                                    // Data
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Delayed initialization for MOR Control Lock at EndOfDxe.
+
+  This function performs any operations queued by MorLockInit().
+**/
+VOID
+MorLockInitAtEndOfDxe (
+  VOID
+  )
+{
+  EFI_STATUS                      Status;
+  EDKII_VARIABLE_POLICY_PROTOCOL  *VariablePolicy;
+
+  // First, we obviously need to locate the VariablePolicy protocol.
+  Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Could not locate VariablePolicy protocol! %r\n", __FUNCTION__, Status));
+    return;
+  }
+
+  // If we're successful, go ahead and set the policies to protect the target variables.
+  Status = RegisterBasicVariablePolicy (
+             VariablePolicy,
+             &gEfiMemoryOverwriteRequestControlLockGuid,
+             MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+             VARIABLE_POLICY_NO_MIN_SIZE,
+             VARIABLE_POLICY_NO_MAX_SIZE,
+             VARIABLE_POLICY_NO_MUST_ATTR,
+             VARIABLE_POLICY_NO_CANT_ATTR,
+             VARIABLE_POLICY_TYPE_LOCK_NOW
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Could not lock variable %s! %r\n", __FUNCTION__, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, Status));
+  }
+
+  Status = RegisterBasicVariablePolicy (
+             VariablePolicy,
+             &gEfiMemoryOverwriteControlDataGuid,
+             MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+             VARIABLE_POLICY_NO_MIN_SIZE,
+             VARIABLE_POLICY_NO_MAX_SIZE,
+             VARIABLE_POLICY_NO_MUST_ATTR,
+             VARIABLE_POLICY_NO_CANT_ATTR,
+             VARIABLE_POLICY_TYPE_LOCK_NOW
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Could not lock variable %s! %r\n", __FUNCTION__, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, Status));
+  }
+
+  return;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm.c
new file mode 100644
index 000000000000..296afd2ec414
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm.c
@@ -0,0 +1,569 @@
+/** @file
+  TCG MOR (Memory Overwrite Request) Lock Control support (SMM version).
+
+  This module initilizes MemoryOverwriteRequestControlLock variable.
+  This module adds Variable Hook and check MemoryOverwriteRequestControlLock.
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "Variable.h"
+
+#include <Protocol/VariablePolicy.h>
+#include <Library/VariablePolicyHelperLib.h>
+#include <Library/VariablePolicyLib.h>
+
+typedef struct {
+  CHAR16      *VariableName;
+  EFI_GUID    *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE  mMorVariableType[] = {
+  { MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,     &gEfiMemoryOverwriteControlDataGuid        },
+  { MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid },
+};
+
+BOOLEAN  mMorPassThru = FALSE;
+
+#define MOR_LOCK_DATA_UNLOCKED            0x0
+#define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY  0x1
+#define MOR_LOCK_DATA_LOCKED_WITH_KEY     0x2
+
+#define MOR_LOCK_V1_SIZE      1
+#define MOR_LOCK_V2_KEY_SIZE  8
+
+typedef enum {
+  MorLockStateUnlocked = 0,
+  MorLockStateLocked   = 1,
+} MOR_LOCK_STATE;
+
+BOOLEAN         mMorLockInitializationRequired = FALSE;
+UINT8           mMorLockKey[MOR_LOCK_V2_KEY_SIZE];
+BOOLEAN         mMorLockKeyEmpty = TRUE;
+BOOLEAN         mMorLockPassThru = FALSE;
+MOR_LOCK_STATE  mMorLockState    = MorLockStateUnlocked;
+
+/**
+  Returns if this is MOR related variable.
+
+  @param  VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+  @param  VendorGuid   Unify identifier for vendor.
+
+  @retval  TRUE            The variable is MOR related.
+  @retval  FALSE           The variable is NOT MOR related.
+**/
+BOOLEAN
+IsAnyMorVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < sizeof (mMorVariableType)/sizeof (mMorVariableType[0]); Index++) {
+    if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&
+        (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid)))
+    {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Returns if this is MOR lock variable.
+
+  @param  VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+  @param  VendorGuid   Unify identifier for vendor.
+
+  @retval  TRUE            The variable is MOR lock variable.
+  @retval  FALSE           The variable is NOT MOR lock variable.
+**/
+BOOLEAN
+IsMorLockVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  )
+{
+  if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&
+      (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid)))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Set MOR lock variable.
+
+  @param  Data         MOR Lock variable data.
+
+  @retval  EFI_SUCCESS            The firmware has successfully stored the variable and its data as
+                                  defined by the Attributes.
+  @retval  EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the
+                                  DataSize exceeds the maximum allowed.
+  @retval  EFI_INVALID_PARAMETER  VariableName is an empty Unicode string.
+  @retval  EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
+  @retval  EFI_DEVICE_ERROR       The variable could not be saved due to a hardware failure.
+  @retval  EFI_WRITE_PROTECTED    The variable in question is read-only.
+  @retval  EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
+  @retval  EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+                                  set but the AuthInfo does NOT pass the validation check carried
+                                  out by the firmware.
+  @retval  EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+SetMorLockVariable (
+  IN UINT8  Data
+  )
+{
+  EFI_STATUS  Status;
+
+  mMorLockPassThru = TRUE;
+  Status           = VariableServiceSetVariable (
+                       MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+                       &gEfiMemoryOverwriteRequestControlLockGuid,
+                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                       sizeof (Data),
+                       &Data
+                       );
+  mMorLockPassThru = FALSE;
+  return Status;
+}
+
+/**
+  This service is an MorLock checker handler for the SetVariable().
+
+  @param  VariableName the name of the vendor's variable, as a
+                       Null-Terminated Unicode String
+  @param  VendorGuid   Unify identifier for vendor.
+  @param  Attributes   Point to memory location to return the attributes of variable. If the point
+                       is NULL, the parameter would be ignored.
+  @param  DataSize     The size in bytes of Data-Buffer.
+  @param  Data         Point to the content of the variable.
+
+  @retval  EFI_SUCCESS            The MorLock check pass, and Variable driver can store the variable data.
+  @retval  EFI_INVALID_PARAMETER  The MorLock data or data size or attributes is not allowed.
+  @retval  EFI_ACCESS_DENIED      The MorLock is locked.
+  @retval  EFI_WRITE_PROTECTED    The MorLock deletion is not allowed.
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this function.
+                                  Variable driver can just return EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMorLock (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Basic Check
+  //
+  if ((Attributes == 0) || (DataSize == 0) || (Data == NULL)) {
+    //
+    // Permit deletion for passthru request, deny it otherwise.
+    //
+    return mMorLockPassThru ? EFI_SUCCESS : EFI_WRITE_PROTECTED;
+  }
+
+  if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+      ((DataSize != MOR_LOCK_V1_SIZE) && (DataSize != MOR_LOCK_V2_KEY_SIZE)))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Do not check if the request is passthru.
+  //
+  if (mMorLockPassThru) {
+    return EFI_SUCCESS;
+  }
+
+  if (mMorLockState == MorLockStateUnlocked) {
+    //
+    // In Unlocked State
+    //
+    if (DataSize == MOR_LOCK_V1_SIZE) {
+      //
+      // V1 - lock permanently
+      //
+      if (*(UINT8 *)Data == MOR_LOCK_DATA_UNLOCKED) {
+        //
+        // Unlock
+        //
+        Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
+        if (!EFI_ERROR (Status)) {
+          //
+          // return EFI_ALREADY_STARTED to skip variable set.
+          //
+          return EFI_ALREADY_STARTED;
+        } else {
+          //
+          // SetVar fail
+          //
+          return Status;
+        }
+      } else if (*(UINT8 *)Data == MOR_LOCK_DATA_LOCKED_WITHOUT_KEY) {
+        //
+        // Lock without key
+        //
+        Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY);
+        if (!EFI_ERROR (Status)) {
+          //
+          // Lock success
+          //
+          mMorLockState = MorLockStateLocked;
+          //
+          // return EFI_ALREADY_STARTED to skip variable set.
+          //
+          return EFI_ALREADY_STARTED;
+        } else {
+          //
+          // SetVar fail
+          //
+          return Status;
+        }
+      } else {
+        return EFI_INVALID_PARAMETER;
+      }
+    } else if (DataSize == MOR_LOCK_V2_KEY_SIZE) {
+      //
+      // V2 lock and provision the key
+      //
+
+      //
+      // Need set here because the data value on flash is different
+      //
+      Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY);
+      if (EFI_ERROR (Status)) {
+        //
+        // SetVar fail, do not provision the key
+        //
+        return Status;
+      } else {
+        //
+        // Lock success, provision the key
+        //
+        mMorLockKeyEmpty = FALSE;
+        CopyMem (mMorLockKey, Data, MOR_LOCK_V2_KEY_SIZE);
+        mMorLockState = MorLockStateLocked;
+        //
+        // return EFI_ALREADY_STARTED to skip variable set.
+        //
+        return EFI_ALREADY_STARTED;
+      }
+    } else {
+      ASSERT (FALSE);
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // In Locked State
+    //
+    if (mMorLockKeyEmpty || (DataSize != MOR_LOCK_V2_KEY_SIZE)) {
+      return EFI_ACCESS_DENIED;
+    }
+
+    if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) == 0)) {
+      //
+      // Key match - unlock
+      //
+
+      //
+      // Need set here because the data value on flash is different
+      //
+      Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
+      if (EFI_ERROR (Status)) {
+        //
+        // SetVar fail
+        //
+        return Status;
+      } else {
+        //
+        // Unlock Success
+        //
+        mMorLockState    = MorLockStateUnlocked;
+        mMorLockKeyEmpty = TRUE;
+        ZeroMem (mMorLockKey, sizeof (mMorLockKey));
+        //
+        // return EFI_ALREADY_STARTED to skip variable set.
+        //
+        return EFI_ALREADY_STARTED;
+      }
+    } else {
+      //
+      // Key mismatch - Prevent Dictionary Attack
+      //
+      mMorLockState    = MorLockStateLocked;
+      mMorLockKeyEmpty = TRUE;
+      ZeroMem (mMorLockKey, sizeof (mMorLockKey));
+      return EFI_ACCESS_DENIED;
+    }
+  }
+}
+
+/**
+  This service is an MOR/MorLock checker handler for the SetVariable().
+
+  @param[in]  VariableName the name of the vendor's variable, as a
+                           Null-Terminated Unicode String
+  @param[in]  VendorGuid   Unify identifier for vendor.
+  @param[in]  Attributes   Attributes bitmask to set for the variable.
+  @param[in]  DataSize     The size in bytes of Data-Buffer.
+  @param[in]  Data         Point to the content of the variable.
+
+  @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable
+                                  driver can store the variable data.
+  @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or
+                                  attributes is not allowed for MOR variable.
+  @retval  EFI_ACCESS_DENIED      The MOR/MorLock is locked.
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this
+                                  function. Variable driver can just return
+                                  EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  //
+  // do not handle non-MOR variable
+  //
+  if (!IsAnyMorVariable (VariableName, VendorGuid)) {
+    return EFI_SUCCESS;
+  }
+
+  // Permit deletion when policy is disabled.
+  if (!IsVariablePolicyEnabled () && ((Attributes == 0) || (DataSize == 0))) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // MorLock variable
+  //
+  if (IsMorLockVariable (VariableName, VendorGuid)) {
+    return SetVariableCheckHandlerMorLock (
+             VariableName,
+             VendorGuid,
+             Attributes,
+             DataSize,
+             Data
+             );
+  }
+
+  //
+  // Mor Variable
+  //
+
+  //
+  // Permit deletion for passthru request.
+  //
+  if (((Attributes == 0) || (DataSize == 0)) && mMorPassThru) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Basic Check
+  //
+  if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+      (DataSize != sizeof (UINT8)) ||
+      (Data == NULL))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (mMorLockState == MorLockStateLocked) {
+    //
+    // If lock, deny access
+    //
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // grant access
+  //
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialization for MOR Control Lock.
+
+  @retval EFI_SUCCESS     MorLock initialization success.
+  @return Others          Some error occurs.
+**/
+EFI_STATUS
+MorLockInit (
+  VOID
+  )
+{
+  mMorLockInitializationRequired = TRUE;
+  return EFI_SUCCESS;
+}
+
+/**
+  Delayed initialization for MOR Control Lock at EndOfDxe.
+
+  This function performs any operations queued by MorLockInit().
+**/
+VOID
+MorLockInitAtEndOfDxe (
+  VOID
+  )
+{
+  UINTN                  MorSize;
+  EFI_STATUS             MorStatus;
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewPolicy;
+
+  if (!mMorLockInitializationRequired) {
+    //
+    // The EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL has never been installed, thus
+    // the variable write service is unavailable. This should never happen.
+    //
+    ASSERT (FALSE);
+    return;
+  }
+
+  //
+  // Check if the MOR variable exists.
+  //
+  MorSize   = 0;
+  MorStatus = VariableServiceGetVariable (
+                MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+                &gEfiMemoryOverwriteControlDataGuid,
+                NULL,                                   // Attributes
+                &MorSize,
+                NULL                                    // Data
+                );
+  //
+  // We provided a zero-sized buffer, so the above call can never succeed.
+  //
+  ASSERT (EFI_ERROR (MorStatus));
+
+  if (MorStatus == EFI_BUFFER_TOO_SMALL) {
+    //
+    // The MOR variable exists.
+    //
+    // Some OSes don't follow the TCG's Platform Reset Attack Mitigation spec
+    // in that the OS should never create the MOR variable, only read and write
+    // it -- these OSes (unintentionally) create MOR if the platform firmware
+    // does not produce it. Whether this is the case (from the last OS boot)
+    // can be deduced from the absence of the TCG / TCG2 protocols, as edk2's
+    // MOR implementation depends on (one of) those protocols.
+    //
+    if (VariableHaveTcgProtocols ()) {
+      //
+      // The MOR variable originates from the platform firmware; set the MOR
+      // Control Lock variable to report the locking capability to the OS.
+      //
+      SetMorLockVariable (0);
+      return;
+    }
+
+    //
+    // The MOR variable's origin is inexplicable; delete it.
+    //
+    DEBUG ((
+      DEBUG_WARN,
+      "%a: deleting unexpected / unsupported variable %g:%s\n",
+      __FUNCTION__,
+      &gEfiMemoryOverwriteControlDataGuid,
+      MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
+      ));
+
+    mMorPassThru = TRUE;
+    VariableServiceSetVariable (
+      MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+      &gEfiMemoryOverwriteControlDataGuid,
+      0,                                      // Attributes
+      0,                                      // DataSize
+      NULL                                    // Data
+      );
+    mMorPassThru = FALSE;
+  }
+
+  //
+  // The MOR variable is absent; the platform firmware does not support it.
+  // Lock the variable so that no other module may create it.
+  //
+  NewPolicy = NULL;
+  Status    = CreateBasicVariablePolicy (
+                &gEfiMemoryOverwriteControlDataGuid,
+                MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+                VARIABLE_POLICY_NO_MIN_SIZE,
+                VARIABLE_POLICY_NO_MAX_SIZE,
+                VARIABLE_POLICY_NO_MUST_ATTR,
+                VARIABLE_POLICY_NO_CANT_ATTR,
+                VARIABLE_POLICY_TYPE_LOCK_NOW,
+                &NewPolicy
+                );
+  if (!EFI_ERROR (Status)) {
+    Status = RegisterVariablePolicy (NewPolicy);
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", __FUNCTION__, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, Status));
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (NewPolicy != NULL) {
+    FreePool (NewPolicy);
+  }
+
+  //
+  // Delete the MOR Control Lock variable too (should it exists for some
+  // reason) and prevent other modules from creating it.
+  //
+  mMorLockPassThru = TRUE;
+  VariableServiceSetVariable (
+    MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+    &gEfiMemoryOverwriteRequestControlLockGuid,
+    0,                                          // Attributes
+    0,                                          // DataSize
+    NULL                                        // Data
+    );
+  mMorLockPassThru = FALSE;
+
+  NewPolicy = NULL;
+  Status    = CreateBasicVariablePolicy (
+                &gEfiMemoryOverwriteRequestControlLockGuid,
+                MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+                VARIABLE_POLICY_NO_MIN_SIZE,
+                VARIABLE_POLICY_NO_MAX_SIZE,
+                VARIABLE_POLICY_NO_MUST_ATTR,
+                VARIABLE_POLICY_NO_CANT_ATTR,
+                VARIABLE_POLICY_TYPE_LOCK_NOW,
+                &NewPolicy
+                );
+  if (!EFI_ERROR (Status)) {
+    Status = RegisterVariablePolicy (NewPolicy);
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", __FUNCTION__, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, Status));
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (NewPolicy != NULL) {
+    FreePool (NewPolicy);
+  }
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c
new file mode 100644
index 000000000000..a94b0b02ec15
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c
@@ -0,0 +1,101 @@
+/** @file
+  Implementation functions and structures for var check protocol
+  and variable lock protocol based on VarCheckLib.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+  Register SetVariable check handler.
+
+  @param[in] Handler            Pointer to check handler.
+
+  @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
+  @retval EFI_INVALID_PARAMETER Handler is NULL.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
+  @retval EFI_UNSUPPORTED       This interface is not implemented.
+                                For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+  IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER  Handler
+  )
+{
+  EFI_STATUS  Status;
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+  Status = VarCheckLibRegisterSetVariableCheckHandler (Handler);
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  return Status;
+}
+
+/**
+  Variable property set.
+
+  @param[in] Name               Pointer to the variable name.
+  @param[in] Guid               Pointer to the vendor GUID.
+  @param[in] VariableProperty   Pointer to the input variable property.
+
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+                                or the fields of VariableProperty are not valid.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+  IN CHAR16                       *Name,
+  IN EFI_GUID                     *Guid,
+  IN VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty
+  )
+{
+  EFI_STATUS  Status;
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+  Status = VarCheckLibVariablePropertySet (Name, Guid, VariableProperty);
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  return Status;
+}
+
+/**
+  Variable property get.
+
+  @param[in]  Name              Pointer to the variable name.
+  @param[in]  Guid              Pointer to the vendor GUID.
+  @param[out] VariableProperty  Pointer to the output variable property.
+
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+  @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+  IN CHAR16                        *Name,
+  IN EFI_GUID                      *Guid,
+  OUT VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty
+  )
+{
+  EFI_STATUS  Status;
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+  Status = VarCheckLibVariablePropertyGet (Name, Guid, VariableProperty);
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c
new file mode 100644
index 000000000000..19b432b772d7
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c
@@ -0,0 +1,4037 @@
+/** @file
+  The common variable operation routines shared by DXE_RUNTIME variable
+  module and DXE_SMM variable module.
+
+  Caution: This module requires additional review when modified.
+  This driver will have external input - variable data. They may be input in SMM mode.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
+  They need check input parameter.
+
+  VariableServiceGetVariable() and VariableServiceSetVariable() are external API
+  to receive datasize and data buffer. The size should be checked carefully.
+
+  VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
+  integer overflow. It should also check attribute to avoid authentication bypass.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
+Copyright (c) Microsoft Corporation.<BR>
+Copyright (c) 2022, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal = NULL;
+
+///
+/// Define a memory cache that improves the search performance for a variable.
+/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
+///
+VARIABLE_STORE_HEADER  *mNvVariableCache = NULL;
+
+///
+/// Memory cache of Fv Header.
+///
+EFI_FIRMWARE_VOLUME_HEADER  *mNvFvHeaderCache = NULL;
+
+///
+/// The memory entry used for variable statistics data.
+///
+VARIABLE_INFO_ENTRY  *gVariableInfo = NULL;
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN  mEndOfDxe = FALSE;
+
+///
+/// It indicates the var check request source.
+/// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
+///
+VAR_CHECK_REQUEST_SOURCE  mRequestSource = VarCheckFromUntrusted;
+
+//
+// It will record the current boot error flag before EndOfDxe.
+//
+VAR_ERROR_FLAG  mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;
+
+VARIABLE_ENTRY_PROPERTY  mVariableEntryProperty[] = {
+  {
+    &gEdkiiVarErrorFlagGuid,
+    VAR_ERROR_FLAG_NAME,
+    {
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+      VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+      VARIABLE_ATTRIBUTE_NV_BS_RT,
+      sizeof (VAR_ERROR_FLAG),
+      sizeof (VAR_ERROR_FLAG)
+    }
+  },
+};
+
+AUTH_VAR_LIB_CONTEXT_IN  mAuthContextIn = {
+  AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,
+  //
+  // StructSize, TO BE FILLED
+  //
+  0,
+  //
+  // MaxAuthVariableSize, TO BE FILLED
+  //
+  0,
+  VariableExLibFindVariable,
+  VariableExLibFindNextVariable,
+  VariableExLibUpdateVariable,
+  VariableExLibGetScratchBuffer,
+  VariableExLibCheckRemainingSpaceForConsistency,
+  VariableExLibAtRuntime,
+};
+
+AUTH_VAR_LIB_CONTEXT_OUT  mAuthContextOut;
+
+/**
+
+  This function writes data to the FWH at the correct LBA even if the LBAs
+  are fragmented.
+
+  @param Global                  Pointer to VARAIBLE_GLOBAL structure.
+  @param Volatile                Point out the Variable is Volatile or Non-Volatile.
+  @param SetByIndex              TRUE if target pointer is given as index.
+                                 FALSE if target pointer is absolute.
+  @param Fvb                     Pointer to the writable FVB protocol.
+  @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER
+                                 structure.
+  @param DataSize                Size of data to be written.
+  @param Buffer                  Pointer to the buffer from which data is written.
+
+  @retval EFI_INVALID_PARAMETER  Parameters not valid.
+  @retval EFI_UNSUPPORTED        Fvb is a NULL for Non-Volatile variable update.
+  @retval EFI_OUT_OF_RESOURCES   The remaining size is not enough.
+  @retval EFI_SUCCESS            Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+  IN  VARIABLE_GLOBAL                     *Global,
+  IN  BOOLEAN                             Volatile,
+  IN  BOOLEAN                             SetByIndex,
+  IN  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb,
+  IN  UINTN                               DataPtrIndex,
+  IN  UINT32                              DataSize,
+  IN  UINT8                               *Buffer
+  )
+{
+  EFI_FV_BLOCK_MAP_ENTRY  *PtrBlockMapEntry;
+  UINTN                   BlockIndex2;
+  UINTN                   LinearOffset;
+  UINTN                   CurrWriteSize;
+  UINTN                   CurrWritePtr;
+  UINT8                   *CurrBuffer;
+  EFI_LBA                 LbaNumber;
+  UINTN                   Size;
+  VARIABLE_STORE_HEADER   *VolatileBase;
+  EFI_PHYSICAL_ADDRESS    FvVolHdr;
+  EFI_PHYSICAL_ADDRESS    DataPtr;
+  EFI_STATUS              Status;
+
+  FvVolHdr = 0;
+  DataPtr  = DataPtrIndex;
+
+  //
+  // Check if the Data is Volatile.
+  //
+  if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
+    if (Fvb == NULL) {
+      return EFI_UNSUPPORTED;
+    }
+
+    Status = Fvb->GetPhysicalAddress (Fvb, &FvVolHdr);
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // Data Pointer should point to the actual Address where data is to be
+    // written.
+    //
+    if (SetByIndex) {
+      DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+    }
+
+    if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // Data Pointer should point to the actual Address where data is to be
+    // written.
+    //
+    if (Volatile) {
+      VolatileBase = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+      if (SetByIndex) {
+        DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+      }
+
+      if ((DataPtr + DataSize) > ((UINTN)VolatileBase + VolatileBase->Size)) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    } else {
+      //
+      // Emulated non-volatile variable mode.
+      //
+      if (SetByIndex) {
+        DataPtr += (UINTN)mNvVariableCache;
+      }
+
+      if ((DataPtr + DataSize) > ((UINTN)mNvVariableCache + mNvVariableCache->Size)) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+
+    //
+    // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
+    //
+    CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
+    return EFI_SUCCESS;
+  }
+
+  //
+  // If we are here we are dealing with Non-Volatile Variables.
+  //
+  LinearOffset  = (UINTN)FvVolHdr;
+  CurrWritePtr  = (UINTN)DataPtr;
+  CurrWriteSize = DataSize;
+  CurrBuffer    = Buffer;
+  LbaNumber     = 0;
+
+  if (CurrWritePtr < LinearOffset) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+    for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
+      //
+      // Check to see if the Variable Writes are spanning through multiple
+      // blocks.
+      //
+      if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
+        if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
+          Status = Fvb->Write (
+                          Fvb,
+                          LbaNumber,
+                          (UINTN)(CurrWritePtr - LinearOffset),
+                          &CurrWriteSize,
+                          CurrBuffer
+                          );
+          return Status;
+        } else {
+          Size   = (UINT32)(LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
+          Status = Fvb->Write (
+                          Fvb,
+                          LbaNumber,
+                          (UINTN)(CurrWritePtr - LinearOffset),
+                          &Size,
+                          CurrBuffer
+                          );
+          if (EFI_ERROR (Status)) {
+            return Status;
+          }
+
+          CurrWritePtr  = LinearOffset + PtrBlockMapEntry->Length;
+          CurrBuffer    = CurrBuffer + Size;
+          CurrWriteSize = CurrWriteSize - Size;
+        }
+      }
+
+      LinearOffset += PtrBlockMapEntry->Length;
+      LbaNumber++;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Record variable error flag.
+
+  @param[in] Flag               Variable error flag to record.
+  @param[in] VariableName       Name of variable.
+  @param[in] VendorGuid         Guid of variable.
+  @param[in] Attributes         Attributes of the variable.
+  @param[in] VariableSize       Size of the variable.
+
+**/
+VOID
+RecordVarErrorFlag (
+  IN VAR_ERROR_FLAG  Flag,
+  IN CHAR16          *VariableName,
+  IN EFI_GUID        *VendorGuid,
+  IN UINT32          Attributes,
+  IN UINTN           VariableSize
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_POINTER_TRACK  Variable;
+  VAR_ERROR_FLAG          *VarErrFlag;
+  VAR_ERROR_FLAG          TempFlag;
+
+  DEBUG_CODE_BEGIN ();
+  DEBUG ((DEBUG_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));
+  if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {
+    if (AtRuntime ()) {
+      DEBUG ((DEBUG_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
+    } else {
+      DEBUG ((DEBUG_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
+    }
+  } else {
+    DEBUG ((DEBUG_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));
+  }
+
+  DEBUG_CODE_END ();
+
+  if (!mEndOfDxe) {
+    //
+    // Before EndOfDxe, just record the current boot variable error flag to local variable,
+    // and leave the variable error flag in NV flash as the last boot variable error flag.
+    // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
+    // will be initialized to this local current boot variable error flag.
+    //
+    mCurrentBootVarErrFlag &= Flag;
+    return;
+  }
+
+  //
+  // Record error flag (it should have be initialized).
+  //
+  Status = FindVariable (
+             VAR_ERROR_FLAG_NAME,
+             &gEdkiiVarErrorFlagGuid,
+             &Variable,
+             &mVariableModuleGlobal->VariableGlobal,
+             FALSE
+             );
+  if (!EFI_ERROR (Status)) {
+    VarErrFlag = (VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    TempFlag   = *VarErrFlag;
+    TempFlag  &= Flag;
+    if (TempFlag == *VarErrFlag) {
+      return;
+    }
+
+    Status = UpdateVariableStore (
+               &mVariableModuleGlobal->VariableGlobal,
+               FALSE,
+               FALSE,
+               mVariableModuleGlobal->FvbInstance,
+               (UINTN)VarErrFlag - (UINTN)mNvVariableCache + (UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+               sizeof (TempFlag),
+               &TempFlag
+               );
+    if (!EFI_ERROR (Status)) {
+      //
+      // Update the data in NV cache.
+      //
+      *VarErrFlag = TempFlag;
+      Status      =  SynchronizeRuntimeVariableCache (
+                       &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,
+                       0,
+                       mNvVariableCache->Size
+                       );
+      ASSERT_EFI_ERROR (Status);
+    }
+  }
+}
+
+/**
+  Initialize variable error flag.
+
+  Before EndOfDxe, the variable indicates the last boot variable error flag,
+  then it means the last boot variable error flag must be got before EndOfDxe.
+  After EndOfDxe, the variable indicates the current boot variable error flag,
+  then it means the current boot variable error flag must be got after EndOfDxe.
+
+**/
+VOID
+InitializeVarErrorFlag (
+  VOID
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_POINTER_TRACK  Variable;
+  VAR_ERROR_FLAG          Flag;
+  VAR_ERROR_FLAG          VarErrFlag;
+
+  if (!mEndOfDxe) {
+    return;
+  }
+
+  Flag = mCurrentBootVarErrFlag;
+  DEBUG ((DEBUG_INFO, "Initialize variable error flag (%02x)\n", Flag));
+
+  Status = FindVariable (
+             VAR_ERROR_FLAG_NAME,
+             &gEdkiiVarErrorFlagGuid,
+             &Variable,
+             &mVariableModuleGlobal->VariableGlobal,
+             FALSE
+             );
+  if (!EFI_ERROR (Status)) {
+    VarErrFlag = *((VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat));
+    if (VarErrFlag == Flag) {
+      return;
+    }
+  }
+
+  UpdateVariable (
+    VAR_ERROR_FLAG_NAME,
+    &gEdkiiVarErrorFlagGuid,
+    &Flag,
+    sizeof (Flag),
+    VARIABLE_ATTRIBUTE_NV_BS_RT,
+    0,
+    0,
+    &Variable,
+    NULL
+    );
+}
+
+/**
+  Is user variable?
+
+  @param[in] Variable   Pointer to variable header.
+
+  @retval TRUE          User variable.
+  @retval FALSE         System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+  IN VARIABLE_HEADER  *Variable
+  )
+{
+  VAR_CHECK_VARIABLE_PROPERTY  Property;
+
+  //
+  // Only after End Of Dxe, the variables belong to system variable are fixed.
+  // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
+  // then no need to check if the variable is user variable or not specially.
+  //
+  if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
+    if (VarCheckLibVariablePropertyGet (
+          GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+          GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+          &Property
+          ) == EFI_NOT_FOUND)
+    {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Calculate common user variable total size.
+
+**/
+VOID
+CalculateCommonUserVariableTotalSize (
+  VOID
+  )
+{
+  VARIABLE_HEADER              *Variable;
+  VARIABLE_HEADER              *NextVariable;
+  UINTN                        VariableSize;
+  VAR_CHECK_VARIABLE_PROPERTY  Property;
+
+  //
+  // Only after End Of Dxe, the variables belong to system variable are fixed.
+  // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
+  // then no need to calculate the common user variable total size specially.
+  //
+  if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
+    Variable = GetStartPointer (mNvVariableCache);
+    while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache), mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
+      NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+      VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+      if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+        if (VarCheckLibVariablePropertyGet (
+              GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+              GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+              &Property
+              ) == EFI_NOT_FOUND)
+        {
+          //
+          // No property, it is user variable.
+          //
+          mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+        }
+      }
+
+      Variable = NextVariable;
+    }
+  }
+}
+
+/**
+  Initialize variable quota.
+
+**/
+VOID
+InitializeVariableQuota (
+  VOID
+  )
+{
+  if (!mEndOfDxe) {
+    return;
+  }
+
+  InitializeVarErrorFlag ();
+  CalculateCommonUserVariableTotalSize ();
+}
+
+/**
+  Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.
+  If VariableName is an empty string, then we just return the first
+  qualified variable without comparing VariableName and VendorGuid.
+  If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
+  at runtime when searching existing variable, only VariableName and VendorGuid are compared.
+  Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
+
+  @param[in]   VariableName           Name of the variable to be found.
+  @param[in]   VendorGuid             Vendor GUID to be found.
+  @param[out]  PtrTrack               VARIABLE_POINTER_TRACK structure for output,
+                                      including the range searched and the target position.
+  @param[in]   Global                 Pointer to VARIABLE_GLOBAL structure, including
+                                      base of volatile variable storage area, base of
+                                      NV variable storage area, and a lock.
+  @param[in]   IgnoreRtCheck          Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+                                      check at runtime when searching variable.
+
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while
+                                      VendorGuid is NULL.
+  @retval EFI_SUCCESS                 Variable successfully found.
+  @retval EFI_NOT_FOUND               Variable not found
+
+**/
+EFI_STATUS
+FindVariable (
+  IN  CHAR16                  *VariableName,
+  IN  EFI_GUID                *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
+  IN  VARIABLE_GLOBAL         *Global,
+  IN  BOOLEAN                 IgnoreRtCheck
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_STORE_HEADER  *VariableStoreHeader[VariableStoreTypeMax];
+  VARIABLE_STORE_TYPE    Type;
+
+  if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // 0: Volatile, 1: HOB, 2: Non-Volatile.
+  // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
+  // make use of this mapping to implement search algorithm.
+  //
+  VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)Global->VolatileVariableBase;
+  VariableStoreHeader[VariableStoreTypeHob]      = (VARIABLE_STORE_HEADER *)(UINTN)Global->HobVariableBase;
+  VariableStoreHeader[VariableStoreTypeNv]       = mNvVariableCache;
+
+  //
+  // Find the variable by walk through HOB, volatile and non-volatile variable store.
+  //
+  for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+    if (VariableStoreHeader[Type] == NULL) {
+      continue;
+    }
+
+    PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+    PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader[Type]);
+    PtrTrack->Volatile = (BOOLEAN)(Type == VariableStoreTypeVolatile);
+
+    Status =  FindVariableEx (
+                VariableName,
+                VendorGuid,
+                IgnoreRtCheck,
+                PtrTrack,
+                mVariableModuleGlobal->VariableGlobal.AuthFormat
+                );
+    if (!EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get index from supported language codes according to language string.
+
+  This code is used to get corresponding index in supported language codes. It can handle
+  RFC4646 and ISO639 language tags.
+  In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
+  In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
+
+  For example:
+    SupportedLang  = "engfraengfra"
+    Lang           = "eng"
+    Iso639Language = TRUE
+  The return value is "0".
+  Another example:
+    SupportedLang  = "en;fr;en-US;fr-FR"
+    Lang           = "fr-FR"
+    Iso639Language = FALSE
+  The return value is "3".
+
+  @param  SupportedLang               Platform supported language codes.
+  @param  Lang                        Configured language.
+  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+  @retval The index of language in the language codes.
+
+**/
+UINTN
+GetIndexFromSupportedLangCodes (
+  IN  CHAR8    *SupportedLang,
+  IN  CHAR8    *Lang,
+  IN  BOOLEAN  Iso639Language
+  )
+{
+  UINTN  Index;
+  UINTN  CompareLength;
+  UINTN  LanguageLength;
+
+  if (Iso639Language) {
+    CompareLength = ISO_639_2_ENTRY_SIZE;
+    for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
+      if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
+        //
+        // Successfully find the index of Lang string in SupportedLang string.
+        //
+        Index = Index / CompareLength;
+        return Index;
+      }
+    }
+
+    ASSERT (FALSE);
+    return 0;
+  } else {
+    //
+    // Compare RFC4646 language code
+    //
+    Index = 0;
+    for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++) {
+    }
+
+    for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
+      //
+      // Skip ';' characters in SupportedLang
+      //
+      for ( ; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++) {
+      }
+
+      //
+      // Determine the length of the next language code in SupportedLang
+      //
+      for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++) {
+      }
+
+      if ((CompareLength == LanguageLength) &&
+          (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0))
+      {
+        //
+        // Successfully find the index of Lang string in SupportedLang string.
+        //
+        return Index;
+      }
+    }
+
+    ASSERT (FALSE);
+    return 0;
+  }
+}
+
+/**
+  Get language string from supported language codes according to index.
+
+  This code is used to get corresponding language strings in supported language codes. It can handle
+  RFC4646 and ISO639 language tags.
+  In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
+  In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
+
+  For example:
+    SupportedLang  = "engfraengfra"
+    Index          = "1"
+    Iso639Language = TRUE
+  The return value is "fra".
+  Another example:
+    SupportedLang  = "en;fr;en-US;fr-FR"
+    Index          = "1"
+    Iso639Language = FALSE
+  The return value is "fr".
+
+  @param  SupportedLang               Platform supported language codes.
+  @param  Index                       The index in supported language codes.
+  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+  @retval The language string in the language codes.
+
+**/
+CHAR8 *
+GetLangFromSupportedLangCodes (
+  IN  CHAR8    *SupportedLang,
+  IN  UINTN    Index,
+  IN  BOOLEAN  Iso639Language
+  )
+{
+  UINTN  SubIndex;
+  UINTN  CompareLength;
+  CHAR8  *Supported;
+
+  SubIndex  = 0;
+  Supported = SupportedLang;
+  if (Iso639Language) {
+    //
+    // According to the index of Lang string in SupportedLang string to get the language.
+    // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
+    // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+    //
+    CompareLength                              = ISO_639_2_ENTRY_SIZE;
+    mVariableModuleGlobal->Lang[CompareLength] = '\0';
+    return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
+  } else {
+    while (TRUE) {
+      //
+      // Take semicolon as delimitation, sequentially traverse supported language codes.
+      //
+      for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
+        Supported++;
+      }
+
+      if ((*Supported == '\0') && (SubIndex != Index)) {
+        //
+        // Have completed the traverse, but not find corrsponding string.
+        // This case is not allowed to happen.
+        //
+        ASSERT (FALSE);
+        return NULL;
+      }
+
+      if (SubIndex == Index) {
+        //
+        // According to the index of Lang string in SupportedLang string to get the language.
+        // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
+        // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+        //
+        mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
+        return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
+      }
+
+      SubIndex++;
+
+      //
+      // Skip ';' characters in Supported
+      //
+      for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {
+      }
+    }
+  }
+}
+
+/**
+  Returns a pointer to an allocated buffer that contains the best matching language
+  from a set of supported languages.
+
+  This function supports both ISO 639-2 and RFC 4646 language codes, but language
+  code types may not be mixed in a single call to this function. This function
+  supports a variable argument list that allows the caller to pass in a prioritized
+  list of language codes to test against all the language codes in SupportedLanguages.
+
+  If SupportedLanguages is NULL, then ASSERT().
+
+  @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
+                                  contains a set of language codes in the format
+                                  specified by Iso639Language.
+  @param[in]  Iso639Language      If not zero, then all language codes are assumed to be
+                                  in ISO 639-2 format.  If zero, then all language
+                                  codes are assumed to be in RFC 4646 language format
+  @param[in]  ...                 A variable argument list that contains pointers to
+                                  Null-terminated ASCII strings that contain one or more
+                                  language codes in the format specified by Iso639Language.
+                                  The first language code from each of these language
+                                  code lists is used to determine if it is an exact or
+                                  close match to any of the language codes in
+                                  SupportedLanguages.  Close matches only apply to RFC 4646
+                                  language codes, and the matching algorithm from RFC 4647
+                                  is used to determine if a close match is present.  If
+                                  an exact or close match is found, then the matching
+                                  language code from SupportedLanguages is returned.  If
+                                  no matches are found, then the next variable argument
+                                  parameter is evaluated.  The variable argument list
+                                  is terminated by a NULL.
+
+  @retval NULL   The best matching language could not be found in SupportedLanguages.
+  @retval NULL   There are not enough resources available to return the best matching
+                 language.
+  @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
+                 language in SupportedLanguages.
+
+**/
+CHAR8 *
+EFIAPI
+VariableGetBestLanguage (
+  IN CONST CHAR8  *SupportedLanguages,
+  IN UINTN        Iso639Language,
+  ...
+  )
+{
+  VA_LIST      Args;
+  CHAR8        *Language;
+  UINTN        CompareLength;
+  UINTN        LanguageLength;
+  CONST CHAR8  *Supported;
+  CHAR8        *Buffer;
+
+  if (SupportedLanguages == NULL) {
+    return NULL;
+  }
+
+  VA_START (Args, Iso639Language);
+  while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
+    //
+    // Default to ISO 639-2 mode
+    //
+    CompareLength  = 3;
+    LanguageLength = MIN (3, AsciiStrLen (Language));
+
+    //
+    // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
+    //
+    if (Iso639Language == 0) {
+      for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++) {
+      }
+    }
+
+    //
+    // Trim back the length of Language used until it is empty
+    //
+    while (LanguageLength > 0) {
+      //
+      // Loop through all language codes in SupportedLanguages
+      //
+      for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
+        //
+        // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
+        //
+        if (Iso639Language == 0) {
+          //
+          // Skip ';' characters in Supported
+          //
+          for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {
+          }
+
+          //
+          // Determine the length of the next language code in Supported
+          //
+          for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++) {
+          }
+
+          //
+          // If Language is longer than the Supported, then skip to the next language
+          //
+          if (LanguageLength > CompareLength) {
+            continue;
+          }
+        }
+
+        //
+        // See if the first LanguageLength characters in Supported match Language
+        //
+        if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
+          VA_END (Args);
+
+          Buffer                = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
+          Buffer[CompareLength] = '\0';
+          return CopyMem (Buffer, Supported, CompareLength);
+        }
+      }
+
+      if (Iso639Language != 0) {
+        //
+        // If ISO 639 mode, then each language can only be tested once
+        //
+        LanguageLength = 0;
+      } else {
+        //
+        // If RFC 4646 mode, then trim Language from the right to the next '-' character
+        //
+        for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--) {
+        }
+      }
+    }
+  }
+
+  VA_END (Args);
+
+  //
+  // No matches were found
+  //
+  return NULL;
+}
+
+/**
+  This function is to check if the remaining variable space is enough to set
+  all Variables from argument list successfully. The purpose of the check
+  is to keep the consistency of the Variables to be in variable storage.
+
+  Note: Variables are assumed to be in same storage.
+  The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+  so follow the argument sequence to check the Variables.
+
+  @param[in] Attributes         Variable attributes for Variable entries.
+  @param[in] Marker             VA_LIST style variable argument list.
+                                The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+                                A NULL terminates the list. The VariableSize of
+                                VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+                                It will be changed to variable total size as output.
+
+  @retval TRUE                  Have enough variable space to set the Variables successfully.
+  @retval FALSE                 No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistencyInternal (
+  IN UINT32   Attributes,
+  IN VA_LIST  Marker
+  )
+{
+  EFI_STATUS                  Status;
+  VA_LIST                     Args;
+  VARIABLE_ENTRY_CONSISTENCY  *VariableEntry;
+  UINT64                      MaximumVariableStorageSize;
+  UINT64                      RemainingVariableStorageSize;
+  UINT64                      MaximumVariableSize;
+  UINTN                       TotalNeededSize;
+  UINTN                       OriginalVarSize;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+  VARIABLE_POINTER_TRACK      VariablePtrTrack;
+  VARIABLE_HEADER             *NextVariable;
+  UINTN                       VarNameSize;
+  UINTN                       VarDataSize;
+
+  //
+  // Non-Volatile related.
+  //
+  VariableStoreHeader = mNvVariableCache;
+
+  Status = VariableServiceQueryVariableInfoInternal (
+             Attributes,
+             &MaximumVariableStorageSize,
+             &RemainingVariableStorageSize,
+             &MaximumVariableSize
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  TotalNeededSize = 0;
+  VA_COPY (Args, Marker);
+  VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+  while (VariableEntry != NULL) {
+    //
+    // Calculate variable total size.
+    //
+    VarNameSize                 = StrSize (VariableEntry->Name);
+    VarNameSize                += GET_PAD_SIZE (VarNameSize);
+    VarDataSize                 = VariableEntry->VariableSize;
+    VarDataSize                += GET_PAD_SIZE (VarDataSize);
+    VariableEntry->VariableSize = HEADER_ALIGN (
+                                    GetVariableHeaderSize (
+                                      mVariableModuleGlobal->VariableGlobal.AuthFormat
+                                      ) + VarNameSize + VarDataSize
+                                    );
+
+    TotalNeededSize += VariableEntry->VariableSize;
+    VariableEntry    = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+  }
+
+  VA_END (Args);
+
+  if (RemainingVariableStorageSize >= TotalNeededSize) {
+    //
+    // Already have enough space.
+    //
+    return TRUE;
+  } else if (AtRuntime ()) {
+    //
+    // At runtime, no reclaim.
+    // The original variable space of Variables can't be reused.
+    //
+    return FALSE;
+  }
+
+  VA_COPY (Args, Marker);
+  VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+  while (VariableEntry != NULL) {
+    //
+    // Check if Variable[Index] has been present and get its size.
+    //
+    OriginalVarSize           = 0;
+    VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
+    VariablePtrTrack.EndPtr   = GetEndPointer (VariableStoreHeader);
+    Status                    = FindVariableEx (
+                                  VariableEntry->Name,
+                                  VariableEntry->Guid,
+                                  FALSE,
+                                  &VariablePtrTrack,
+                                  mVariableModuleGlobal->VariableGlobal.AuthFormat
+                                  );
+    if (!EFI_ERROR (Status)) {
+      //
+      // Get size of Variable[Index].
+      //
+      NextVariable    = GetNextVariablePtr (VariablePtrTrack.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+      OriginalVarSize = (UINTN)NextVariable - (UINTN)VariablePtrTrack.CurrPtr;
+      //
+      // Add the original size of Variable[Index] to remaining variable storage size.
+      //
+      RemainingVariableStorageSize += OriginalVarSize;
+    }
+
+    if (VariableEntry->VariableSize > RemainingVariableStorageSize) {
+      //
+      // No enough space for Variable[Index].
+      //
+      VA_END (Args);
+      return FALSE;
+    }
+
+    //
+    // Sub the (new) size of Variable[Index] from remaining variable storage size.
+    //
+    RemainingVariableStorageSize -= VariableEntry->VariableSize;
+    VariableEntry                 = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+  }
+
+  VA_END (Args);
+
+  return TRUE;
+}
+
+/**
+  This function is to check if the remaining variable space is enough to set
+  all Variables from argument list successfully. The purpose of the check
+  is to keep the consistency of the Variables to be in variable storage.
+
+  Note: Variables are assumed to be in same storage.
+  The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+  so follow the argument sequence to check the Variables.
+
+  @param[in] Attributes         Variable attributes for Variable entries.
+  @param ...                    The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+                                A NULL terminates the list. The VariableSize of
+                                VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+                                It will be changed to variable total size as output.
+
+  @retval TRUE                  Have enough variable space to set the Variables successfully.
+  @retval FALSE                 No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistency (
+  IN UINT32  Attributes,
+  ...
+  )
+{
+  VA_LIST  Marker;
+  BOOLEAN  Return;
+
+  VA_START (Marker, Attributes);
+
+  Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
+
+  VA_END (Marker);
+
+  return Return;
+}
+
+/**
+  Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
+
+  When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
+
+  According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
+  and are read-only. Therefore, in variable driver, only store the original value for other use.
+
+  @param[in] VariableName       Name of variable.
+
+  @param[in] Data               Variable data.
+
+  @param[in] DataSize           Size of data. 0 means delete.
+
+  @retval EFI_SUCCESS           The update operation is successful or ignored.
+  @retval EFI_WRITE_PROTECTED   Update PlatformLangCodes/LangCodes at runtime.
+  @retval EFI_OUT_OF_RESOURCES  No enough variable space to do the update operation.
+  @retval Others                Other errors happened during the update operation.
+
+**/
+EFI_STATUS
+AutoUpdateLangVariable (
+  IN  CHAR16  *VariableName,
+  IN  VOID    *Data,
+  IN  UINTN   DataSize
+  )
+{
+  EFI_STATUS                  Status;
+  CHAR8                       *BestPlatformLang;
+  CHAR8                       *BestLang;
+  UINTN                       Index;
+  UINT32                      Attributes;
+  VARIABLE_POINTER_TRACK      Variable;
+  BOOLEAN                     SetLanguageCodes;
+  VARIABLE_ENTRY_CONSISTENCY  VariableEntry[2];
+
+  //
+  // Don't do updates for delete operation
+  //
+  if (DataSize == 0) {
+    return EFI_SUCCESS;
+  }
+
+  SetLanguageCodes = FALSE;
+
+  if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {
+    //
+    // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
+    //
+    if (AtRuntime ()) {
+      return EFI_WRITE_PROTECTED;
+    }
+
+    SetLanguageCodes = TRUE;
+
+    //
+    // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
+    // Therefore, in variable driver, only store the original value for other use.
+    //
+    if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
+      FreePool (mVariableModuleGlobal->PlatformLangCodes);
+    }
+
+    mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
+    ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
+
+    //
+    // PlatformLang holds a single language from PlatformLangCodes,
+    // so the size of PlatformLangCodes is enough for the PlatformLang.
+    //
+    if (mVariableModuleGlobal->PlatformLang != NULL) {
+      FreePool (mVariableModuleGlobal->PlatformLang);
+    }
+
+    mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
+    ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
+  } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {
+    //
+    // LangCodes is a volatile variable, so it can not be updated at runtime.
+    //
+    if (AtRuntime ()) {
+      return EFI_WRITE_PROTECTED;
+    }
+
+    SetLanguageCodes = TRUE;
+
+    //
+    // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
+    // Therefore, in variable driver, only store the original value for other use.
+    //
+    if (mVariableModuleGlobal->LangCodes != NULL) {
+      FreePool (mVariableModuleGlobal->LangCodes);
+    }
+
+    mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
+    ASSERT (mVariableModuleGlobal->LangCodes != NULL);
+  }
+
+  if (  SetLanguageCodes
+     && (mVariableModuleGlobal->PlatformLangCodes != NULL)
+     && (mVariableModuleGlobal->LangCodes != NULL))
+  {
+    //
+    // Update Lang if PlatformLang is already set
+    // Update PlatformLang if Lang is already set
+    //
+    Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+    if (!EFI_ERROR (Status)) {
+      //
+      // Update Lang
+      //
+      VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;
+      Data         = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+      DataSize     = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    } else {
+      Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+      if (!EFI_ERROR (Status)) {
+        //
+        // Update PlatformLang
+        //
+        VariableName = EFI_LANG_VARIABLE_NAME;
+        Data         = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+        DataSize     = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+      } else {
+        //
+        // Neither PlatformLang nor Lang is set, directly return
+        //
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  Status = EFI_SUCCESS;
+
+  //
+  // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
+  //
+  Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+
+  if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {
+    //
+    // Update Lang when PlatformLangCodes/LangCodes were set.
+    //
+    if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
+      //
+      // When setting PlatformLang, firstly get most matched language string from supported language codes.
+      //
+      BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
+      if (BestPlatformLang != NULL) {
+        //
+        // Get the corresponding index in language codes.
+        //
+        Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
+
+        //
+        // Get the corresponding ISO639 language tag according to RFC4646 language tag.
+        //
+        BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
+
+        //
+        // Check the variable space for both Lang and PlatformLang variable.
+        //
+        VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
+        VariableEntry[0].Guid         = &gEfiGlobalVariableGuid;
+        VariableEntry[0].Name         = EFI_LANG_VARIABLE_NAME;
+
+        VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);
+        VariableEntry[1].Guid         = &gEfiGlobalVariableGuid;
+        VariableEntry[1].Name         = EFI_PLATFORM_LANG_VARIABLE_NAME;
+        if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+          //
+          // No enough variable space to set both Lang and PlatformLang successfully.
+          //
+          Status = EFI_OUT_OF_RESOURCES;
+        } else {
+          //
+          // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
+          //
+          FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+
+          Status = UpdateVariable (
+                     EFI_LANG_VARIABLE_NAME,
+                     &gEfiGlobalVariableGuid,
+                     BestLang,
+                     ISO_639_2_ENTRY_SIZE + 1,
+                     Attributes,
+                     0,
+                     0,
+                     &Variable,
+                     NULL
+                     );
+        }
+
+        DEBUG ((DEBUG_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));
+      }
+    }
+  } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {
+    //
+    // Update PlatformLang when PlatformLangCodes/LangCodes were set.
+    //
+    if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
+      //
+      // When setting Lang, firstly get most matched language string from supported language codes.
+      //
+      BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
+      if (BestLang != NULL) {
+        //
+        // Get the corresponding index in language codes.
+        //
+        Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
+
+        //
+        // Get the corresponding RFC4646 language tag according to ISO639 language tag.
+        //
+        BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
+
+        //
+        // Check the variable space for both PlatformLang and Lang variable.
+        //
+        VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);
+        VariableEntry[0].Guid         = &gEfiGlobalVariableGuid;
+        VariableEntry[0].Name         = EFI_PLATFORM_LANG_VARIABLE_NAME;
+
+        VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
+        VariableEntry[1].Guid         = &gEfiGlobalVariableGuid;
+        VariableEntry[1].Name         = EFI_LANG_VARIABLE_NAME;
+        if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+          //
+          // No enough variable space to set both PlatformLang and Lang successfully.
+          //
+          Status = EFI_OUT_OF_RESOURCES;
+        } else {
+          //
+          // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
+          //
+          FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+
+          Status = UpdateVariable (
+                     EFI_PLATFORM_LANG_VARIABLE_NAME,
+                     &gEfiGlobalVariableGuid,
+                     BestPlatformLang,
+                     AsciiStrSize (BestPlatformLang),
+                     Attributes,
+                     0,
+                     0,
+                     &Variable,
+                     NULL
+                     );
+        }
+
+        DEBUG ((DEBUG_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));
+      }
+    }
+  }
+
+  if (SetLanguageCodes) {
+    //
+    // Continue to set PlatformLangCodes or LangCodes.
+    //
+    return EFI_SUCCESS;
+  } else {
+    return Status;
+  }
+}
+
+/**
+  Check if there's enough free space in storage to write the new variable.
+
+  @param[in] NewVariable        Pointer to buffer of new variable.
+  @param[in] VariableSize       Size of new variable.
+  @param[in] VariableName       Name of variable.
+  @param[in] VendorGuid         Guid of variable.
+  @param[in] Attributes         Attributes of the variable.
+  @param[in] VolatileFlag       Volatile/non-volatile variable indicator.
+
+  @retval EFI_SUCCESS           Enough free space on variable storage.
+  @retval EFI_BUFFER_TOO_SMALL  There's not enough continuous free space.
+  @retval EFI_OUT_OF_RESOURCES  There's not enough free space in total.
+**/
+EFI_STATUS
+CheckVariableStoreSpace (
+  IN  VARIABLE_HEADER  *NewVariable,
+  IN  UINTN            VariableSize,
+  IN  CHAR16           *VariableName,
+  IN  EFI_GUID         *VendorGuid,
+  IN  UINT32           Attributes,
+  IN  BOOLEAN          VolatileFlag
+  )
+{
+  BOOLEAN                IsCommonVariable;
+  BOOLEAN                IsCommonUserVariable;
+  UINTN                  CommonVariableTotalSize;
+  UINTN                  CommonUserVariableTotalSize;
+  UINTN                  HwErrVariableTotalSize;
+  VARIABLE_STORE_HEADER  *VarStore;
+
+  if ((NewVariable == NULL) || (VariableSize == 0)) {
+    return EFI_SUCCESS;
+  }
+
+  if (VolatileFlag) {
+    VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+               mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+    if ((UINT32)(VariableSize + mVariableModuleGlobal->VolatileLastVariableOffset)
+        > VarStore->Size)
+    {
+      return EFI_BUFFER_TOO_SMALL;
+    }
+  } else {
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+      IsCommonVariable     = TRUE;
+      IsCommonUserVariable = IsUserVariable (NewVariable);
+    } else {
+      IsCommonVariable     = FALSE;
+      IsCommonUserVariable = FALSE;
+    }
+
+    CommonVariableTotalSize     = mVariableModuleGlobal->CommonVariableTotalSize + VariableSize;
+    CommonUserVariableTotalSize = mVariableModuleGlobal->CommonUserVariableTotalSize + VariableSize;
+    HwErrVariableTotalSize      = mVariableModuleGlobal->HwErrVariableTotalSize + VariableSize;
+
+    if (  (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) &&
+           (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)))
+       || (IsCommonVariable && (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace))
+       || (IsCommonVariable &&
+           AtRuntime () &&
+           (CommonVariableTotalSize > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+       || (IsCommonUserVariable &&
+           (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)))
+    {
+      if (AtRuntime ()) {
+        if (IsCommonUserVariable &&
+            ((VariableSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+             > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+        {
+          RecordVarErrorFlag (
+            VAR_ERROR_FLAG_USER_ERROR,
+            VariableName,
+            VendorGuid,
+            Attributes,
+            VariableSize
+            );
+        }
+
+        if (IsCommonVariable &&
+            ((VariableSize + mVariableModuleGlobal->CommonVariableTotalSize)
+             > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+        {
+          RecordVarErrorFlag (
+            VAR_ERROR_FLAG_SYSTEM_ERROR,
+            VariableName,
+            VendorGuid,
+            Attributes,
+            VariableSize
+            );
+        }
+
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      return EFI_BUFFER_TOO_SMALL;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Fill specific data of auth-variable in buffer.
+
+  @param[in,out]  NewVariable        Pointer to buffer of new variable.
+  @param[in]      OldVariable        Pointer to buffer of old copy of the variable.
+  @param[in]      Attributes         Attributes of the variable.
+  @param[in]      KeyIndex           Index of associated public key.
+  @param[in]      MonotonicCount     Value of associated monotonic count.
+  @param[in]      TimeStamp          Value of associated TimeStamp.
+
+**/
+VOID
+SetVariableAuthData (
+  IN  OUT AUTHENTICATED_VARIABLE_HEADER  *NewVariable,
+  IN      AUTHENTICATED_VARIABLE_HEADER  *OldVariable,
+  IN      UINT32                         Attributes,
+  IN      UINT32                         KeyIndex,
+  IN      UINT64                         MonotonicCount,
+  IN      EFI_TIME                       *TimeStamp
+  )
+{
+  NewVariable->PubKeyIndex    = KeyIndex;
+  NewVariable->MonotonicCount = MonotonicCount;
+
+  if ((TimeStamp != NULL) &&
+      ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0))
+  {
+    //
+    // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
+    // when the new TimeStamp value is later than the current timestamp associated
+    // with the variable, we need associate the new timestamp with the updated value.
+    //
+    if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+        (OldVariable != NULL) &&
+        !VariableCompareTimeStampInternal (&OldVariable->TimeStamp, TimeStamp))
+    {
+      TimeStamp = &OldVariable->TimeStamp;
+    }
+
+    CopyMem (&NewVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+  } else {
+    ZeroMem (&NewVariable->TimeStamp, sizeof (EFI_TIME));
+  }
+}
+
+/**
+  Fill the variable data buffer according to variable format on storage.
+
+  @param[in,out]  NewVariable        Pointer to buffer of new variable.
+  @param[in]      OldVariable        Pointer to buffer of old copy of the variable.
+  @param[in]      VariableName       Name of variable.
+  @param[in]      VendorGuid         Guid of variable.
+  @param[in]      Data               Variable data.
+  @param[in]      DataSize           Size of data. 0 means delete.
+  @param[in]      Attributes         Attributes of the variable.
+  @param[in]      KeyIndex           Index of associated public key.
+  @param[in]      MonotonicCount     Value of associated monotonic count.
+  @param[in]      TimeStamp          Value of associated TimeStamp.
+
+  @retval Size of the new variable.
+
+**/
+UINTN
+SetVariableData (
+  IN  OUT VARIABLE_HEADER  *NewVariable,
+  IN      VARIABLE_HEADER  *OldVariable,
+  IN      CHAR16           *VariableName,
+  IN      EFI_GUID         *VendorGuid,
+  IN      VOID             *Data,
+  IN      UINTN            DataSize,
+  IN      UINT32           Attributes,
+  IN      UINT32           KeyIndex,
+  IN      UINT64           MonotonicCount,
+  IN      EFI_TIME         *TimeStamp
+  )
+{
+  EFI_STATUS  Status;
+  BOOLEAN     AuthFormat;
+  UINT8       *DataPtr;
+  UINTN       NameSize;
+  UINTN       OldDataSize;
+
+  AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  if (AuthFormat) {
+    SetVariableAuthData (
+      (AUTHENTICATED_VARIABLE_HEADER *)NewVariable,
+      (AUTHENTICATED_VARIABLE_HEADER *)OldVariable,
+      Attributes,
+      KeyIndex,
+      MonotonicCount,
+      TimeStamp
+      );
+  }
+
+  NewVariable->StartId    = VARIABLE_DATA;
+  NewVariable->State      = VAR_ADDED;
+  NewVariable->Reserved   = 0;
+  NewVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
+
+  CopyMem (
+    GetVendorGuidPtr (NewVariable, AuthFormat),
+    VendorGuid,
+    sizeof (EFI_GUID)
+    );
+
+  NameSize = StrSize (VariableName);
+  SetNameSizeOfVariable (NewVariable, NameSize, AuthFormat);
+  CopyMem (
+    (UINT8 *)GetVariableNamePtr (NewVariable, AuthFormat),
+    VariableName,
+    NameSize
+    );
+
+  //
+  // Set data size first otherwise we can't get correct data pointer in the
+  // buffer of new variable.
+  //
+  SetDataSizeOfVariable (NewVariable, DataSize, AuthFormat);
+  DataPtr = GetVariableDataPtr (NewVariable, AuthFormat);
+  if (((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) &&
+      (OldVariable != NULL) &&
+      ((OldVariable->State == VAR_ADDED) ||
+       (OldVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+  {
+    //
+    // Get old data, which might be encrypted.
+    //
+    OldDataSize = mVariableModuleGlobal->ScratchBufferSize
+                  - ((UINTN)DataPtr - (UINTN)NewVariable);
+    Status = ProtectedVariableLibGetByBuffer (
+               OldVariable,
+               DataPtr,
+               (UINT32 *)&OldDataSize,
+               AuthFormat
+               );
+    if (Status == EFI_UNSUPPORTED) {
+      OldDataSize = DataSizeOfVariable (OldVariable, AuthFormat);
+      CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat), OldDataSize);
+    } else if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return 0;
+    }
+
+    DataPtr += OldDataSize;
+    //
+    // Update data size.
+    //
+    SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthFormat);
+  }
+
+  CopyMem (DataPtr, Data, DataSize);
+
+  //
+  // The actual size of the variable stored in storage should include padding.
+  //
+  return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) - (UINTN)NewVariable);
+}
+
+/**
+  Update state of given variable as well as its cached copy.
+
+  @param[in,out]  Variable        Pointer to the buffer of the variable.
+  @param[in,out]  CacheVariable   Cache copy of the variable.
+  @param[in]      NewState        New state value.
+  @param[in]      Volatile        Volatile/non-volatile variable indicator.
+
+  @retval EFI_SUCCESS     Variable state was updated successfully.
+  @retval Others          Failed to update the variable state.
+
+**/
+EFI_STATUS
+UpdateVariableState (
+  IN  OUT VARIABLE_HEADER  *Variable,
+  IN  OUT VARIABLE_HEADER  *CacheVariable,
+  IN      UINT8            NewState,
+  IN      BOOLEAN          Volatile
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = UpdateVariableStore (
+             &mVariableModuleGlobal->VariableGlobal,
+             Volatile,
+             FALSE,
+             mVariableModuleGlobal->FvbInstance,
+             (UINTN)&Variable->State,
+             sizeof (NewState),
+             &NewState
+             );
+  if (!EFI_ERROR (Status) && (CacheVariable != NULL)) {
+    CacheVariable->State = NewState;
+  }
+
+  return Status;
+}
+
+/**
+  Flush variable data to variable storage.
+
+  @param[in]      VarStoreBase    Base address of variable storage.
+  @param[in,out]  Offset          Offset to write the variable from.
+                                  Offset from where next variable can be written.
+  @param[in,out]  NewVariable     Pointer to the buffer of new variable.
+  @param[in]      VariableSize    Size of new variable.
+  @param[in]      Volatile        Volatile/non-volatile variable indicator.
+  @param[in]      AuthFormat      Auth-variable indicator.
+
+  @retval EFI_SUCCESS     Variable(s) were written successfully.
+  @retval Others          Failed to write the variable data.
+
+**/
+EFI_STATUS
+WriteVariable (
+  IN  EFI_PHYSICAL_ADDRESS  VarStoreBase,
+  IN  OUT UINTN             *Offset,
+  IN  OUT VARIABLE_HEADER   **NewVariable,
+  IN      UINT32            VariableSize,
+  IN      BOOLEAN           Volatile,
+  IN      BOOLEAN           AuthFormat
+  )
+{
+  EFI_STATUS  Status;
+
+  struct {
+    UINTN     Offset;
+    UINT8     *Buffer;
+    UINT32    Size;
+    UINT8     State;
+  }                   WriteSteps[4];
+  UINTN            Index;
+  UINTN            Steps;
+  VARIABLE_HEADER  *Variable;
+
+  Variable = *NewVariable;
+  if (Volatile) {
+    //
+    // For non-volatile variable, one step only :
+    //
+    WriteSteps[0].Offset = *Offset;
+    WriteSteps[0].Buffer = (UINT8 *)Variable;
+    WriteSteps[0].Size   = VariableSize;
+
+    Steps = 1;
+  } else {
+    //
+    // Four steps for non-volatile variable:
+    //
+    // 1. Write variable header
+    // 2. Set variable state to header valid
+    // 3. Write variable name and data
+    // 4. Set variable state to valid
+    //
+    Variable->State      = 0xff;
+    WriteSteps[0].Offset = *Offset;
+    WriteSteps[0].Buffer = (UINT8 *)Variable;
+    WriteSteps[0].Size   = (UINT32)GetVariableHeaderSize (AuthFormat);
+
+    WriteSteps[1].State  = VAR_HEADER_VALID_ONLY;
+    WriteSteps[1].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+    WriteSteps[1].Buffer = &WriteSteps[1].State;
+    WriteSteps[1].Size   = sizeof (Variable->State);
+
+    WriteSteps[2].Offset = *Offset + GetVariableHeaderSize (AuthFormat);
+    WriteSteps[2].Buffer = (UINT8 *)Variable + GetVariableHeaderSize (AuthFormat);
+    WriteSteps[2].Size   = VariableSize - (UINT32)GetVariableHeaderSize (AuthFormat);
+
+    WriteSteps[3].State  = VAR_ADDED;
+    WriteSteps[3].Offset = *Offset + OFFSET_OF (VARIABLE_HEADER, State);
+    WriteSteps[3].Buffer = &WriteSteps[3].State;
+    WriteSteps[3].Size   = sizeof (Variable->State);
+
+    Steps = ARRAY_SIZE (WriteSteps);
+  }
+
+  for (Index = 0; Index < Steps; ++Index) {
+    Status = UpdateVariableStore (
+               &mVariableModuleGlobal->VariableGlobal,
+               Volatile,
+               TRUE,
+               mVariableModuleGlobal->FvbInstance,
+               WriteSteps[Index].Offset,
+               WriteSteps[Index].Size,
+               WriteSteps[Index].Buffer
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+  }
+
+  Variable->State = VAR_ADDED;
+  if (!Volatile) {
+    CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize);
+  }
+
+  *NewVariable = (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset);
+  *Offset     += HEADER_ALIGN (VariableSize);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Rebase the given variable pointer(s) to the equivalent one in given variable
+  storage via VarStore.
+
+  @param[in]      InVarTrackPtr     Pointer to current variable in cache.
+  @param[out]     OutVarTrackPtr    Pointer to rebased variable against VarStore.
+  @param[in]      VarStore          Start of variable storage to rebase against.
+  @param[in]      VariableName      Name of variable.
+  @param[in]      VendorGuid        Guid of variable.
+  @param[in]      ByOffset          If TRUE, don't do variable search in VarStore.
+
+  @retval EFI_SUCCESS           Variable(s) were deleted successfully.
+  @retval EFI_INVALID_PARAMETER Invalid parameters passed.
+  @retval EFI_NOT_FOUND         Given variable (VariableName & VendorGuid) was
+                                not found in VarStore, if ByOffset is FALSE.
+
+**/
+EFI_STATUS
+RebaseVariablePtr (
+  IN      VARIABLE_POINTER_TRACK  *InVarTrackPtr,
+  OUT VARIABLE_POINTER_TRACK      *OutVarTrackPtr,
+  IN      VARIABLE_STORE_HEADER   *VarStore,
+  IN      CHAR16                  *VariableName,
+  IN      EFI_GUID                *VendorGuid,
+  IN      BOOLEAN                 ByOffset
+  )
+{
+  EFI_STATUS       Status;
+  BOOLEAN          AuthFormat;
+  VARIABLE_HEADER  *NewStart;
+
+  if ((InVarTrackPtr == NULL) || (OutVarTrackPtr == NULL) || (VarStore == NULL)) {
+    ASSERT (InVarTrackPtr != NULL);
+    ASSERT (OutVarTrackPtr != NULL);
+    ASSERT (VarStore != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  if (  (InVarTrackPtr->CurrPtr == NULL)
+     || (InVarTrackPtr->StartPtr == GetStartPointer (VarStore)))
+  {
+    CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof (VARIABLE_POINTER_TRACK));
+    return EFI_SUCCESS;
+  }
+
+  NewStart = GetStartPointer (VarStore);
+  if (ByOffset) {
+    OutVarTrackPtr->CurrPtr = (VARIABLE_HEADER *)
+                              ((UINTN)NewStart + ((UINTN)InVarTrackPtr->CurrPtr -
+                                                  (UINTN)InVarTrackPtr->StartPtr));
+
+    if (InVarTrackPtr->InDeletedTransitionPtr != NULL) {
+      OutVarTrackPtr->InDeletedTransitionPtr =
+        (VARIABLE_HEADER *)((UINTN)NewStart +
+                            ((UINTN)InVarTrackPtr->InDeletedTransitionPtr -
+                             (UINTN)InVarTrackPtr->StartPtr));
+    } else {
+      OutVarTrackPtr->InDeletedTransitionPtr = NULL;
+    }
+
+    OutVarTrackPtr->StartPtr = NewStart;
+    OutVarTrackPtr->EndPtr   = GetEndPointer (VarStore);
+  } else {
+    OutVarTrackPtr->StartPtr = NewStart;
+    OutVarTrackPtr->EndPtr   = GetEndPointer (VarStore);
+
+    Status = FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTrackPtr, AuthFormat);
+    if ((OutVarTrackPtr->CurrPtr == NULL) || EFI_ERROR (Status)) {
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  if (  (VarStore == mNvVariableCache)
+     || ((UINTN)VarStore == (UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))
+  {
+    OutVarTrackPtr->Volatile = FALSE;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check if the given variable is from HOB.
+
+  @param[in] CacheVariable      Pointer to current variable in cache.
+
+  @retval TRUE    The variable is from HOB.
+  @retval FALSE   The variable is NOT from HOB.
+
+**/
+BOOLEAN
+IsHobVariable (
+  IN VARIABLE_POINTER_TRACK  *CacheVariable
+  )
+{
+  VARIABLE_STORE_HEADER  *HobVarStore;
+
+  HobVarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+                mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+  return (CacheVariable->CurrPtr != NULL &&
+          HobVarStore != NULL &&
+          CacheVariable->StartPtr == GetStartPointer (HobVarStore));
+}
+
+/**
+  Get temporary buffer for a new variable data.
+
+  @retval Pointer to the buffer address.
+
+**/
+VARIABLE_HEADER *
+GetNewVariableBuffer (
+  VOID
+  )
+{
+  VARIABLE_HEADER        *NewVariable;
+  VARIABLE_STORE_HEADER  *VarStore;
+
+  //
+  // Tricky part: Use scratch data area at the end of volatile variable store
+  // as a temporary storage.
+  //
+  VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+             mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+  NewVariable = GetEndPointer (VarStore);
+
+  SetMem (NewVariable, mVariableModuleGlobal->ScratchBufferSize, 0xff);
+
+  return NewVariable;
+}
+
+/**
+  Delete old copies of variable completely.
+
+  @param[in]      VariableName       Name of variable.
+  @param[in]      VendorGuid         Guid of variable.
+  @param[in]      Variable           Pointer to current variable on storage.
+  @param[in,out]  CacheVariable      Pointer to current variable in cache.
+  @param[in]      VolatileFlag       Auth-variable indicator.
+
+  @retval EFI_SUCCESS           Variable(s) were deleted successfully.
+  @retval Others                Failed to update variable state.
+
+**/
+EFI_STATUS
+DeleteVariable (
+  IN      CHAR16                  *VariableName,
+  IN      EFI_GUID                *VendorGuid,
+  IN      VARIABLE_POINTER_TRACK  *Variable,
+  IN  OUT VARIABLE_POINTER_TRACK  *CacheVariable,
+  IN      BOOLEAN                 VolatileFlag
+  )
+{
+  EFI_STATUS  Status;
+
+  if (Variable->InDeletedTransitionPtr != NULL) {
+    ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
+    //
+    // Both ADDED and IN_DELETED_TRANSITION variable are present,
+    // set IN_DELETED_TRANSITION one to DELETED state first.
+    //
+    Status = UpdateVariableState (
+               Variable->InDeletedTransitionPtr,
+               CacheVariable->InDeletedTransitionPtr,
+               CacheVariable->InDeletedTransitionPtr->State & VAR_DELETED,
+               VolatileFlag
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  ASSERT (CacheVariable->CurrPtr != NULL);
+  Status = UpdateVariableState (
+             Variable->CurrPtr,
+             CacheVariable->CurrPtr,
+             CacheVariable->CurrPtr->State & VAR_DELETED,
+             VolatileFlag
+             );
+
+  if (!EFI_ERROR (Status)) {
+    UpdateVariableInfo (
+      VariableName,
+      VendorGuid,
+      Variable->Volatile,
+      FALSE,
+      FALSE,
+      TRUE,
+      FALSE,
+      &gVariableInfo
+      );
+    if (!Variable->Volatile) {
+      FlushHobVariableToFlash (VariableName, VendorGuid);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Check if it's the right time to update a variable.
+
+  @param[in] Attributes         Attributes of a variable.
+
+  @retval TRUE    It's ready for variable update.
+  @retval FALSE   It's NOT ready for variable update.
+
+**/
+BOOLEAN
+ReadyForUpdate (
+  IN UINT32  Attributes
+  )
+{
+  if ((mVariableModuleGlobal->FvbInstance == NULL) &&
+      !mVariableModuleGlobal->VariableGlobal.EmuNvMode)
+  {
+    //
+    // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+    // is not installed.
+    //
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+      //
+      // Trying to update NV variable prior to the installation of
+      // EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+      //
+      DEBUG ((
+        DEBUG_ERROR,
+        "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
+        EFI_NOT_AVAILABLE_YET
+        ));
+      return FALSE;
+    } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+      //
+      // Trying to update volatile authenticated variable prior to the
+      // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The authenticated
+      // variable perhaps is not initialized, just return here.
+      //
+      DEBUG ((
+        DEBUG_ERROR,
+        "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n",
+        EFI_NOT_AVAILABLE_YET
+        ));
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+  Check parameters associated with the variable to update.
+
+  @param[in] Variable           Pointer to current variable on storage.
+  @param[in] CacheVariable      Pointer to current variable in cache.
+  @param[in] VariableName       Name of variable.
+  @param[in] VendorGuid         Guid of variable.
+  @param[in] Data               Variable data.
+  @param[in] DataSize           Size of data. 0 means delete.
+  @param[in] Attributes         Attributes of the variable.
+  @param[in] KeyIndex           Index of associated public key.
+  @param[in] MonotonicCount     Value of associated monotonic count.
+  @param[in] TimeStamp          Value of associated TimeStamp.
+
+  @retval EFI_SUCCESS           The variable is ok to be updated.
+  @retval EFI_ALREADY_STARTED   No need to update the variable.
+  @retval EFI_WRITE_PROTECTED   The variable cannot be updated.
+  @retval EFI_INVALID_PARAMETER The variable attributes are not valid.
+  @retval EFI_NOT_FOUND         Trying to delete non-existing variable.
+
+**/
+EFI_STATUS
+ValidateVariableParameters (
+  IN VARIABLE_POINTER_TRACK  *Variable,
+  IN VARIABLE_POINTER_TRACK  *CacheVariable,
+  IN CHAR16                  *VariableName,
+  IN EFI_GUID                *VendorGuid,
+  IN VOID                    *Data,
+  IN UINTN                   DataSize,
+  IN UINT32                  Attributes,
+  IN UINT32                  KeyIndex,
+  IN UINT64                  MonotonicCount,
+  IN EFI_TIME                *TimeStamp
+  )
+{
+  BOOLEAN  AuthFlag;
+
+  AuthFlag = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  if (Variable->CurrPtr != NULL) {
+    //
+    // Update/Delete existing variable.
+    //
+    if (AtRuntime ()) {
+      //
+      // If AtRuntime and the variable is Volatile and Runtime Access,
+      // the volatile is ReadOnly, and SetVariable should be aborted and
+      // return EFI_WRITE_PROTECTED.
+      //
+      if (Variable->Volatile) {
+        return EFI_WRITE_PROTECTED;
+      }
+
+      //
+      // Only variable that have NV attributes can be updated/deleted in Runtime.
+      //
+      if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      //
+      // Only variable that have RT attributes can be updated/deleted in Runtime.
+      //
+      if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+
+    //
+    // Variable content unchanged and no need to update timestamp, just return.
+    //
+    if (  ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)
+       && (TimeStamp == NULL)
+       && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) == DataSize)
+       && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFlag), DataSize) == 0))
+    {
+      UpdateVariableInfo (
+        VariableName,
+        VendorGuid,
+        Variable->Volatile,
+        FALSE,
+        TRUE,
+        FALSE,
+        FALSE,
+        &gVariableInfo
+        );
+      return EFI_ALREADY_STARTED;
+    }
+  } else {
+    //
+    // Create a new variable.
+    //
+
+    //
+    // Make sure we are trying to create a new variable. You cannot delete a new
+    // variable.
+    //
+    if ((DataSize == 0) ||
+        ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0))
+    {
+      return EFI_NOT_FOUND;
+    }
+
+    //
+    // Only variable have NV|RT attribute can be created in Runtime.
+    //
+    if (  AtRuntime ()
+       && (  ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)
+          || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
+    {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+  index of associated public key is needed.
+
+  @param[in]      VariableName       Name of variable.
+  @param[in]      VendorGuid         Guid of variable.
+  @param[in]      Data               Variable data.
+  @param[in]      DataSize           Size of data. 0 means delete.
+  @param[in]      Attributes         Attributes of the variable.
+  @param[in]      KeyIndex           Index of associated public key.
+  @param[in]      MonotonicCount     Value of associated monotonic count.
+  @param[in,out]  CacheVariable      The variable information which is used
+                                     to keep track of variable usage.
+  @param[in]      TimeStamp          Value of associated TimeStamp.
+
+  @retval EFI_SUCCESS           The update operation is success.
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariable (
+  IN      CHAR16                  *VariableName,
+  IN      EFI_GUID                *VendorGuid,
+  IN      VOID                    *Data,
+  IN      UINTN                   DataSize,
+  IN      UINT32                  Attributes      OPTIONAL,
+  IN      UINT32                  KeyIndex        OPTIONAL,
+  IN      UINT64                  MonotonicCount  OPTIONAL,
+  IN OUT  VARIABLE_POINTER_TRACK  *CacheVariable,
+  IN      EFI_TIME                *TimeStamp      OPTIONAL
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_GLOBAL         *VarGlobal;
+  VARIABLE_HEADER         *NewVariable;
+  VARIABLE_HEADER         *NextVariable;
+  VARIABLE_HEADER         *UpdatingVariable;
+  UINTN                   VarSize;
+  UINTN                   UpdateSize;
+  UINTN                   Offset;
+  VARIABLE_POINTER_TRACK  *Variable;
+  VARIABLE_POINTER_TRACK  NvVariable;
+  VARIABLE_STORE_HEADER   *VariableStoreHeader;
+  VARIABLE_RUNTIME_CACHE  *VolatileCacheInstance;
+  BOOLEAN                 IsCommonVariable;
+  BOOLEAN                 IsCommonUserVariable;
+  BOOLEAN                 DeleteFlag;
+  BOOLEAN                 VolatileFlag;
+  BOOLEAN                 HobVarOnlyFlag;
+  EFI_PHYSICAL_ADDRESS    VarStoreBase;
+  UINTN                   *LastVariableOffset;
+
+  if (!ReadyForUpdate (Attributes)) {
+    return EFI_NOT_AVAILABLE_YET;
+  }
+
+  VarGlobal = &mVariableModuleGlobal->VariableGlobal;
+
+  if (  (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))
+     || (Attributes == 0)
+     || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS
+                                         |EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)))
+  {
+    DeleteFlag = TRUE;
+  } else {
+    DeleteFlag = FALSE;
+  }
+
+  if (  ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)
+     || ((CacheVariable->CurrPtr != NULL) &&
+         ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)))
+  {
+    VolatileFlag = FALSE;
+  } else {
+    VolatileFlag = TRUE;
+  }
+
+  //
+  // Check if CacheVariable points to the variable in variable HOB.
+  // If yes, let CacheVariable points to the variable in NV variable cache.
+  //
+  HobVarOnlyFlag = FALSE;
+  if (IsHobVariable (CacheVariable)) {
+    Status = RebaseVariablePtr (
+               CacheVariable,
+               CacheVariable,
+               mNvVariableCache,
+               VariableName,
+               VendorGuid,
+               FALSE
+               );
+    if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {
+      //
+      // There is no matched variable in NV variable cache.
+      //
+      if (DeleteFlag) {
+        //
+        // Leave the deletion to FlushHobVariableToFlash() before return.
+        //
+        HobVarOnlyFlag = TRUE;
+        Status         = EFI_SUCCESS;
+        goto Done;
+      }
+    }
+  }
+
+  //
+  // Determine the physical position of variable store to update, due to cache
+  // mechanims of variable service.
+  //
+  if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
+    //
+    // - Add new variable (volatile or non-volatile); Or
+    // - Update/delete volatile variable in place.
+    //
+    Variable = CacheVariable;
+  } else {
+    //
+    // - Update/Delete existing NV variable.
+    //    CacheVariable points to the variable in the memory copy of Flash area.
+    //    Now let Variable points to the same variable in Flash area.
+    //
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)
+                          VarGlobal->NonVolatileVariableBase;
+    Variable = &NvVariable;
+    Status   = RebaseVariablePtr (
+                 CacheVariable,
+                 Variable,
+                 VariableStoreHeader,
+                 VariableName,
+                 VendorGuid,
+                 TRUE
+                 );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Validate variable parameters.
+  //
+  Status = ValidateVariableParameters (
+             Variable,
+             CacheVariable,
+             VariableName,
+             VendorGuid,
+             Data,
+             DataSize,
+             Attributes,
+             KeyIndex,
+             MonotonicCount,
+             TimeStamp
+             );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Add or update a variable. Allocate a buffer to hold it temporarily.
+  //
+  NewVariable = GetNewVariableBuffer ();
+
+  //
+  // Fill-up variable data first, if necessary.
+  //
+  IsCommonVariable     = FALSE;
+  IsCommonUserVariable = FALSE;
+  if (DeleteFlag) {
+    //
+    // No need to fill up variable buffer when deleting a variable. But the
+    // buffer is still needed if variable protection is employed.
+    //
+    VarSize = 0;
+  } else {
+    VarSize = SetVariableData (
+                NewVariable,
+                CacheVariable->CurrPtr,
+                VariableName,
+                VendorGuid,
+                Data,
+                DataSize,
+                Attributes,
+                KeyIndex,
+                MonotonicCount,
+                TimeStamp
+                );
+
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+      IsCommonVariable     = TRUE;
+      IsCommonUserVariable = IsUserVariable (NewVariable);
+    }
+  }
+
+  //
+  // We might need to do protection for non-volatile variable before flushing
+  // the data to storage. A null version (meaning no protection) of following
+  // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without any
+  // changes to original data.
+  //
+  if (!VolatileFlag) {
+    Status = ProtectedVariableLibUpdate (
+               Variable->CurrPtr,
+               Variable->InDeletedTransitionPtr,
+               NewVariable,
+               &VarSize
+               );
+    if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+      return Status;
+    }
+
+    Status = EFI_SUCCESS;
+  }
+
+  //
+  // Mark the old variable as in delete transition first. There's no such need
+  // for deleting a variable, even if variable protection is employed.
+  //
+  if (  !DeleteFlag
+     && (CacheVariable->CurrPtr != NULL)
+     && (  (CacheVariable->CurrPtr->State == VAR_ADDED)
+        || (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))))
+  {
+    Status = UpdateVariableState (
+               Variable->CurrPtr,
+               CacheVariable->CurrPtr,
+               CacheVariable->CurrPtr->State & VAR_IN_DELETED_TRANSITION,
+               Variable->Volatile
+               );
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+  }
+
+  //
+  // Have enough space to store the variable?
+  //
+  Status = CheckVariableStoreSpace (
+             NewVariable,
+             VarSize,
+             VariableName,
+             VendorGuid,
+             Attributes,
+             VolatileFlag
+             );
+  if (Status == EFI_OUT_OF_RESOURCES) {
+    //
+    // Not a chance.
+    //
+    goto Done;
+  }
+
+  //
+  // Maybe not...
+  //
+  VarStoreBase = (VolatileFlag) ? VarGlobal->VolatileVariableBase
+                                : VarGlobal->NonVolatileVariableBase;
+  LastVariableOffset = (VolatileFlag)
+                        ? &mVariableModuleGlobal->VolatileLastVariableOffset
+                        : &mVariableModuleGlobal->NonVolatileLastVariableOffset;
+  if (!EFI_ERROR (Status)) {
+    //
+    // There's enough free space at the tail of variable storage.
+    //
+
+    //
+    // If non-volatile variable is protected, a separate variable (MetaDataHmacVar)
+    // is always updated along with current updating variable. The buffer pointed
+    // by NewVariable must have two variables. They should be written at this
+    // time orderly.
+    //
+    NextVariable     = NewVariable;
+    UpdatingVariable = NULL;
+    UpdateSize       = 0;
+    while (  !EFI_ERROR (Status)
+          && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize)
+    {
+      UpdatingVariable = NextVariable;
+      NextVariable     = GetNextVariablePtr (UpdatingVariable, VarGlobal->AuthFormat);
+      UpdateSize       = (UINTN)NextVariable - (UINTN)UpdatingVariable;
+
+      Status = WriteVariable (
+                 VarStoreBase,
+                 LastVariableOffset,
+                 &UpdatingVariable,
+                 (UINT32)UpdateSize,
+                 VolatileFlag,
+                 VarGlobal->AuthFormat
+                 );
+    }
+
+    //
+    // UpdatingVariable must point to the last written variable. Restore it to
+    // the first one so that we can calculate the offset in variable storage.
+    //
+    UpdatingVariable = (VARIABLE_HEADER *)((UINTN)UpdatingVariable + UpdateSize
+                                           - VarSize);
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+      mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;
+    } else {
+      mVariableModuleGlobal->CommonVariableTotalSize += VarSize;
+      if (IsCommonUserVariable) {
+        mVariableModuleGlobal->CommonUserVariableTotalSize += VarSize;
+      }
+    }
+
+    //
+    // Mark the old variable(s) as deleted.
+    //
+    if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
+      Status = DeleteVariable (
+                 VariableName,
+                 VendorGuid,
+                 Variable,
+                 CacheVariable,
+                 VolatileFlag
+                 );
+    }
+  } else {
+    //
+    // There's not enough space at the tail of variable storage but there's
+    // enough free space holes in the whole storage. Perform garbage collection
+    // & reclaim operation, and integrate the new variable at the same time.
+    //
+    Status = Reclaim (
+               VarStoreBase,
+               LastVariableOffset,
+               VolatileFlag,
+               Variable,
+               NewVariable,
+               VarSize
+               );
+
+    if (Variable->CurrPtr != NULL) {
+      UpdatingVariable = Variable->CurrPtr;
+    } else {
+      UpdatingVariable = (VARIABLE_HEADER *)(((UINTN)VarStoreBase + *LastVariableOffset) - VarSize);
+    }
+
+    if (EFI_ERROR (Status) &&
+        ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0))
+    {
+      //
+      // Out of space.
+      //
+      IsCommonUserVariable = IsUserVariable (NewVariable);
+      IsCommonVariable     = TRUE;
+
+      if (IsCommonUserVariable &&
+          ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize)
+           > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+      {
+        RecordVarErrorFlag (
+          VAR_ERROR_FLAG_USER_ERROR,
+          VariableName,
+          VendorGuid,
+          Attributes,
+          VarSize
+          );
+      }
+
+      if (IsCommonVariable &&
+          ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize)
+           > mVariableModuleGlobal->CommonVariableSpace))
+      {
+        RecordVarErrorFlag (
+          VAR_ERROR_FLAG_SYSTEM_ERROR,
+          VariableName,
+          VendorGuid,
+          Attributes,
+          VarSize
+          );
+      }
+    }
+  }
+
+Done:
+  if (!EFI_ERROR (Status)) {
+    if (!VolatileFlag) {
+      Offset = (UpdatingVariable != NULL) ? (UINTN)UpdatingVariable - (UINTN)VarStoreBase
+                                          : 0;
+      Status = ProtectedVariableLibWriteFinal (
+                 NewVariable,
+                 VarSize,
+                 Offset
+                 );
+      if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+        return Status;
+      }
+
+      Status = EFI_SUCCESS;
+    }
+
+    UpdateVariableInfo (
+      VariableName,
+      VendorGuid,
+      VolatileFlag,
+      FALSE,
+      TRUE,
+      FALSE,
+      FALSE,
+      &gVariableInfo
+      );
+    //
+    // HOB copy of the same variable is no longer needed, no matter it has
+    // been deleted, updated or added from/to real variable storage.
+    //
+    if (HobVarOnlyFlag || !VolatileFlag) {
+      FlushHobVariableToFlash (VariableName, VendorGuid);
+    }
+
+    if (!VolatileFlag) {
+      VolatileCacheInstance = &(VarGlobal->VariableRuntimeCacheContext.VariableRuntimeNvCache);
+    } else {
+      VolatileCacheInstance = &(VarGlobal->VariableRuntimeCacheContext.VariableRuntimeVolatileCache);
+    }
+
+    if (VolatileCacheInstance->Store != NULL) {
+      Status =  SynchronizeRuntimeVariableCache (
+                  VolatileCacheInstance,
+                  0,
+                  VolatileCacheInstance->Store->Size
+                  );
+      ASSERT_EFI_ERROR (Status);
+    }
+  } else if (Status == EFI_ALREADY_STARTED) {
+    //
+    // Meaning nothing needs to be done. Just return success.
+    //
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+
+  This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode, and datasize is external input.
+  This function will do basic validation, before parse the data.
+
+  @param VariableName               Name of Variable to be found.
+  @param VendorGuid                 Variable vendor GUID.
+  @param Attributes                 Attribute value of the variable found.
+  @param DataSize                   Size of Data found. If size is less than the
+                                    data, this value contains the required size.
+  @param Data                       The buffer to return the contents of the variable. May be NULL
+                                    with a zero DataSize in order to determine the size buffer needed.
+
+  @return EFI_INVALID_PARAMETER     Invalid parameter.
+  @return EFI_SUCCESS               Find the specified variable.
+  @return EFI_NOT_FOUND             Not found.
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetVariable (
+  IN      CHAR16    *VariableName,
+  IN      EFI_GUID  *VendorGuid,
+  OUT     UINT32    *Attributes OPTIONAL,
+  IN OUT  UINTN     *DataSize,
+  OUT     VOID      *Data OPTIONAL
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_POINTER_TRACK  Variable;
+
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableName[0] == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+  if ((Variable.CurrPtr == NULL) || EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Get data and its size
+  //
+  if (!Variable.Volatile) {
+    //
+    // Currently only non-volatile variable needs protection.
+    //
+    Status = ProtectedVariableLibGetByBuffer (
+               Variable.CurrPtr,
+               Data,
+               (UINT32 *)DataSize,
+               mVariableModuleGlobal->VariableGlobal.AuthFormat
+               );
+  }
+
+  if (Variable.Volatile || (Status == EFI_UNSUPPORTED)) {
+    Status = GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSize, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  }
+
+  if (!EFI_ERROR (Status)) {
+    UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo);
+  }
+
+Done:
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
+    if ((Attributes != NULL) && (Variable.CurrPtr != NULL)) {
+      *Attributes = Variable.CurrPtr->Attributes;
+    }
+  }
+
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+  return Status;
+}
+
+/**
+
+  This code Finds the Next available variable.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param VariableNameSize           The size of the VariableName buffer. The size must be large
+                                    enough to fit input string supplied in VariableName buffer.
+  @param VariableName               Pointer to variable name.
+  @param VendorGuid                 Variable Vendor Guid.
+
+  @retval EFI_SUCCESS               The function completed successfully.
+  @retval EFI_NOT_FOUND             The next variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL      The VariableNameSize is too small for the result.
+                                    VariableNameSize has been updated with the size needed to complete the request.
+  @retval EFI_INVALID_PARAMETER     VariableNameSize is NULL.
+  @retval EFI_INVALID_PARAMETER     VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER     VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER     The input values of VariableName and VendorGuid are not a name and
+                                    GUID of an existing variable.
+  @retval EFI_INVALID_PARAMETER     Null-terminator is not found in the first VariableNameSize bytes of
+                                    the input VariableName buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableName (
+  IN OUT  UINTN     *VariableNameSize,
+  IN OUT  CHAR16    *VariableName,
+  IN OUT  EFI_GUID  *VendorGuid
+  )
+{
+  EFI_STATUS             Status;
+  UINTN                  MaxLen;
+  UINTN                  VarNameSize;
+  BOOLEAN                AuthFormat;
+  VARIABLE_HEADER        *VariablePtr;
+  VARIABLE_STORE_HEADER  *VariableStoreHeader[VariableStoreTypeMax];
+
+  if ((VariableNameSize == NULL) || (VariableName == NULL) || (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  //
+  // Calculate the possible maximum length of name string, including the Null terminator.
+  //
+  MaxLen = *VariableNameSize / sizeof (CHAR16);
+  if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
+    //
+    // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
+    // follow spec to return EFI_INVALID_PARAMETER.
+    //
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  //
+  // 0: Volatile, 1: HOB, 2: Non-Volatile.
+  // The index and attributes mapping must be kept in this order as FindVariable
+  // makes use of this mapping to implement search algorithm.
+  //
+  VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+  VariableStoreHeader[VariableStoreTypeHob]      = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+  VariableStoreHeader[VariableStoreTypeNv]       = mNvVariableCache;
+
+  Status =  VariableServiceGetNextVariableInternal (
+              VariableName,
+              VendorGuid,
+              VariableStoreHeader,
+              &VariablePtr,
+              AuthFormat
+              );
+  if (!EFI_ERROR (Status)) {
+    VarNameSize = NameSizeOfVariable (VariablePtr, AuthFormat);
+    ASSERT (VarNameSize != 0);
+    if (VarNameSize <= *VariableNameSize) {
+      CopyMem (
+        VariableName,
+        GetVariableNamePtr (VariablePtr, AuthFormat),
+        VarNameSize
+        );
+      CopyMem (
+        VendorGuid,
+        GetVendorGuidPtr (VariablePtr, AuthFormat),
+        sizeof (EFI_GUID)
+        );
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_BUFFER_TOO_SMALL;
+    }
+
+    *VariableNameSize = VarNameSize;
+  }
+
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+  return Status;
+}
+
+/**
+
+  This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode, and datasize and data are external input.
+  This function will do basic validation, before parse the data.
+  This function will parse the authentication carefully to avoid security issues, like
+  buffer overflow, integer overflow.
+  This function will check attribute carefully to avoid authentication bypass.
+
+  @param VariableName                     Name of Variable to be found.
+  @param VendorGuid                       Variable vendor GUID.
+  @param Attributes                       Attribute value of the variable found
+  @param DataSize                         Size of Data found. If size is less than the
+                                          data, this value contains the required size.
+  @param Data                             Data pointer.
+
+  @return EFI_INVALID_PARAMETER           Invalid parameter.
+  @return EFI_SUCCESS                     Set successfully.
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
+  @return EFI_NOT_FOUND                   Not found.
+  @return EFI_WRITE_PROTECTED             Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceSetVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  VARIABLE_POINTER_TRACK  Variable;
+  EFI_STATUS              Status;
+  VARIABLE_HEADER         *NextVariable;
+  EFI_PHYSICAL_ADDRESS    Point;
+  UINTN                   PayloadSize;
+  BOOLEAN                 AuthFormat;
+
+  AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  //
+  // Check input parameters.
+  //
+  if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((DataSize != 0) && (Data == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check for reserverd bit in variable attribute.
+  // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
+  // the delete operation of common authenticated variable at user physical presence.
+  // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
+  //
+  if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if the combination of attribute bits is valid.
+  //
+  if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+    //
+    // Make sure if runtime bit is set, boot service bit is set also.
+    //
+    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+      return EFI_UNSUPPORTED;
+    } else {
+      return EFI_INVALID_PARAMETER;
+    }
+  } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {
+    //
+    // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid
+    //
+    return EFI_INVALID_PARAMETER;
+  } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+    if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+      //
+      // Not support authenticated variable write.
+      //
+      return EFI_INVALID_PARAMETER;
+    }
+  } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+    if (PcdGet32 (PcdHwErrStorageSize) == 0) {
+      //
+      // Not support harware error record variable variable.
+      //
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
+  // cannot be set both.
+  //
+  if (  ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+     && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS))
+  {
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
+    //
+    //  If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
+    //  Maybe it's the delete operation of common authenticated variable at user physical presence.
+    //
+    if (DataSize != AUTHINFO_SIZE) {
+      return EFI_UNSUPPORTED;
+    }
+
+    PayloadSize = DataSize - AUTHINFO_SIZE;
+  } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+    //
+    // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
+    //
+    if ((DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA) ||
+        (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo))) ||
+        (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
+    {
+      return EFI_SECURITY_VIOLATION;
+    }
+
+    //
+    // The VariableSpeculationBarrier() call here is to ensure the above sanity
+    // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
+    // before the execution of subsequent codes.
+    //
+    VariableSpeculationBarrier ();
+    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+  } else {
+    PayloadSize = DataSize;
+  }
+
+  if ((UINTN)(~0) - PayloadSize < StrSize (VariableName)) {
+    //
+    // Prevent whole variable size overflow
+    //
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  //  The size of the VariableName, including the Unicode Null in bytes plus
+  //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
+  //  bytes for HwErrRec#### variable.
+  //
+  if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+    if (StrSize (VariableName) + PayloadSize >
+        PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (AuthFormat))
+    {
+      return EFI_INVALID_PARAMETER;
+    }
+  } else {
+    //
+    //  The size of the VariableName, including the Unicode Null in bytes plus
+    //  the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
+    //
+    if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+      if (StrSize (VariableName) + PayloadSize >
+          mVariableModuleGlobal->MaxAuthVariableSize -
+          GetVariableHeaderSize (AuthFormat))
+      {
+        DEBUG ((
+          DEBUG_ERROR,
+          "%a: Failed to set variable '%s' with Guid %g\n",
+          __FUNCTION__,
+          VariableName,
+          VendorGuid
+          ));
+        DEBUG ((
+          DEBUG_ERROR,
+          "NameSize(0x%x) + PayloadSize(0x%x) > "
+          "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
+          StrSize (VariableName),
+          PayloadSize,
+          mVariableModuleGlobal->MaxAuthVariableSize,
+          GetVariableHeaderSize (AuthFormat)
+          ));
+        return EFI_INVALID_PARAMETER;
+      }
+    } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+      if (StrSize (VariableName) + PayloadSize >
+          mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (AuthFormat))
+      {
+        DEBUG ((
+          DEBUG_ERROR,
+          "%a: Failed to set variable '%s' with Guid %g\n",
+          __FUNCTION__,
+          VariableName,
+          VendorGuid
+          ));
+        DEBUG ((
+          DEBUG_ERROR,
+          "NameSize(0x%x) + PayloadSize(0x%x) > "
+          "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
+          StrSize (VariableName),
+          PayloadSize,
+          mVariableModuleGlobal->MaxVariableSize,
+          GetVariableHeaderSize (AuthFormat)
+          ));
+        return EFI_INVALID_PARAMETER;
+      }
+    } else {
+      if (StrSize (VariableName) + PayloadSize >
+          mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (AuthFormat))
+      {
+        DEBUG ((
+          DEBUG_ERROR,
+          "%a: Failed to set variable '%s' with Guid %g\n",
+          __FUNCTION__,
+          VariableName,
+          VendorGuid
+          ));
+        DEBUG ((
+          DEBUG_ERROR,
+          "NameSize(0x%x) + PayloadSize(0x%x) > "
+          "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
+          StrSize (VariableName),
+          PayloadSize,
+          mVariableModuleGlobal->MaxVolatileVariableSize,
+          GetVariableHeaderSize (AuthFormat)
+          ));
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+  }
+
+  //
+  // Special Handling for MOR Lock variable.
+  //
+  Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize));
+  if (Status == EFI_ALREADY_STARTED) {
+    //
+    // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
+    // Variable driver can just return SUCCESS.
+    //
+    return EFI_SUCCESS;
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize), mRequestSource);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  //
+  // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
+  //
+  if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
+    Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+    //
+    // Parse non-volatile variable data and get last variable offset.
+    //
+    NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
+    while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point), AuthFormat)) {
+      NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
+    }
+
+    mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)NextVariable - (UINTN)Point;
+  }
+
+  //
+  // Check whether the input variable is already existed.
+  //
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
+  if (!EFI_ERROR (Status)) {
+    if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
+      Status = EFI_WRITE_PROTECTED;
+      goto Done;
+    }
+
+    if ((Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes)) {
+      //
+      // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
+      // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
+      // 1. No access attributes specified
+      // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
+      //
+      Status = EFI_INVALID_PARAMETER;
+      DEBUG ((DEBUG_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
+      goto Done;
+    }
+  }
+
+  if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
+    //
+    // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
+    //
+    Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
+    if (EFI_ERROR (Status)) {
+      //
+      // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
+      //
+      goto Done;
+    }
+  }
+
+  if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+    Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
+  } else {
+    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
+  }
+
+Done:
+  InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  if (!AtRuntime ()) {
+    if (!EFI_ERROR (Status)) {
+      SecureBootHook (
+        VariableName,
+        VendorGuid
+        );
+    }
+  }
+
+  return Status;
+}
+
+/**
+
+  This code returns information about the EFI variables.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param Attributes                     Attributes bitmask to specify the type of variables
+                                        on which to return information.
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available
+                                        for the EFI variables associated with the attributes specified.
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available
+                                        for EFI variables associated with the attributes specified.
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables
+                                        associated with the attributes specified.
+
+  @return EFI_SUCCESS                   Query successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfoInternal (
+  IN  UINT32  Attributes,
+  OUT UINT64  *MaximumVariableStorageSize,
+  OUT UINT64  *RemainingVariableStorageSize,
+  OUT UINT64  *MaximumVariableSize
+  )
+{
+  VARIABLE_HEADER         *Variable;
+  VARIABLE_HEADER         *NextVariable;
+  UINT64                  VariableSize;
+  VARIABLE_STORE_HEADER   *VariableStoreHeader;
+  UINT64                  CommonVariableTotalSize;
+  UINT64                  HwErrVariableTotalSize;
+  EFI_STATUS              Status;
+  VARIABLE_POINTER_TRACK  VariablePtrTrack;
+
+  CommonVariableTotalSize = 0;
+  HwErrVariableTotalSize  = 0;
+
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+    //
+    // Query is Volatile related.
+    //
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+  } else {
+    //
+    // Query is Non-Volatile related.
+    //
+    VariableStoreHeader = mNvVariableCache;
+  }
+
+  //
+  // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
+  // with the storage size (excluding the storage header size).
+  //
+  *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
+
+  //
+  // Harware error record variable needs larger size.
+  //
+  if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+    *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
+    *MaximumVariableSize        =  PcdGet32 (PcdMaxHardwareErrorVariableSize) -
+                                  GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  } else {
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+      if (AtRuntime ()) {
+        *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
+      } else {
+        *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
+      }
+    }
+
+    //
+    // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
+    //
+    if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+      *MaximumVariableSize =  mVariableModuleGlobal->MaxAuthVariableSize -
+                             GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+      *MaximumVariableSize =  mVariableModuleGlobal->MaxVariableSize -
+                             GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    } else {
+      *MaximumVariableSize =   mVariableModuleGlobal->MaxVolatileVariableSize -
+                             GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    }
+  }
+
+  //
+  // Point to the starting address of the variables.
+  //
+  Variable = GetStartPointer (VariableStoreHeader);
+
+  //
+  // Now walk through the related variable store.
+  //
+  while (IsValidVariableHeader (
+           Variable,
+           GetEndPointer (VariableStoreHeader),
+           mVariableModuleGlobal->VariableGlobal.AuthFormat
+           ))
+  {
+    NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;
+
+    if (AtRuntime ()) {
+      //
+      // We don't take the state of the variables in mind
+      // when calculating RemainingVariableStorageSize,
+      // since the space occupied by variables not marked with
+      // VAR_ADDED is not allowed to be reclaimed in Runtime.
+      //
+      if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+        HwErrVariableTotalSize += VariableSize;
+      } else {
+        CommonVariableTotalSize += VariableSize;
+      }
+    } else {
+      //
+      // Only care about Variables with State VAR_ADDED, because
+      // the space not marked as VAR_ADDED is reclaimable now.
+      //
+      if (Variable->State == VAR_ADDED) {
+        if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+          HwErrVariableTotalSize += VariableSize;
+        } else {
+          CommonVariableTotalSize += VariableSize;
+        }
+      } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+        //
+        // If it is a IN_DELETED_TRANSITION variable,
+        // and there is not also a same ADDED one at the same time,
+        // this IN_DELETED_TRANSITION variable is valid.
+        //
+        VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
+        VariablePtrTrack.EndPtr   = GetEndPointer (VariableStoreHeader);
+        Status                    = FindVariableEx (
+                                      GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+                                      GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+                                      FALSE,
+                                      &VariablePtrTrack,
+                                      mVariableModuleGlobal->VariableGlobal.AuthFormat
+                                      );
+        if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State != VAR_ADDED)) {
+          if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+            HwErrVariableTotalSize += VariableSize;
+          } else {
+            CommonVariableTotalSize += VariableSize;
+          }
+        }
+      }
+    }
+
+    //
+    // Go to the next one.
+    //
+    Variable = NextVariable;
+  }
+
+  if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
+  } else {
+    if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
+      *RemainingVariableStorageSize = 0;
+    } else {
+      *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
+    }
+  }
+
+  if (*RemainingVariableStorageSize < GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
+    *MaximumVariableSize = 0;
+  } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) <
+             *MaximumVariableSize
+             )
+  {
+    *MaximumVariableSize = *RemainingVariableStorageSize -
+                           GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  This code returns information about the EFI variables.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param Attributes                     Attributes bitmask to specify the type of variables
+                                        on which to return information.
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available
+                                        for the EFI variables associated with the attributes specified.
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available
+                                        for EFI variables associated with the attributes specified.
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables
+                                        associated with the attributes specified.
+
+  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.
+  @return EFI_SUCCESS                   Query successfully.
+  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfo (
+  IN  UINT32  Attributes,
+  OUT UINT64  *MaximumVariableStorageSize,
+  OUT UINT64  *RemainingVariableStorageSize,
+  OUT UINT64  *MaximumVariableSize
+  )
+{
+  EFI_STATUS  Status;
+
+  if ((MaximumVariableStorageSize == NULL) || (RemainingVariableStorageSize == NULL) || (MaximumVariableSize == NULL) || (Attributes == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+    //
+    //  Deprecated attribute, make this check as highest priority.
+    //
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
+    //
+    // Make sure the Attributes combination is supported by the platform.
+    //
+    return EFI_UNSUPPORTED;
+  } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {
+    //
+    // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid
+    //
+    return EFI_INVALID_PARAMETER;
+  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+    //
+    // Make sure if runtime bit is set, boot service bit is set also.
+    //
+    return EFI_INVALID_PARAMETER;
+  } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
+    //
+    // Make sure RT Attribute is set if we are in Runtime phase.
+    //
+    return EFI_INVALID_PARAMETER;
+  } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+    //
+    // Make sure Hw Attribute is set with NV.
+    //
+    return EFI_INVALID_PARAMETER;
+  } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+    if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+      //
+      // Not support authenticated variable write.
+      //
+      return EFI_UNSUPPORTED;
+    }
+  } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+    if (PcdGet32 (PcdHwErrStorageSize) == 0) {
+      //
+      // Not support harware error record variable variable.
+      //
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  Status = VariableServiceQueryVariableInfoInternal (
+             Attributes,
+             MaximumVariableStorageSize,
+             RemainingVariableStorageSize,
+             MaximumVariableSize
+             );
+
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+  return Status;
+}
+
+/**
+  This function reclaims variable storage if free size is below the threshold.
+
+  Caution: This function may be invoked at SMM mode.
+  Care must be taken to make sure not security issue.
+
+**/
+VOID
+ReclaimForOS (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  UINTN           RemainingCommonRuntimeVariableSpace;
+  UINTN           RemainingHwErrVariableSpace;
+  STATIC BOOLEAN  Reclaimed;
+
+  //
+  // This function will be called only once at EndOfDxe or ReadyToBoot event.
+  //
+  if (Reclaimed) {
+    return;
+  }
+
+  Reclaimed = TRUE;
+
+  Status = EFI_SUCCESS;
+
+  if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {
+    RemainingCommonRuntimeVariableSpace = 0;
+  } else {
+    RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
+  }
+
+  RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
+
+  //
+  // Check if the free area is below a threshold.
+  //
+  if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
+       (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
+      ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
+       (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))))
+  {
+    Status = Reclaim (
+               mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+               &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+               FALSE,
+               NULL,
+               NULL,
+               0
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+}
+
+/**
+  Get maximum variable size, covering both non-volatile and volatile variables.
+
+  @return Maximum variable size.
+
+**/
+UINTN
+GetMaxVariableSize (
+  VOID
+  )
+{
+  UINTN  MaxVariableSize;
+
+  MaxVariableSize = GetNonVolatileMaxVariableSize ();
+  //
+  // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
+  // the default zero value.
+  //
+  if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {
+    MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);
+  }
+
+  return MaxVariableSize;
+}
+
+/**
+  Flush the HOB variable to flash.
+
+  @param[in] VariableName       Name of variable has been updated or deleted.
+  @param[in] VendorGuid         Guid of variable has been updated or deleted.
+
+**/
+VOID
+FlushHobVariableToFlash (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_STORE_HEADER   *VariableStoreHeader;
+  VARIABLE_HEADER         *Variable;
+  VOID                    *VariableData;
+  VARIABLE_POINTER_TRACK  VariablePtrTrack;
+  BOOLEAN                 ErrorFlag;
+  BOOLEAN                 AuthFormat;
+
+  ErrorFlag  = FALSE;
+  AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  //
+  // Flush the HOB variable to flash.
+  //
+  if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+    //
+    // Set HobVariableBase to 0, it can avoid SetVariable to call back.
+    //
+    mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+    for ( Variable = GetStartPointer (VariableStoreHeader)
+          ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader), AuthFormat)
+          ; Variable = GetNextVariablePtr (Variable, AuthFormat)
+          )
+    {
+      if (Variable->State != VAR_ADDED) {
+        //
+        // The HOB variable has been set to DELETED state in local.
+        //
+        continue;
+      }
+
+      ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
+      if ((VendorGuid == NULL) || (VariableName == NULL) ||
+          !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthFormat)) ||
+          (StrCmp (VariableName, GetVariableNamePtr (Variable, AuthFormat)) != 0))
+      {
+        VariableData = GetVariableDataPtr (Variable, AuthFormat);
+        FindVariable (
+          GetVariableNamePtr (Variable, AuthFormat),
+          GetVendorGuidPtr (Variable, AuthFormat),
+          &VariablePtrTrack,
+          &mVariableModuleGlobal->VariableGlobal,
+          FALSE
+          );
+        Status = UpdateVariable (
+                   GetVariableNamePtr (Variable, AuthFormat),
+                   GetVendorGuidPtr (Variable, AuthFormat),
+                   VariableData,
+                   DataSizeOfVariable (Variable, AuthFormat),
+                   Variable->Attributes,
+                   0,
+                   0,
+                   &VariablePtrTrack,
+                   NULL
+                   );
+        DEBUG ((
+          DEBUG_INFO,
+          "Variable driver flush the HOB variable to flash: %g %s %r\n",
+          GetVendorGuidPtr (Variable, AuthFormat),
+          GetVariableNamePtr (Variable, AuthFormat),
+          Status
+          ));
+      } else {
+        //
+        // The updated or deleted variable is matched with this HOB variable.
+        // Don't break here because we will try to set other HOB variables
+        // since this variable could be set successfully.
+        //
+        Status = EFI_SUCCESS;
+      }
+
+      if (!EFI_ERROR (Status)) {
+        //
+        // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
+        // set the HOB variable to DELETED state in local.
+        //
+        DEBUG ((
+          DEBUG_INFO,
+          "Variable driver set the HOB variable to DELETED state in local: %g %s\n",
+          GetVendorGuidPtr (Variable, AuthFormat),
+          GetVariableNamePtr (Variable, AuthFormat)
+          ));
+        Variable->State &= VAR_DELETED;
+      } else {
+        ErrorFlag = TRUE;
+      }
+    }
+
+    if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store != NULL) {
+      Status =  SynchronizeRuntimeVariableCache (
+                  &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
+                  0,
+                  mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store->Size
+                  );
+      ASSERT_EFI_ERROR (Status);
+    }
+
+    if (ErrorFlag) {
+      //
+      // We still have HOB variable(s) not flushed in flash.
+      //
+      mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStoreHeader;
+    } else {
+      //
+      // All HOB variables have been flushed in flash.
+      //
+      DEBUG ((DEBUG_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));
+      if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete != NULL) {
+        *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = TRUE;
+      }
+
+      if (!AtRuntime ()) {
+        FreePool ((VOID *)VariableStoreHeader);
+      }
+    }
+  }
+}
+
+/**
+  Initializes variable write service.
+
+  @retval EFI_SUCCESS          Function successfully executed.
+  @retval Others               Fail to initialize the variable service.
+
+**/
+EFI_STATUS
+VariableWriteServiceInitialize (
+  VOID
+  )
+{
+  EFI_STATUS               Status;
+  UINTN                    Index;
+  UINT8                    Data;
+  VARIABLE_ENTRY_PROPERTY  *VariableEntry;
+
+  AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  //
+  // Check if the free area is really free.
+  //
+  for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {
+    Data = ((UINT8 *)mNvVariableCache)[Index];
+    if (Data != 0xff) {
+      //
+      // There must be something wrong in variable store, do reclaim operation.
+      //
+      Status = Reclaim (
+                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+                 FALSE,
+                 NULL,
+                 NULL,
+                 0
+                 );
+      if (EFI_ERROR (Status)) {
+        ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+        return Status;
+      }
+
+      break;
+    }
+  }
+
+  FlushHobVariableToFlash (NULL, NULL);
+
+  Status = EFI_SUCCESS;
+  ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));
+  if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+    //
+    // Authenticated variable initialize.
+    //
+    mAuthContextIn.StructSize          = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
+    mAuthContextIn.MaxAuthVariableSize =  mVariableModuleGlobal->MaxAuthVariableSize -
+                                         GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
+    if (!EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable support!\n"));
+      mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;
+      if (mAuthContextOut.AuthVarEntry != NULL) {
+        for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
+          VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
+          Status        = VarCheckLibVariablePropertySet (
+                            VariableEntry->Name,
+                            VariableEntry->Guid,
+                            &VariableEntry->VariableProperty
+                            );
+          ASSERT_EFI_ERROR (Status);
+        }
+      }
+    } else if (Status == EFI_UNSUPPORTED) {
+      DEBUG ((DEBUG_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
+      DEBUG ((DEBUG_INFO, "Variable driver will continue to work without auth variable support!\n"));
+      mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+      Status                                            = EFI_SUCCESS;
+    }
+  }
+
+  if (!EFI_ERROR (Status)) {
+    for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {
+      VariableEntry = &mVariableEntryProperty[Index];
+      Status        = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
+      ASSERT_EFI_ERROR (Status);
+    }
+  }
+
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+  //
+  // Initialize MOR Lock variable.
+  //
+  MorLockInit ();
+
+  return Status;
+}
+
+/**
+  Convert normal variable storage to the allocated auth variable storage.
+
+  @param[in]  NormalVarStorage  Pointer to the normal variable storage header
+
+  @retval the allocated auth variable storage
+**/
+VOID *
+ConvertNormalVarStorageToAuthVarStorage (
+  VARIABLE_STORE_HEADER  *NormalVarStorage
+  )
+{
+  VARIABLE_HEADER                *StartPtr;
+  UINT8                          *NextPtr;
+  VARIABLE_HEADER                *EndPtr;
+  UINTN                          AuthVarStorageSize;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthStartPtr;
+  VARIABLE_STORE_HEADER          *AuthVarStorage;
+
+  AuthVarStorageSize = sizeof (VARIABLE_STORE_HEADER);
+  //
+  // Set AuthFormat as FALSE for normal variable storage
+  //
+  mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;
+
+  //
+  // Calculate Auth Variable Storage Size
+  //
+  StartPtr = GetStartPointer (NormalVarStorage);
+  EndPtr   = GetEndPointer (NormalVarStorage);
+  while (StartPtr < EndPtr) {
+    if (StartPtr->State == VAR_ADDED) {
+      AuthVarStorageSize  = HEADER_ALIGN (AuthVarStorageSize);
+      AuthVarStorageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
+      AuthVarStorageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
+      AuthVarStorageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
+    }
+
+    StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  }
+
+  //
+  // Allocate Runtime memory for Auth Variable Storage
+  //
+  AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStorageSize);
+  ASSERT (AuthVarStorage != NULL);
+  if (AuthVarStorage == NULL) {
+    return NULL;
+  }
+
+  //
+  // Copy Variable from Normal storage to Auth storage
+  //
+  StartPtr     = GetStartPointer (NormalVarStorage);
+  EndPtr       = GetEndPointer (NormalVarStorage);
+  AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)GetStartPointer (AuthVarStorage);
+  while (StartPtr < EndPtr) {
+    if (StartPtr->State == VAR_ADDED) {
+      AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (AuthStartPtr);
+      //
+      // Copy Variable Header
+      //
+      AuthStartPtr->StartId    = StartPtr->StartId;
+      AuthStartPtr->State      = StartPtr->State;
+      AuthStartPtr->Attributes = StartPtr->Attributes;
+      AuthStartPtr->NameSize   = StartPtr->NameSize;
+      AuthStartPtr->DataSize   = StartPtr->DataSize;
+      CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);
+      //
+      // Copy Variable Name
+      //
+      NextPtr = (UINT8 *)(AuthStartPtr + 1);
+      CopyMem (
+        NextPtr,
+        GetVariableNamePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat),
+        AuthStartPtr->NameSize
+        );
+      //
+      // Copy Variable Data
+      //
+      NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);
+      CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), AuthStartPtr->DataSize);
+      //
+      // Go to next variable
+      //
+      AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)(NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));
+    }
+
+    StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  }
+
+  //
+  // Update Auth Storage Header
+  //
+  AuthVarStorage->Format = NormalVarStorage->Format;
+  AuthVarStorage->State  = NormalVarStorage->State;
+  AuthVarStorage->Size   = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
+  CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
+  ASSERT (AuthVarStorage->Size <= AuthVarStorageSize);
+
+  //
+  // Restore AuthFormat
+  //
+  mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;
+  return AuthVarStorage;
+}
+
+/**
+  Get HOB variable store.
+
+  @param[in] VariableGuid       NV variable store signature.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+GetHobVariableStore (
+  IN EFI_GUID  *VariableGuid
+  )
+{
+  VARIABLE_STORE_HEADER  *VariableStoreHeader;
+  UINT64                 VariableStoreLength;
+  EFI_HOB_GUID_TYPE      *GuidHob;
+  BOOLEAN                NeedConvertNormalToAuth;
+
+  //
+  // Make sure there is no more than one Variable HOB.
+  //
+  DEBUG_CODE_BEGIN ();
+  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+  if (GuidHob != NULL) {
+    if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+      DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
+      ASSERT (FALSE);
+    } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
+      DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
+      ASSERT (FALSE);
+    }
+  } else {
+    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+    if (GuidHob != NULL) {
+      if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
+        DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
+        ASSERT (FALSE);
+      }
+    }
+  }
+
+  DEBUG_CODE_END ();
+
+  //
+  // Combinations supported:
+  // 1. Normal NV variable store +
+  //    Normal HOB variable store
+  // 2. Auth NV variable store +
+  //    Auth HOB variable store
+  // 3. Auth NV variable store +
+  //    Normal HOB variable store (code will convert it to Auth Format)
+  //
+  NeedConvertNormalToAuth = FALSE;
+  GuidHob                 = GetFirstGuidHob (VariableGuid);
+  if ((GuidHob == NULL) && (VariableGuid == &gEfiAuthenticatedVariableGuid)) {
+    //
+    // Try getting it from normal variable HOB
+    //
+    GuidHob                 = GetFirstGuidHob (&gEfiVariableGuid);
+    NeedConvertNormalToAuth = TRUE;
+  }
+
+  if (GuidHob != NULL) {
+    VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
+    VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);
+    if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
+      if (!NeedConvertNormalToAuth) {
+        mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimeCopyPool ((UINTN)VariableStoreLength, (VOID *)VariableStoreHeader);
+      } else {
+        mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertNormalVarStorageToAuthVarStorage ((VOID *)VariableStoreHeader);
+      }
+
+      if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "HOB Variable Store header is corrupted!\n"));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initializes variable store area for non-volatile and volatile variable.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+  VOID
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_STORE_HEADER  *VolatileVariableStore;
+  UINTN                  ScratchSize;
+  EFI_GUID               *VariableGuid;
+
+  //
+  // Allocate runtime memory for variable driver global structure.
+  //
+  mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
+  if (mVariableModuleGlobal == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
+
+  //
+  // Init non-volatile variable store.
+  //
+  Status = InitNonVolatileVariableStore ();
+  if (EFI_ERROR (Status)) {
+    FreePool (mVariableModuleGlobal);
+    return Status;
+  }
+
+  //
+  // mVariableModuleGlobal->VariableGlobal.AuthFormat
+  // has been initialized in InitNonVolatileVariableStore().
+  //
+  if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+    DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable format!\n"));
+    //
+    // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
+    //
+    mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+    VariableGuid                                      = &gEfiAuthenticatedVariableGuid;
+  } else {
+    DEBUG ((DEBUG_INFO, "Variable driver will work without auth variable support!\n"));
+    mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+    VariableGuid                                      = &gEfiVariableGuid;
+  }
+
+  //
+  // Get HOB variable store.
+  //
+  Status = GetHobVariableStore (VariableGuid);
+  if (EFI_ERROR (Status)) {
+    if (mNvFvHeaderCache != NULL) {
+      FreePool (mNvFvHeaderCache);
+    }
+
+    FreePool (mVariableModuleGlobal);
+    return Status;
+  }
+
+  mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?
+                                                    PcdGet32 (PcdMaxVolatileVariableSize) :
+                                                    mVariableModuleGlobal->MaxVariableSize
+                                                    );
+  //
+  // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
+  //
+  ScratchSize                              = GetMaxVariableSize () * 2;
+  mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
+  VolatileVariableStore                    = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
+  if (VolatileVariableStore == NULL) {
+    if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+      FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+    }
+
+    if (mNvFvHeaderCache != NULL) {
+      FreePool (mNvFvHeaderCache);
+    }
+
+    FreePool (mVariableModuleGlobal);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
+
+  //
+  // Initialize Variable Specific Data.
+  //
+  mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VolatileVariableStore;
+  mVariableModuleGlobal->VolatileLastVariableOffset          = (UINTN)GetStartPointer (VolatileVariableStore) - (UINTN)VolatileVariableStore;
+
+  CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
+  VolatileVariableStore->Size      = PcdGet32 (PcdVariableStoreSize);
+  VolatileVariableStore->Format    = VARIABLE_STORE_FORMATTED;
+  VolatileVariableStore->State     = VARIABLE_STORE_HEALTHY;
+  VolatileVariableStore->Reserved  = 0;
+  VolatileVariableStore->Reserved1 = 0;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the proper fvb handle and/or fvb protocol by the given Flash address.
+
+  @param[in]  Address       The Flash address.
+  @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.
+  @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.
+
+**/
+EFI_STATUS
+GetFvbInfoByAddress (
+  IN  EFI_PHYSICAL_ADDRESS                Address,
+  OUT EFI_HANDLE                          *FvbHandle OPTIONAL,
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_HANDLE                          *HandleBuffer;
+  UINTN                               HandleCount;
+  UINTN                               Index;
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
+  EFI_FVB_ATTRIBUTES_2                Attributes;
+  UINTN                               BlockSize;
+  UINTN                               NumberOfBlocks;
+
+  HandleBuffer = NULL;
+  //
+  // Get all FVB handles.
+  //
+  Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Get the FVB to access variable store.
+  //
+  Fvb = NULL;
+  for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
+    Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
+    if (EFI_ERROR (Status)) {
+      Status = EFI_NOT_FOUND;
+      break;
+    }
+
+    //
+    // Ensure this FVB protocol supported Write operation.
+    //
+    Status = Fvb->GetAttributes (Fvb, &Attributes);
+    if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
+      continue;
+    }
+
+    //
+    // Compare the address and select the right one.
+    //
+    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    //
+    // Assume one FVB has one type of BlockSize.
+    //
+    Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
+      if (FvbHandle != NULL) {
+        *FvbHandle = HandleBuffer[Index];
+      }
+
+      if (FvbProtocol != NULL) {
+        *FvbProtocol = Fvb;
+      }
+
+      Status = EFI_SUCCESS;
+      break;
+    }
+  }
+
+  FreePool (HandleBuffer);
+
+  if (Fvb == NULL) {
+    Status = EFI_NOT_FOUND;
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c
new file mode 100644
index 000000000000..4595bf8c9d02
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c
@@ -0,0 +1,670 @@
+/** @file
+  Implement all four UEFI Runtime Variable services for the nonvolatile
+  and volatile storage space and install variable architecture protocol.
+
+Copyright (C) 2013, Red Hat, Inc.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+#include <Protocol/VariablePolicy.h>
+#include <Library/VariablePolicyLib.h>
+#include "VariableParsing.h"
+
+EFI_STATUS
+EFIAPI
+ProtocolIsVariablePolicyEnabled (
+  OUT BOOLEAN  *State
+  );
+
+EFI_HANDLE                      mHandle                      = NULL;
+EFI_EVENT                       mVirtualAddressChangeEvent   = NULL;
+VOID                            *mFtwRegistration            = NULL;
+VOID                            ***mVarCheckAddressPointer   = NULL;
+UINTN                           mVarCheckAddressPointerCount = 0;
+EDKII_VARIABLE_LOCK_PROTOCOL    mVariableLock                = { VariableLockRequestToLock };
+EDKII_VARIABLE_POLICY_PROTOCOL  mVariablePolicyProtocol      = {
+  EDKII_VARIABLE_POLICY_PROTOCOL_REVISION,
+  DisableVariablePolicy,
+  ProtocolIsVariablePolicyEnabled,
+  RegisterVariablePolicy,
+  DumpVariablePolicy,
+  LockVariablePolicy
+};
+EDKII_VAR_CHECK_PROTOCOL        mVarCheck = {
+  VarCheckRegisterSetVariableCheckHandler,
+  VarCheckVariablePropertySet,
+  VarCheckVariablePropertyGet
+};
+
+/**
+  Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+  Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData (
+  VOID
+  );
+
+/**
+  Return TRUE if ExitBootServices () has been called.
+
+  @retval TRUE If ExitBootServices () has been called.
+**/
+BOOLEAN
+AtRuntime (
+  VOID
+  )
+{
+  return EfiAtRuntime ();
+}
+
+/**
+  Initializes a basic mutual exclusion lock.
+
+  This function initializes a basic mutual exclusion lock to the released state
+  and returns the lock.  Each lock provides mutual exclusion access at its task
+  priority level.  Since there is no preemption or multiprocessor support in EFI,
+  acquiring the lock only consists of raising to the locks TPL.
+  If Lock is NULL, then ASSERT().
+  If Priority is not a valid TPL value, then ASSERT().
+
+  @param  Lock       A pointer to the lock data structure to initialize.
+  @param  Priority   EFI TPL is associated with the lock.
+
+  @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+  IN OUT EFI_LOCK  *Lock,
+  IN     EFI_TPL   Priority
+  )
+{
+  return EfiInitializeLock (Lock, Priority);
+}
+
+/**
+  Acquires lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function that will be removed when
+  EfiAcquireLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiAcquireLock() at boot time, and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  )
+{
+  if (!AtRuntime ()) {
+    EfiAcquireLock (Lock);
+  }
+}
+
+/**
+  Releases lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function which will be removed when
+  EfiReleaseLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiReleaseLock() at boot time and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  )
+{
+  if (!AtRuntime ()) {
+    EfiReleaseLock (Lock);
+  }
+}
+
+/**
+  Retrieve the Fault Tolerent Write protocol interface.
+
+  @param[out] FtwProtocol       The interface of Ftw protocol
+
+  @retval EFI_SUCCESS           The FTW protocol instance was found and returned in FtwProtocol.
+  @retval EFI_NOT_FOUND         The FTW protocol instance was not found.
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+GetFtwProtocol (
+  OUT VOID  **FtwProtocol
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Locate Fault Tolerent Write protocol
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiFaultTolerantWriteProtocolGuid,
+                  NULL,
+                  FtwProtocol
+                  );
+  return Status;
+}
+
+/**
+  Retrieve the FVB protocol interface by HANDLE.
+
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for
+                                reading, writing, and erasing the target block.
+  @param[out] FvBlock           The interface of FVB protocol
+
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+GetFvbByHandle (
+  IN  EFI_HANDLE                          FvBlockHandle,
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock
+  )
+{
+  //
+  // To get the FVB protocol interface on the handle
+  //
+  return gBS->HandleProtocol (
+                FvBlockHandle,
+                &gEfiFirmwareVolumeBlockProtocolGuid,
+                (VOID **)FvBlock
+                );
+}
+
+/**
+  Function returns an array of handles that support the FVB protocol
+  in a buffer allocated from pool.
+
+  @param[out]  NumberHandles    The number of handles returned in Buffer.
+  @param[out]  Buffer           A pointer to the buffer to return the requested
+                                array of  handles that support FVB protocol.
+
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of
+                                handles in Buffer was returned in NumberHandles.
+  @retval EFI_NOT_FOUND         No FVB handle was found.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+  OUT UINTN       *NumberHandles,
+  OUT EFI_HANDLE  **Buffer
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Locate all handles of Fvb protocol
+  //
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiFirmwareVolumeBlockProtocolGuid,
+                  NULL,
+                  NumberHandles,
+                  Buffer
+                  );
+  return Status;
+}
+
+/**
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+  It convers pointer to new virtual address.
+
+  @param  Event        Event whose notification function is being invoked.
+  @param  Context      Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableClassAddressChangeEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  UINTN  Index;
+
+  if (mVariableModuleGlobal->FvbInstance != NULL) {
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->GetBlockSize);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->GetAttributes);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->SetAttributes);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->Read);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->Write);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance->EraseBlocks);
+    EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance);
+  }
+
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->PlatformLangCodes);
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->LangCodes);
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->PlatformLang);
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+  EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal);
+  EfiConvertPointer (0x0, (VOID **)&mNvVariableCache);
+  EfiConvertPointer (0x0, (VOID **)&mNvFvHeaderCache);
+
+  if (mAuthContextOut.AddressPointer != NULL) {
+    for (Index = 0; Index < mAuthContextOut.AddressPointerCount; Index++) {
+      EfiConvertPointer (0x0, (VOID **)mAuthContextOut.AddressPointer[Index]);
+    }
+  }
+
+  if (mVarCheckAddressPointer != NULL) {
+    for (Index = 0; Index < mVarCheckAddressPointerCount; Index++) {
+      EfiConvertPointer (0x0, (VOID **)mVarCheckAddressPointer[Index]);
+    }
+  }
+}
+
+/**
+  Notification function of EVT_GROUP_READY_TO_BOOT event group.
+
+  This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
+  When the Boot Manager is about to load and execute a boot option, it reclaims variable
+  storage if free size is below the threshold.
+
+  @param  Event        Event whose notification function is being invoked.
+  @param  Context      Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+  EFI_EVENT  Event,
+  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  if (!mEndOfDxe) {
+    MorLockInitAtEndOfDxe ();
+
+    Status = LockVariablePolicy ();
+    ASSERT_EFI_ERROR (Status);
+    //
+    // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUID event is not signaled.
+    //
+    mEndOfDxe               = TRUE;
+    mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
+    //
+    // The initialization for variable quota.
+    //
+    InitializeVariableQuota ();
+  }
+
+  ReclaimForOS ();
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+    if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+      gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
+    } else {
+      gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
+    }
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+  This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+  @param  Event        Event whose notification function is being invoked.
+  @param  Context      Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnEndOfDxe (
+  EFI_EVENT  Event,
+  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "[Variable]END_OF_DXE is signaled\n"));
+  MorLockInitAtEndOfDxe ();
+  Status = LockVariablePolicy ();
+  ASSERT_EFI_ERROR (Status);
+  mEndOfDxe               = TRUE;
+  mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
+  //
+  // The initialization for variable quota.
+  //
+  InitializeVariableQuota ();
+  if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
+    ReclaimForOS ();
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Initializes variable write service for DXE.
+
+**/
+VOID
+VariableWriteServiceInitializeDxe (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = VariableWriteServiceInitialize ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
+  }
+
+  //
+  // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
+  // Secure Boot Policy Variable change. Record their initial value.
+  //
+  RecordSecureBootPolicyVarData ();
+
+  //
+  // Install the Variable Write Architectural protocol.
+  //
+  Status = gBS->InstallProtocolInterface (
+                  &mHandle,
+                  &gEfiVariableWriteArchProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  Fault Tolerant Write protocol notification event handler.
+
+  Non-Volatile variable write may needs FTW protocol to reclaim when
+  writting variable.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+FtwNotificationEvent (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;
+  EFI_PHYSICAL_ADDRESS                NvStorageVariableBase;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR     GcdDescriptor;
+  EFI_PHYSICAL_ADDRESS                BaseAddress;
+  UINT64                              Length;
+  EFI_PHYSICAL_ADDRESS                VariableStoreBase;
+  UINT64                              VariableStoreLength;
+  UINTN                               FtwMaxBlockSize;
+  UINT32                              NvStorageVariableSize;
+  UINT64                              NvStorageVariableSize64;
+
+  //
+  // Ensure FTW protocol is installed.
+  //
+  Status = GetFtwProtocol ((VOID **)&FtwProtocol);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  Status = GetVariableFlashNvStorageInfo (&NvStorageVariableBase, &NvStorageVariableSize64);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SafeUint64ToUint32 (NvStorageVariableSize64, &NvStorageVariableSize);
+  // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
+  ASSERT_EFI_ERROR (Status);
+
+  VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;
+
+  Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+  if (!EFI_ERROR (Status)) {
+    ASSERT (NvStorageVariableSize <= FtwMaxBlockSize);
+  }
+
+  //
+  // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
+  //
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+
+  //
+  // Find the proper FVB protocol for variable.
+  //
+  Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;
+
+  //
+  // Mark the variable storage region of the FLASH as RUNTIME.
+  //
+  VariableStoreLength = mNvVariableCache->Size;
+  BaseAddress         = VariableStoreBase & (~EFI_PAGE_MASK);
+  Length              = VariableStoreLength + (VariableStoreBase - BaseAddress);
+  Length              = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
+
+  Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_WARN, "Variable driver failed to get flash memory attribute.\n"));
+  } else {
+    if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == 0) {
+      Status = gDS->SetMemorySpaceAttributes (
+                      BaseAddress,
+                      Length,
+                      GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
+                      );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));
+      }
+    }
+  }
+
+  //
+  // Initializes variable write service after FTW was ready.
+  //
+  VariableWriteServiceInitializeDxe ();
+
+  //
+  // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again.
+  //
+  gBS->CloseEvent (Event);
+}
+
+/**
+  This API function returns whether or not the policy engine is
+  currently being enforced.
+
+  @param[out]   State       Pointer to a return value for whether the policy enforcement
+                            is currently enabled.
+
+  @retval     EFI_SUCCESS
+  @retval     Others        An error has prevented this command from completing.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtocolIsVariablePolicyEnabled (
+  OUT BOOLEAN  *State
+  )
+{
+  *State = IsVariablePolicyEnabled ();
+  return EFI_SUCCESS;
+}
+
+/**
+  Variable Driver main entry point. The Variable driver places the 4 EFI
+  runtime services in the EFI System Table and installs arch protocols
+  for variable read and write services being available. It also registers
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   ReadyToBootEvent;
+  EFI_EVENT   EndOfDxeEvent;
+
+  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
+
+  //
+  // Initialze protected variable service, if enabled.
+  //
+  ContextIn.StructSize    = sizeof (ContextIn);
+  ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+  ContextIn.FindVariableSmm     = NULL;
+  ContextIn.GetVariableInfo     = GetVariableInfo;
+  ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+  ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+  ContextIn.UpdateVariable      = VariableExLibUpdateVariable;
+
+  ContextIn.MaxVariableSize     = (UINT32)GetMaxVariableSize ();
+  ContextIn.VariableServiceUser = FromSmmModule;
+
+  Status = ProtectedVariableLibInitialize (&ContextIn);
+  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Status = VariableCommonInitialize ();
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mHandle,
+                  &gEdkiiVariableLockProtocolGuid,
+                  &mVariableLock,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mHandle,
+                  &gEdkiiVarCheckProtocolGuid,
+                  &mVarCheck,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  SystemTable->RuntimeServices->GetVariable         = VariableServiceGetVariable;
+  SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
+  SystemTable->RuntimeServices->SetVariable         = VariableServiceSetVariable;
+  SystemTable->RuntimeServices->QueryVariableInfo   = VariableServiceQueryVariableInfo;
+
+  //
+  // Now install the Variable Runtime Architectural protocol on a new handle.
+  //
+  Status = gBS->InstallProtocolInterface (
+                  &mHandle,
+                  &gEfiVariableArchProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+    //
+    // Register FtwNotificationEvent () notify function.
+    //
+    EfiCreateProtocolNotifyEvent (
+      &gEfiFaultTolerantWriteProtocolGuid,
+      TPL_CALLBACK,
+      FtwNotificationEvent,
+      (VOID *)SystemTable,
+      &mFtwRegistration
+      );
+  } else {
+    //
+    // Emulated non-volatile variable mode does not depend on FVB and FTW.
+    //
+    VariableWriteServiceInitializeDxe ();
+  }
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  VariableClassAddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &mVirtualAddressChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Register the event handling function to reclaim variable for OS usage.
+  //
+  Status = EfiCreateEventReadyToBootEx (
+             TPL_NOTIFY,
+             OnReadyToBoot,
+             NULL,
+             &ReadyToBootEvent
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Register the event handling function to set the End Of DXE flag.
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  OnEndOfDxe,
+                  NULL,
+                  &gEfiEndOfDxeEventGroupGuid,
+                  &EndOfDxeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  // Register and initialize the VariablePolicy engine.
+  Status = InitVariablePolicyLib (VariableServiceGetVariable);
+  ASSERT_EFI_ERROR (Status);
+  Status = VarCheckRegisterSetVariableCheckHandler (ValidateSetVariable);
+  ASSERT_EFI_ERROR (Status);
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mHandle,
+                  &gEdkiiVariablePolicyProtocolGuid,
+                  &mVariablePolicyProtocol,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c
new file mode 100644
index 000000000000..5904bcbff78a
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c
@@ -0,0 +1,417 @@
+/** @file
+  Provides variable driver extended services.
+
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+/**
+  Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.
+  If VariableName is an empty string, then we just return the first
+  qualified variable without comparing VariableName and VendorGuid.
+
+  @param[in]  VariableName          Name of the variable to be found.
+  @param[in]  VendorGuid            Variable vendor GUID to be found.
+  @param[out] AuthVariableInfo      Pointer to AUTH_VARIABLE_INFO structure for
+                                    output of the variable found.
+
+  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
+                                    while VendorGuid is NULL.
+  @retval EFI_SUCCESS               Variable successfully found.
+  @retval EFI_NOT_FOUND             Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindVariable (
+  IN  CHAR16              *VariableName,
+  IN  EFI_GUID            *VendorGuid,
+  OUT AUTH_VARIABLE_INFO  *AuthVariableInfo
+  )
+{
+  EFI_STATUS                     Status;
+  VARIABLE_POINTER_TRACK         Variable;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+
+  Status = FindVariable (
+             VariableName,
+             VendorGuid,
+             &Variable,
+             &mVariableModuleGlobal->VariableGlobal,
+             FALSE
+             );
+  if (EFI_ERROR (Status)) {
+    AuthVariableInfo->Data           = NULL;
+    AuthVariableInfo->DataSize       = 0;
+    AuthVariableInfo->Attributes     = 0;
+    AuthVariableInfo->PubKeyIndex    = 0;
+    AuthVariableInfo->MonotonicCount = 0;
+    AuthVariableInfo->TimeStamp      = NULL;
+    return Status;
+  }
+
+  AuthVariableInfo->NameSize     = NameSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->VariableName = GetVariableNamePtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->VendorGuid   = GetVendorGuidPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->DataSize     = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->Data         = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->Attributes   = Variable.CurrPtr->Attributes;
+  if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+    AuthVariable                     = (AUTHENTICATED_VARIABLE_HEADER *)Variable.CurrPtr;
+    AuthVariableInfo->PubKeyIndex    = AuthVariable->PubKeyIndex;
+    AuthVariableInfo->MonotonicCount = ReadUnaligned64 (&(AuthVariable->MonotonicCount));
+    AuthVariableInfo->TimeStamp      = &AuthVariable->TimeStamp;
+  }
+
+  CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+  VarInfo.Buffer        = Variable.CurrPtr;
+  VarInfo.PlainData     = NULL;
+  VarInfo.PlainDataSize = 0;
+  VarInfo.Flags.Auth    = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+  //
+  // In case the variable is encrypted.
+  //
+  Status = ProtectedVariableLibGetByInfo (&VarInfo);
+  if (!EFI_ERROR (Status)) {
+    if (VarInfo.PlainData != NULL) {
+      AuthVariableInfo->Data     = VarInfo.PlainData;
+      AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+  This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+  If VariableName is an empty string, then we just return the first
+  qualified variable without comparing VariableName and VendorGuid.
+
+  @param[in]  VariableName          Name of the variable to be found.
+  @param[in]  VendorGuid            Variable vendor GUID to be found.
+  @param[out] AuthVariableInfo      Pointer to AUTH_VARIABLE_INFO structure for
+                                    output of the next variable.
+
+  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
+                                    while VendorGuid is NULL.
+  @retval EFI_SUCCESS               Variable successfully found.
+  @retval EFI_NOT_FOUND             Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindNextVariable (
+  IN  CHAR16              *VariableName,
+  IN  EFI_GUID            *VendorGuid,
+  OUT AUTH_VARIABLE_INFO  *AuthVariableInfo
+  )
+{
+  EFI_STATUS                     Status;
+  VARIABLE_HEADER                *VariablePtr;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariablePtr;
+  VARIABLE_STORE_HEADER          *VariableStoreHeader[VariableStoreTypeMax];
+  PROTECTED_VARIABLE_INFO        VarInfo;
+
+  VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+  VariableStoreHeader[VariableStoreTypeHob]      = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+  VariableStoreHeader[VariableStoreTypeNv]       = mNvVariableCache;
+
+  Status = VariableServiceGetNextVariableInternal (
+             VariableName,
+             VendorGuid,
+             VariableStoreHeader,
+             &VariablePtr,
+             mVariableModuleGlobal->VariableGlobal.AuthFormat
+             );
+  if (EFI_ERROR (Status)) {
+    AuthVariableInfo->VariableName   = NULL;
+    AuthVariableInfo->VendorGuid     = NULL;
+    AuthVariableInfo->Data           = NULL;
+    AuthVariableInfo->DataSize       = 0;
+    AuthVariableInfo->Attributes     = 0;
+    AuthVariableInfo->PubKeyIndex    = 0;
+    AuthVariableInfo->MonotonicCount = 0;
+    AuthVariableInfo->TimeStamp      = NULL;
+    return Status;
+  }
+
+  AuthVariableInfo->NameSize     = NameSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->VendorGuid   = GetVendorGuidPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->DataSize     = DataSizeOfVariable (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->Data         = GetVariableDataPtr (VariablePtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+  AuthVariableInfo->Attributes   = VariablePtr->Attributes;
+  if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+    AuthVariablePtr                  = (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr;
+    AuthVariableInfo->PubKeyIndex    = AuthVariablePtr->PubKeyIndex;
+    AuthVariableInfo->MonotonicCount = ReadUnaligned64 (&(AuthVariablePtr->MonotonicCount));
+    AuthVariableInfo->TimeStamp      = &AuthVariablePtr->TimeStamp;
+  }
+
+  CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header));
+
+  VarInfo.Buffer        = VariablePtr;
+  VarInfo.PlainData     = NULL;
+  VarInfo.PlainDataSize = 0;
+
+  Status = ProtectedVariableLibGetByInfo (&VarInfo);
+  if (!EFI_ERROR (Status)) {
+    if (VarInfo.PlainData != NULL) {
+      AuthVariableInfo->Data     = VarInfo.PlainData;
+      AuthVariableInfo->DataSize = VarInfo.PlainDataSize;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update the variable region with Variable information.
+
+  @param[in] AuthVariableInfo       Pointer AUTH_VARIABLE_INFO structure for
+                                    input of the variable.
+
+  @retval EFI_SUCCESS               The update operation is success.
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateVariable (
+  IN AUTH_VARIABLE_INFO  *AuthVariableInfo
+  )
+{
+  VARIABLE_POINTER_TRACK  Variable;
+
+  FindVariable (AuthVariableInfo->VariableName, AuthVariableInfo->VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+  return UpdateVariable (
+           AuthVariableInfo->VariableName,
+           AuthVariableInfo->VendorGuid,
+           AuthVariableInfo->Data,
+           AuthVariableInfo->DataSize,
+           AuthVariableInfo->Attributes,
+           AuthVariableInfo->PubKeyIndex,
+           AuthVariableInfo->MonotonicCount,
+           &Variable,
+           AuthVariableInfo->TimeStamp
+           );
+}
+
+/**
+  Get scratch buffer.
+
+  @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+                                    the maximum supported buffer size, this value contains
+                                    the maximum supported buffer size as output.
+  @param[out]     ScratchBuffer     Pointer to scratch buffer address.
+
+  @retval EFI_SUCCESS       Get scratch buffer successfully.
+  @retval EFI_UNSUPPORTED   If input size is greater than the maximum supported buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibGetScratchBuffer (
+  IN OUT UINTN  *ScratchBufferSize,
+  OUT    VOID   **ScratchBuffer
+  )
+{
+  UINTN  MaxBufferSize;
+
+  MaxBufferSize = mVariableModuleGlobal->ScratchBufferSize;
+  if (*ScratchBufferSize > MaxBufferSize) {
+    *ScratchBufferSize = MaxBufferSize;
+    return EFI_UNSUPPORTED;
+  }
+
+  *ScratchBuffer = GetEndPointer ((VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is to check if the remaining variable space is enough to set
+  all Variables from argument list successfully. The purpose of the check
+  is to keep the consistency of the Variables to be in variable storage.
+
+  Note: Variables are assumed to be in same storage.
+  The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+  so follow the argument sequence to check the Variables.
+
+  @param[in] Attributes         Variable attributes for Variable entries.
+  @param ...                    The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+                                A NULL terminates the list. The VariableSize of
+                                VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+                                It will be changed to variable total size as output.
+
+  @retval TRUE                  Have enough variable space to set the Variables successfully.
+  @retval FALSE                 No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibCheckRemainingSpaceForConsistency (
+  IN UINT32  Attributes,
+  ...
+  )
+{
+  VA_LIST  Marker;
+  BOOLEAN  Return;
+
+  VA_START (Marker, Attributes);
+
+  Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
+
+  VA_END (Marker);
+
+  return Return;
+}
+
+/**
+  Return TRUE if at OS runtime.
+
+  @retval TRUE If at OS runtime.
+  @retval FALSE If at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibAtRuntime (
+  VOID
+  )
+{
+  return AtRuntime ();
+}
+
+/**
+  Update partial data of a variable on NV storage and/or cached copy.
+
+  @param[in]  VariableInfo  Pointer to a variable with detailed information.
+  @param[in]  Offset        Offset to write from.
+  @param[in]  Size          Size of data Buffer to update.
+  @param[in]  Buffer        Pointer to data buffer to update.
+
+  @retval EFI_SUCCESS             The variable data was updated successfully.
+  @retval EFI_UNSUPPORTED         If this function is called directly in runtime.
+  @retval EFI_INVALID_PARAMETER   If VariableInfo, Buffer or Size are not valid.
+  @retval Others                  Failed to update NV storage or variable cache.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateNvVariable (
+  IN  PROTECTED_VARIABLE_INFO  *VariableInfo,
+  IN  UINTN                    Offset,
+  IN  UINT32                   Size,
+  IN  UINT8                    *Buffer
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_GLOBAL         *Global;
+  VARIABLE_RUNTIME_CACHE  *CacheInstance;
+  VARIABLE_HEADER         *VariableCache;
+
+  if ((mVariableModuleGlobal == NULL) || (mNvVariableCache == NULL)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Flush the cache to store.
+  //
+  if (Size == (UINT32)-1) {
+    Status = FtwVariableSpace (
+               mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+               mNvVariableCache
+               );
+    if (  !EFI_ERROR (Status)
+       && (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0))
+    {
+      FlushHobVariableToFlash (NULL, NULL);
+      if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+        FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+        mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+      }
+    }
+
+    return Status;
+  }
+
+  if (  (VariableInfo == NULL)
+     || (VariableInfo->StoreIndex == VAR_INDEX_INVALID)
+     || (Buffer == NULL)
+     || (Size == 0))
+  {
+    ASSERT (VariableInfo != NULL);
+    ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+    ASSERT (Buffer != NULL);
+    ASSERT (Size != 0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Global = &mVariableModuleGlobal->VariableGlobal;
+
+  VariableCache = (VARIABLE_HEADER *)((UINTN)mNvVariableCache + (UINTN)VariableInfo->StoreIndex);
+
+  ASSERT (
+    StrCmp (
+      VariableInfo->Header.VariableName,
+      GetVariableNamePtr (VariableCache, Global->AuthFormat)
+      ) == 0
+    );
+  ASSERT (
+    CompareGuid (
+      VariableInfo->Header.VendorGuid,
+      GetVendorGuidPtr (VariableCache, Global->AuthFormat)
+      )
+    );
+
+  //
+  // Forcibly update part data of flash copy of the variable ...
+  //
+  Status =  UpdateVariableStore (
+              Global,
+              FALSE,
+              FALSE,
+              mVariableModuleGlobal->FvbInstance,
+              (UINTN)(Global->NonVolatileVariableBase + VariableInfo->StoreIndex + Offset),
+              Size,
+              Buffer
+              );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // ... as well as the local cached copy.
+  //
+  CopyMem ((VOID *)((UINTN)VariableCache + Offset), Buffer, Size);
+
+  //
+  // Sync remote cached copy.
+  //
+  CacheInstance = &Global->VariableRuntimeCacheContext.VariableRuntimeNvCache;
+  if (CacheInstance->Store != NULL) {
+    Status =  SynchronizeRuntimeVariableCache (
+                CacheInstance,
+                (UINTN)VariableInfo->StoreIndex + Offset,
+                Size
+                );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequestToLock.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequestToLock.c
new file mode 100644
index 000000000000..d849ee9ce292
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequestToLock.c
@@ -0,0 +1,96 @@
+/** @file
+  Temporary location of the RequestToLock shim code while projects
+  are moved to VariablePolicy. Should be removed when deprecated.
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/VariablePolicyLib.h>
+#include <Library/VariablePolicyHelperLib.h>
+#include <Protocol/VariableLock.h>
+
+/**
+  DEPRECATED. THIS IS ONLY HERE AS A CONVENIENCE WHILE PORTING.
+  Mark a variable that will become read-only after leaving the DXE phase of
+  execution. Write request coming from SMM environment through
+  EFI_SMM_VARIABLE_PROTOCOL is allowed.
+
+  @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.
+  @param[in] VariableName  A pointer to the variable name that will be made
+                           read-only subsequently.
+  @param[in] VendorGuid    A pointer to the vendor GUID that will be made
+                           read-only subsequently.
+
+  @retval EFI_SUCCESS           The variable specified by the VariableName and
+                                the VendorGuid was marked as pending to be
+                                read-only.
+  @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+                                Or VariableName is an empty string.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or
+                                EFI_EVENT_GROUP_READY_TO_BOOT has already been
+                                signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock
+                                request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL  *This,
+  IN CHAR16                              *VariableName,
+  IN EFI_GUID                            *VendorGuid
+  )
+{
+  EFI_STATUS             Status;
+  VARIABLE_POLICY_ENTRY  *NewPolicy;
+
+  DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! %a() will go away soon!\n", __FUNCTION__));
+  DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! Please move to use Variable Policy!\n"));
+  DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! Variable: %g %s\n", VendorGuid, VariableName));
+
+  NewPolicy = NULL;
+  Status    = CreateBasicVariablePolicy (
+                VendorGuid,
+                VariableName,
+                VARIABLE_POLICY_NO_MIN_SIZE,
+                VARIABLE_POLICY_NO_MAX_SIZE,
+                VARIABLE_POLICY_NO_MUST_ATTR,
+                VARIABLE_POLICY_NO_CANT_ATTR,
+                VARIABLE_POLICY_TYPE_LOCK_NOW,
+                &NewPolicy
+                );
+  if (!EFI_ERROR (Status)) {
+    Status = RegisterVariablePolicy (NewPolicy);
+
+    //
+    // If the error returned is EFI_ALREADY_STARTED, we need to check the
+    // current database for the variable and see whether it's locked. If it's
+    // locked, we're still fine, but also generate a DEBUG_WARN message so the
+    // duplicate lock can be removed.
+    //
+    if (Status == EFI_ALREADY_STARTED) {
+      Status = ValidateSetVariable (VariableName, VendorGuid, 0, 0, NULL);
+      if (Status == EFI_WRITE_PROTECTED) {
+        DEBUG ((DEBUG_WARN, "  Variable: %g %s is already locked!\n", VendorGuid, VariableName));
+        Status = EFI_SUCCESS;
+      } else {
+        DEBUG ((DEBUG_ERROR, "  Variable: %g %s can not be locked!\n", VendorGuid, VariableName));
+        Status = EFI_ACCESS_DENIED;
+      }
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", __FUNCTION__, VariableName, Status));
+  }
+
+  if (NewPolicy != NULL) {
+    FreePool (NewPolicy);
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.c
new file mode 100644
index 000000000000..32dd9901b260
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.c
@@ -0,0 +1,537 @@
+/** @file
+  Common variable non-volatile store routines.
+
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableNonVolatile.h"
+#include "VariableParsing.h"
+
+extern VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
+
+/**
+  Get non-volatile maximum variable size.
+
+  @return Non-volatile maximum variable size.
+
+**/
+UINTN
+GetNonVolatileMaxVariableSize (
+  VOID
+  )
+{
+  if (PcdGet32 (PcdHwErrStorageSize) != 0) {
+    return MAX (
+             MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),
+             PcdGet32 (PcdMaxHardwareErrorVariableSize)
+             );
+  } else {
+    return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));
+  }
+}
+
+/**
+  Init emulated non-volatile variable store.
+
+  @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+InitEmuNonVolatileVariableStore (
+  OUT EFI_PHYSICAL_ADDRESS  *VariableStoreBase
+  )
+{
+  VARIABLE_STORE_HEADER  *VariableStore;
+  UINT32                 VariableStoreLength;
+  BOOLEAN                FullyInitializeStore;
+  UINT32                 HwErrStorageSize;
+
+  FullyInitializeStore = TRUE;
+
+  VariableStoreLength = PcdGet32 (PcdVariableStoreSize);
+  ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
+
+  //
+  // Allocate memory for variable store.
+  //
+  if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {
+    VariableStore = (VARIABLE_STORE_HEADER *)AllocateRuntimePool (VariableStoreLength);
+    if (VariableStore == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // A memory location has been reserved for the NV variable store.  Certain
+    // platforms may be able to preserve a memory range across system resets,
+    // thereby providing better NV variable emulation.
+    //
+    VariableStore =
+      (VARIABLE_STORE_HEADER *)(VOID *)(UINTN)
+      PcdGet64 (PcdEmuVariableNvStoreReserved);
+    if ((VariableStore->Size == VariableStoreLength) &&
+        (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||
+         CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&
+        (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
+        (VariableStore->State == VARIABLE_STORE_HEALTHY))
+    {
+      DEBUG ((
+        DEBUG_INFO,
+        "Variable Store reserved at %p appears to be valid\n",
+        VariableStore
+        ));
+      FullyInitializeStore = FALSE;
+    }
+  }
+
+  if (FullyInitializeStore) {
+    SetMem (VariableStore, VariableStoreLength, 0xff);
+    //
+    // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
+    //
+    CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);
+    VariableStore->Size      = VariableStoreLength;
+    VariableStore->Format    = VARIABLE_STORE_FORMATTED;
+    VariableStore->State     = VARIABLE_STORE_HEALTHY;
+    VariableStore->Reserved  = 0;
+    VariableStore->Reserved1 = 0;
+  }
+
+  *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
+
+  HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
+
+  //
+  // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+  // is stored with common variable in the same NV region. So the platform integrator should
+  // ensure that the value of PcdHwErrStorageSize is less than the value of
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
+  //
+  ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
+
+  mVariableModuleGlobal->CommonVariableSpace        = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
+  mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
+  mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Create a dummy variable used to fill the gap in NV variable storage caused by
+  the invalid variables found in HMAC verification phase.
+
+  @param[out] Variable    Variable buffer.
+  @param[in]  Name        Variable Name.
+  @param[in]  Guid        Vendor GUID of the variable.
+  @param[in]  Size        Whole size of the variable requested.
+  @param[in]  AuthFlag    Variable format flag.
+
+**/
+STATIC
+VOID
+CreateDummyVariable (
+  OUT VARIABLE_HEADER  *Variable,
+  IN  CHAR16           *Name,
+  IN  EFI_GUID         *Guid,
+  IN  UINT32           Size,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  ASSERT (Variable != NULL);
+
+  if (Name == NULL) {
+    Name = L"Dummy";
+  }
+
+  if (AuthFlag) {
+    AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+    AuthVariable->StartId    = VARIABLE_DATA;
+    AuthVariable->State      = VAR_ADDED & VAR_DELETED;
+    AuthVariable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+    AuthVariable->NameSize   = (UINT32)StrSize (Name);
+    AuthVariable->DataSize   = Size - sizeof (AUTHENTICATED_VARIABLE_HEADER)
+                               - AuthVariable->NameSize;
+    if (Guid != NULL) {
+      CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof (EFI_GUID));
+    }
+
+    CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, AuthVariable->NameSize);
+  } else {
+    Variable->StartId    = VARIABLE_DATA;
+    Variable->State      = VAR_ADDED & VAR_DELETED;
+    Variable->Attributes = EFI_VARIABLE_NON_VOLATILE;
+    Variable->NameSize   = (UINT32)StrSize (Name);
+    Variable->DataSize   = Size - sizeof (VARIABLE_HEADER) - Variable->NameSize;
+    if (Guid != NULL) {
+      CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof (EFI_GUID));
+    }
+
+    CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, Variable->NameSize);
+  }
+}
+
+/**
+
+  Init protected variable store.
+
+  @param[in, out]  VariableStore  Pointer to real protected variable store base.
+
+**/
+EFI_STATUS
+InitProtectedVariableStore (
+  IN  OUT VARIABLE_STORE_HEADER  *VariableStore
+  )
+{
+  EFI_STATUS               Status;
+  PROTECTED_VARIABLE_INFO  VarInfo;
+  UINTN                    Size;
+  UINTN                    Index;
+  BOOLEAN                  AuthFlag;
+  EFI_PHYSICAL_ADDRESS     NextVariableStore;
+  EFI_PHYSICAL_ADDRESS     *VarList;
+  UINTN                    NumVars;
+  UINTN                    CurrVar;
+
+  SetMem (
+    (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER),
+    VariableStore->Size - sizeof (VARIABLE_STORE_HEADER),
+    0xFF
+    );
+  Index = sizeof (VARIABLE_STORE_HEADER);
+
+  VarList = NULL;
+  NumVars = 0;
+  ProtectedVariableLibGetSortedList (&VarList, &NumVars);
+
+  //
+  // Search variable in the order of StoreIndex
+  //
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+
+  for (CurrVar = 0; CurrVar < NumVars; CurrVar++) {
+    VarInfo.Buffer     = NULL;
+    VarInfo.StoreIndex = VarList[CurrVar];
+    if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+      break;
+    }
+
+    Status = ProtectedVariableLibFind (&VarInfo);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    ASSERT (VarInfo.Buffer != NULL);
+
+    AuthFlag = VarInfo.Flags.Auth;
+    if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+      continue;
+    } else {
+      ASSERT (VarInfo.StoreIndex == HEADER_ALIGN (VarInfo.StoreIndex));
+      ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof (VARIABLE_STORE_HEADER)));
+      ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHeaderSize (AuthFlag));
+    }
+
+    //
+    // Fill gap caused by invalid variable.
+    //
+    if (VarInfo.StoreIndex > Index) {
+      Size = (UINTN)VarInfo.StoreIndex - Index;
+      CreateDummyVariable (
+        (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index),
+        NULL,
+        NULL,
+        (UINT32)Size,
+        AuthFlag
+        );
+      Index += Size;
+    }
+
+    Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+           - (UINTN)VarInfo.Buffer;
+    CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer, Size);
+
+    Index += Size;
+    Index  = HEADER_ALIGN (Index);
+
+    NextVariableStore = (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore + VarInfo.StoreIndex + Size);
+  }
+
+  //
+  // Search variable in the order of StoreIndex
+  //
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+  for ( ; CurrVar < NumVars; CurrVar++) {
+    VarInfo.Buffer     = NULL;
+    VarInfo.StoreIndex = VarList[CurrVar];
+    Status             = ProtectedVariableLibFind (&VarInfo);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    ASSERT (VarInfo.Buffer != NULL);
+
+    AuthFlag = VarInfo.Flags.Auth;
+    if (VarInfo.StoreIndex == VAR_INDEX_INVALID) {
+      Size = (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag)
+             - (UINTN)VarInfo.Buffer;
+      CopyMem ((VOID *)(UINTN)NextVariableStore, VarInfo.Buffer, Size);
+      Status            = ProtectedVariableLibRefresh (VarInfo.Buffer, 0, NextVariableStore - (UINTN)VariableStore, FALSE);
+      NextVariableStore = NextVariableStore + Size;
+    }
+  }
+
+  if (Status == EFI_UNSUPPORTED) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Init real non-volatile variable store.
+
+  @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+  @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitRealNonVolatileVariableStore (
+  OUT EFI_PHYSICAL_ADDRESS  *VariableStoreBase
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
+  VARIABLE_STORE_HEADER                 *VariableStore;
+  UINT32                                VariableStoreLength;
+  EFI_HOB_GUID_TYPE                     *GuidHob;
+  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
+  UINT8                                 *NvStorageData;
+  UINT32                                NvStorageSize;
+  UINT64                                NvStorageSize64;
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
+  UINT32                                BackUpOffset;
+  UINT32                                BackUpSize;
+  UINT32                                HwErrStorageSize;
+  UINT32                                MaxUserNvVariableSpaceSize;
+  UINT32                                BoottimeReservedNvVariableSpaceSize;
+  EFI_STATUS                            Status;
+  VOID                                  *FtwProtocol;
+
+  mVariableModuleGlobal->FvbInstance = NULL;
+
+  Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);
+  // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
+  ASSERT_EFI_ERROR (Status);
+
+  ASSERT (NvStorageBase != 0);
+
+  //
+  // Allocate runtime memory used for a memory copy of the FLASH region.
+  // Keep the memory and the FLASH in sync as updates occur.
+  //
+  NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
+  if (NvStorageData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Copy NV storage data to the memory buffer.
+  //
+  CopyMem (NvStorageData, (UINT8 *)(UINTN)NvStorageBase, NvStorageSize);
+
+  Status = GetFtwProtocol ((VOID **)&FtwProtocol);
+  //
+  // If FTW protocol has been installed, no need to check FTW last write data hob.
+  //
+  if (EFI_ERROR (Status)) {
+    //
+    // Check the FTW last write data hob.
+    //
+    GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+    if (GuidHob != NULL) {
+      FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
+      if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+        DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));
+        //
+        // Copy the backed up NV storage data to the memory buffer from spare block.
+        //
+        CopyMem (NvStorageData, (UINT8 *)(UINTN)(FtwLastWriteData->SpareAddress), NvStorageSize);
+      } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
+                 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize)))
+      {
+        //
+        // Flash NV storage from the Offset is backed up in spare block.
+        //
+        BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);
+        BackUpSize   = NvStorageSize - BackUpOffset;
+        DEBUG ((DEBUG_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress));
+        //
+        // Copy the partial backed up NV storage data to the memory buffer from spare block.
+        //
+        CopyMem (NvStorageData + BackUpOffset, (UINT8 *)(UINTN)FtwLastWriteData->SpareAddress, BackUpSize);
+      }
+    }
+  }
+
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvStorageData;
+
+  //
+  // Check if the Firmware Volume is not corrupted
+  //
+  if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
+    FreePool (NvStorageData);
+    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  VariableStore       = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+  VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;
+  ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
+  ASSERT (VariableStore->Size == VariableStoreLength);
+
+  //
+  // Check if the Variable Store header is not corrupted
+  //
+  if (GetVariableStoreStatus (VariableStore) != EfiValid) {
+    FreePool (NvStorageData);
+    DEBUG ((DEBUG_ERROR, "Variable Store header is corrupted\n"));
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  //
+  // Overwrite the store with verified copy of protected variables, if enabled.
+  //
+  Status = InitProtectedVariableStore (VariableStore);
+  if ((Status != EFI_SUCCESS) && (Status != EFI_UNSUPPORTED)) {
+    FreePool (NvStorageData);
+    DEBUG ((DEBUG_ERROR, "Variable integrity might have been compromised\n"));
+    return Status;
+  }
+
+  mNvFvHeaderCache = FvHeader;
+
+  *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
+
+  HwErrStorageSize                    = PcdGet32 (PcdHwErrStorageSize);
+  MaxUserNvVariableSpaceSize          = PcdGet32 (PcdMaxUserNvVariableSpaceSize);
+  BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);
+
+  //
+  // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+  // is stored with common variable in the same NV region. So the platform integrator should
+  // ensure that the value of PcdHwErrStorageSize is less than the value of
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
+  //
+  ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
+  //
+  // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
+  //
+  ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
+  //
+  // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
+  // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
+  //
+  ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
+
+  mVariableModuleGlobal->CommonVariableSpace        = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
+  mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);
+  mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "Variable driver common space: 0x%x 0x%x 0x%x\n",
+    mVariableModuleGlobal->CommonVariableSpace,
+    mVariableModuleGlobal->CommonMaxUserVariableSpace,
+    mVariableModuleGlobal->CommonRuntimeVariableSpace
+    ));
+
+  //
+  // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
+  //
+  ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Init non-volatile variable store.
+
+  @retval EFI_SUCCESS           Function successfully executed.
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
+  @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+  VOID
+  )
+{
+  VARIABLE_HEADER       *Variable;
+  VARIABLE_HEADER       *NextVariable;
+  EFI_PHYSICAL_ADDRESS  VariableStoreBase;
+  UINTN                 VariableSize;
+  EFI_STATUS            Status;
+
+  if (PcdGetBool (PcdEmuVariableNvModeEnable)) {
+    Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;
+    DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));
+  } else {
+    Status = InitRealNonVolatileVariableStore (&VariableStoreBase);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;
+  }
+
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+  mNvVariableCache                                              = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
+  mVariableModuleGlobal->VariableGlobal.AuthFormat              = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));
+
+  mVariableModuleGlobal->MaxVariableSize     = PcdGet32 (PcdMaxVariableSize);
+  mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);
+
+  //
+  // Parse non-volatile variable data and get last variable offset.
+  //
+  Variable = GetStartPointer (mNvVariableCache);
+  while (IsValidVariableHeader (
+           Variable,
+           GetEndPointer (mNvVariableCache),
+           mVariableModuleGlobal->VariableGlobal.AuthFormat
+           ))
+  {
+    NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
+    VariableSize = (UINTN)NextVariable - (UINTN)Variable;
+    if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+      mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+    } else {
+      mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+    }
+
+    Variable = NextVariable;
+  }
+
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)Variable - (UINTN)mNvVariableCache;
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
new file mode 100644
index 000000000000..be3f59341c1e
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
@@ -0,0 +1,1110 @@
+/** @file
+  Functions in this module are associated with variable parsing operations and
+  are intended to be usable across variable driver source files.
+
+Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableParsing.h"
+
+/**
+
+  This code checks if variable header is valid or not.
+
+  @param[in] Variable           Pointer to the Variable Header.
+  @param[in] VariableStoreEnd   Pointer to the Variable Store End.
+  @param[in] AuthFormat         TRUE indicates authenticated variables are used.
+                                FALSE indicates authenticated variables are not used.
+
+  @retval TRUE              Variable header is valid.
+  @retval FALSE             Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  VARIABLE_HEADER  *VariableStoreEnd,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  if (  (Variable == NULL)
+     || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >= (UINTN)VariableStoreEnd)
+     || (Variable->StartId != VARIABLE_DATA))
+  {
+    //
+    // Variable is NULL or has reached the end of variable store,
+    // or the StartId is not correct.
+    //
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+
+  This code gets the current status of Variable Store.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @retval EfiRaw         Variable store status is raw.
+  @retval EfiValid       Variable store status is valid.
+  @retval EfiInvalid     Variable store status is invalid.
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  )
+{
+  if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+       CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+      (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
+      (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)
+      )
+  {
+    return EfiValid;
+  } else if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&
+             (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&
+             (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&
+             (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&
+             (VarStoreHeader->Size == 0xffffffff) &&
+             (VarStoreHeader->Format == 0xff) &&
+             (VarStoreHeader->State == 0xff)
+             )
+  {
+    return EfiRaw;
+  } else {
+    return EfiInvalid;
+  }
+}
+
+/**
+  This code gets the size of variable header.
+
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+  @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+  IN  BOOLEAN  AuthFormat
+  )
+{
+  UINTN  Value;
+
+  if (AuthFormat) {
+    Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+  } else {
+    Value = sizeof (VARIABLE_HEADER);
+  }
+
+  return Value;
+}
+
+/**
+
+  This code gets the size of name of variable.
+
+  @param[in]  Variable      Pointer to the variable header.
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+  @return UINTN          Size of variable in bytes.
+
+**/
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFormat) {
+    if ((AuthVariable->State == (UINT8)(-1)) ||
+        (AuthVariable->DataSize == (UINT32)(-1)) ||
+        (AuthVariable->NameSize == (UINT32)(-1)) ||
+        (AuthVariable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)AuthVariable->NameSize;
+  } else {
+    if ((Variable->State == (UINT8)(-1)) ||
+        (Variable->DataSize == (UINT32)(-1)) ||
+        (Variable->NameSize == (UINT32)(-1)) ||
+        (Variable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)Variable->NameSize;
+  }
+}
+
+/**
+  This code sets the size of name of variable.
+
+  @param[in]  Variable      Pointer to the Variable Header.
+  @param[in]  NameSize      Name size to set.
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetNameSizeOfVariable (
+  IN VARIABLE_HEADER  *Variable,
+  IN UINTN            NameSize,
+  IN BOOLEAN          AuthFormat
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFormat) {
+    AuthVariable->NameSize = (UINT32)NameSize;
+  } else {
+    Variable->NameSize = (UINT32)NameSize;
+  }
+}
+
+/**
+
+  This code gets the size of variable data.
+
+  @param[in]  Variable      Pointer to the Variable Header.
+  @param[in]  AuthFormat    TRUE indicates authenticated variables are used.
+                            FALSE indicates authenticated variables are not used.
+
+  @return Size of variable in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFormat) {
+    if ((AuthVariable->State == (UINT8)(-1)) ||
+        (AuthVariable->DataSize == (UINT32)(-1)) ||
+        (AuthVariable->NameSize == (UINT32)(-1)) ||
+        (AuthVariable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)AuthVariable->DataSize;
+  } else {
+    if ((Variable->State == (UINT8)(-1)) ||
+        (Variable->DataSize == (UINT32)(-1)) ||
+        (Variable->NameSize == (UINT32)(-1)) ||
+        (Variable->Attributes == (UINT32)(-1)))
+    {
+      return 0;
+    }
+
+    return (UINTN)Variable->DataSize;
+  }
+}
+
+/**
+  This code sets the size of variable data.
+
+  @param[in] Variable   Pointer to the Variable Header.
+  @param[in] DataSize   Data size to set.
+  @param[in] AuthFormat TRUE indicates authenticated variables are used.
+                        FALSE indicates authenticated variables are not used.
+
+**/
+VOID
+SetDataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  UINTN            DataSize,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFormat) {
+    AuthVariable->DataSize = (UINT32)DataSize;
+  } else {
+    Variable->DataSize = (UINT32)DataSize;
+  }
+}
+
+/**
+
+  This code gets the pointer to the variable name.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFormat));
+}
+
+/**
+  This code gets the pointer to the variable guid.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFormat) {
+    return &AuthVariable->VendorGuid;
+  } else {
+    return &Variable->VendorGuid;
+  }
+}
+
+/**
+
+  This code gets the pointer to the variable data.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  UINTN  Value;
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFormat);
+  Value += NameSizeOfVariable (Variable, AuthFormat);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat));
+
+  return (UINT8 *)Value;
+}
+
+/**
+  This code gets the variable data offset related to variable header.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Variable Data offset.
+
+**/
+UINTN
+GetVariableDataOffset (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  UINTN  Value;
+
+  //
+  // Be careful about pad size for alignment
+  //
+  Value  = GetVariableHeaderSize (AuthFormat);
+  Value += NameSizeOfVariable (Variable, AuthFormat);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat));
+
+  return Value;
+}
+
+/**
+  Get variable data payload.
+
+  @param[in]      Variable     Pointer to the Variable Header.
+  @param[in,out]  Data         Pointer to buffer used to store the variable data.
+  @param[in,out]  DataSize     Size of buffer passed by Data.
+                               Size of data copied into Data buffer.
+  @param[in]      AuthFlag     Auth-variable indicator.
+
+  @return EFI_SUCCESS             Data was fetched.
+  @return EFI_INVALID_PARAMETER   DataSize is NULL.
+  @return EFI_BUFFER_TOO_SMALL    DataSize is smaller than size of variable data.
+
+**/
+EFI_STATUS
+GetVariableData (
+  IN      VARIABLE_HEADER  *Variable,
+  IN  OUT VOID             *Data,
+  IN  OUT UINT32           *DataSize,
+  IN      BOOLEAN          AuthFlag
+  )
+{
+  UINT32  Size;
+
+  if (DataSize == NULL) {
+    ASSERT (DataSize != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Size = (UINT32)DataSizeOfVariable (Variable, AuthFlag);
+  if (*DataSize < Size) {
+    *DataSize = Size;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (Data == NULL) {
+    ASSERT (Data != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size);
+  *DataSize = Size;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  This code gets the pointer to the next variable header.
+
+  @param[in] Variable     Pointer to the Variable Header.
+  @param[in] AuthFormat   TRUE indicates authenticated variables are used.
+                          FALSE indicates authenticated variables are not used.
+
+  @return Pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFormat
+  )
+{
+  UINTN  Value;
+
+  Value  =  (UINTN)GetVariableDataPtr (Variable, AuthFormat);
+  Value += DataSizeOfVariable (Variable, AuthFormat);
+  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable, AuthFormat));
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  return (VARIABLE_HEADER *)HEADER_ALIGN (Value);
+}
+
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  )
+{
+  //
+  // The start of variable store.
+  //
+  return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param[in] VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store
+  //
+  return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);
+}
+
+/**
+  Compare two EFI_TIME data.
+
+
+  @param[in] FirstTime       A pointer to the first EFI_TIME data.
+  @param[in] SecondTime      A pointer to the second EFI_TIME data.
+
+  @retval  TRUE              The FirstTime is not later than the SecondTime.
+  @retval  FALSE             The FirstTime is later than the SecondTime.
+
+**/
+BOOLEAN
+VariableCompareTimeStampInternal (
+  IN EFI_TIME  *FirstTime,
+  IN EFI_TIME  *SecondTime
+  )
+{
+  if (FirstTime->Year != SecondTime->Year) {
+    return (BOOLEAN)(FirstTime->Year < SecondTime->Year);
+  } else if (FirstTime->Month != SecondTime->Month) {
+    return (BOOLEAN)(FirstTime->Month < SecondTime->Month);
+  } else if (FirstTime->Day != SecondTime->Day) {
+    return (BOOLEAN)(FirstTime->Day < SecondTime->Day);
+  } else if (FirstTime->Hour != SecondTime->Hour) {
+    return (BOOLEAN)(FirstTime->Hour < SecondTime->Hour);
+  } else if (FirstTime->Minute != SecondTime->Minute) {
+    return (BOOLEAN)(FirstTime->Minute < SecondTime->Minute);
+  }
+
+  return (BOOLEAN)(FirstTime->Second <= SecondTime->Second);
+}
+
+/**
+  Find the variable in the specified variable store.
+
+  @param[in]       VariableName        Name of the variable to be found
+  @param[in]       VendorGuid          Vendor GUID to be found.
+  @param[in]       IgnoreRtCheck       Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+                                       check at runtime when searching variable.
+  @param[in, out]  PtrTrack            Variable Track Pointer structure that contains Variable Information.
+  @param[in]       AuthFormat          TRUE indicates authenticated variables are used.
+                                       FALSE indicates authenticated variables are not used.
+
+  @retval          EFI_SUCCESS         Variable found successfully
+  @retval          EFI_NOT_FOUND       Variable not found
+**/
+EFI_STATUS
+FindVariableEx (
+  IN     CHAR16                  *VariableName,
+  IN     EFI_GUID                *VendorGuid,
+  IN     BOOLEAN                 IgnoreRtCheck,
+  IN OUT VARIABLE_POINTER_TRACK  *PtrTrack,
+  IN     BOOLEAN                 AuthFormat
+  )
+{
+  VARIABLE_HEADER  *InDeletedVariable;
+  VOID             *Point;
+
+  PtrTrack->InDeletedTransitionPtr = NULL;
+
+  //
+  // Find the variable by walk through HOB, volatile and non-volatile variable store.
+  //
+  InDeletedVariable = NULL;
+
+  for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
+        ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, AuthFormat)
+        ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr, AuthFormat)
+        )
+  {
+    if ((PtrTrack->CurrPtr->State == VAR_ADDED) ||
+        (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))
+        )
+    {
+      if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+        if (VariableName[0] == 0) {
+          if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+            InDeletedVariable = PtrTrack->CurrPtr;
+          } else {
+            PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
+            return EFI_SUCCESS;
+          }
+        } else {
+          if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr, AuthFormat))) {
+            Point = (VOID *)GetVariableNamePtr (PtrTrack->CurrPtr, AuthFormat);
+
+            ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat) != 0);
+            if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat)) == 0) {
+              if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+                InDeletedVariable = PtrTrack->CurrPtr;
+              } else {
+                PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
+                return EFI_SUCCESS;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  PtrTrack->CurrPtr = InDeletedVariable;
+  return (PtrTrack->CurrPtr  == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+  This code finds the next available variable.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+  @param[in]  VariableName      Pointer to variable name.
+  @param[in]  VendorGuid        Variable Vendor Guid.
+  @param[in]  VariableStoreList A list of variable stores that should be used to get the next variable.
+                                The maximum number of entries is the max value of VARIABLE_STORE_TYPE.
+  @param[out] VariablePtr       Pointer to variable header address.
+  @param[in]  AuthFormat        TRUE indicates authenticated variables are used.
+                                FALSE indicates authenticated variables are not used.
+
+  @retval EFI_SUCCESS           The function completed successfully.
+  @retval EFI_NOT_FOUND         The next variable was not found.
+  @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
+                                GUID of an existing variable.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableInternal (
+  IN  CHAR16                 *VariableName,
+  IN  EFI_GUID               *VendorGuid,
+  IN  VARIABLE_STORE_HEADER  **VariableStoreList,
+  OUT VARIABLE_HEADER        **VariablePtr,
+  IN  BOOLEAN                AuthFormat
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_STORE_TYPE     StoreType;
+  VARIABLE_POINTER_TRACK  Variable;
+  VARIABLE_POINTER_TRACK  VariableInHob;
+  VARIABLE_POINTER_TRACK  VariablePtrTrack;
+
+  Status = EFI_NOT_FOUND;
+
+  if (VariableStoreList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Variable, sizeof (Variable));
+
+  // Check if the variable exists in the given variable store list
+  for (StoreType = (VARIABLE_STORE_TYPE)0; StoreType < VariableStoreTypeMax; StoreType++) {
+    if (VariableStoreList[StoreType] == NULL) {
+      continue;
+    }
+
+    Variable.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+    Variable.EndPtr   = GetEndPointer (VariableStoreList[StoreType]);
+    Variable.Volatile = (BOOLEAN)(StoreType == VariableStoreTypeVolatile);
+
+    Status = FindVariableEx (VariableName, VendorGuid, FALSE, &Variable, AuthFormat);
+    if (!EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  if ((Variable.CurrPtr == NULL) || EFI_ERROR (Status)) {
+    //
+    // For VariableName is an empty string, FindVariableEx() will try to find and return
+    // the first qualified variable, and if FindVariableEx() returns error (EFI_NOT_FOUND)
+    // as no any variable is found, still go to return the error (EFI_NOT_FOUND).
+    //
+    if (VariableName[0] != 0) {
+      //
+      // For VariableName is not an empty string, and FindVariableEx() returns error as
+      // VariableName and VendorGuid are not a name and GUID of an existing variable,
+      // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.
+      //
+      Status = EFI_INVALID_PARAMETER;
+    }
+
+    goto Done;
+  }
+
+  if (VariableName[0] != 0) {
+    //
+    // If variable name is not empty, get next variable.
+    //
+    Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+  }
+
+  while (TRUE) {
+    //
+    // Switch to the next variable store if needed
+    //
+    while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr, AuthFormat)) {
+      //
+      // Find current storage index
+      //
+      for (StoreType = (VARIABLE_STORE_TYPE)0; StoreType < VariableStoreTypeMax; StoreType++) {
+        if ((VariableStoreList[StoreType] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreList[StoreType]))) {
+          break;
+        }
+      }
+
+      ASSERT (StoreType < VariableStoreTypeMax);
+      //
+      // Switch to next storage
+      //
+      for (StoreType++; StoreType < VariableStoreTypeMax; StoreType++) {
+        if (VariableStoreList[StoreType] != NULL) {
+          break;
+        }
+      }
+
+      //
+      // Capture the case that
+      // 1. current storage is the last one, or
+      // 2. no further storage
+      //
+      if (StoreType == VariableStoreTypeMax) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+
+      Variable.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+      Variable.EndPtr   = GetEndPointer (VariableStoreList[StoreType]);
+      Variable.CurrPtr  = Variable.StartPtr;
+    }
+
+    //
+    // Variable is found
+    //
+    if ((Variable.CurrPtr->State == VAR_ADDED) || (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+      if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+        if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+          //
+          // If it is a IN_DELETED_TRANSITION variable,
+          // and there is also a same ADDED one at the same time,
+          // don't return it.
+          //
+          VariablePtrTrack.StartPtr = Variable.StartPtr;
+          VariablePtrTrack.EndPtr   = Variable.EndPtr;
+          Status                    = FindVariableEx (
+                                        GetVariableNamePtr (Variable.CurrPtr, AuthFormat),
+                                        GetVendorGuidPtr (Variable.CurrPtr, AuthFormat),
+                                        FALSE,
+                                        &VariablePtrTrack,
+                                        AuthFormat
+                                        );
+          if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State == VAR_ADDED)) {
+            Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+            continue;
+          }
+        }
+
+        //
+        // Don't return NV variable when HOB overrides it
+        //
+        if ((VariableStoreList[VariableStoreTypeHob] != NULL) && (VariableStoreList[VariableStoreTypeNv] != NULL) &&
+            (Variable.StartPtr == GetStartPointer (VariableStoreList[VariableStoreTypeNv]))
+            )
+        {
+          VariableInHob.StartPtr = GetStartPointer (VariableStoreList[VariableStoreTypeHob]);
+          VariableInHob.EndPtr   = GetEndPointer (VariableStoreList[VariableStoreTypeHob]);
+          Status                 = FindVariableEx (
+                                     GetVariableNamePtr (Variable.CurrPtr, AuthFormat),
+                                     GetVendorGuidPtr (Variable.CurrPtr, AuthFormat),
+                                     FALSE,
+                                     &VariableInHob,
+                                     AuthFormat
+                                     );
+          if (!EFI_ERROR (Status)) {
+            Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+            continue;
+          }
+        }
+
+        *VariablePtr = Variable.CurrPtr;
+        Status       = EFI_SUCCESS;
+        goto Done;
+      }
+    }
+
+    Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr, AuthFormat);
+  }
+
+Done:
+  return Status;
+}
+
+/**
+  Routine used to track statistical information about variable usage.
+  The data is stored in the EFI system table so it can be accessed later.
+  VariableInfo.efi can dump out the table. Only Boot Services variable
+  accesses are tracked by this code. The PcdVariableCollectStatistics
+  build flag controls if this feature is enabled.
+
+  A read that hits in the cache will have Read and Cache true for
+  the transaction. Data is allocated by this routine, but never
+  freed.
+
+  @param[in]      VariableName   Name of the Variable to track.
+  @param[in]      VendorGuid     Guid of the Variable to track.
+  @param[in]      Volatile       TRUE if volatile FALSE if non-volatile.
+  @param[in]      Read           TRUE if GetVariable() was called.
+  @param[in]      Write          TRUE if SetVariable() was called.
+  @param[in]      Delete         TRUE if deleted via SetVariable().
+  @param[in]      Cache          TRUE for a cache hit.
+  @param[in,out]  VariableInfo   Pointer to a pointer of VARIABLE_INFO_ENTRY structures.
+
+**/
+VOID
+UpdateVariableInfo (
+  IN  CHAR16                  *VariableName,
+  IN  EFI_GUID                *VendorGuid,
+  IN  BOOLEAN                 Volatile,
+  IN  BOOLEAN                 Read,
+  IN  BOOLEAN                 Write,
+  IN  BOOLEAN                 Delete,
+  IN  BOOLEAN                 Cache,
+  IN OUT VARIABLE_INFO_ENTRY  **VariableInfo
+  )
+{
+  VARIABLE_INFO_ENTRY  *Entry;
+
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+    if ((VariableName == NULL) || (VendorGuid == NULL) || (VariableInfo == NULL)) {
+      return;
+    }
+
+    if (AtRuntime ()) {
+      // Don't collect statistics at runtime.
+      return;
+    }
+
+    if (*VariableInfo == NULL) {
+      //
+      // On the first call allocate a entry and place a pointer to it in
+      // the EFI System Table.
+      //
+      *VariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+      ASSERT (*VariableInfo != NULL);
+
+      CopyGuid (&(*VariableInfo)->VendorGuid, VendorGuid);
+      (*VariableInfo)->Name = AllocateZeroPool (StrSize (VariableName));
+      ASSERT ((*VariableInfo)->Name != NULL);
+      StrCpyS ((*VariableInfo)->Name, StrSize (VariableName)/sizeof (CHAR16), VariableName);
+      (*VariableInfo)->Volatile = Volatile;
+    }
+
+    for (Entry = (*VariableInfo); Entry != NULL; Entry = Entry->Next) {
+      if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
+        if (StrCmp (VariableName, Entry->Name) == 0) {
+          if (Read) {
+            Entry->ReadCount++;
+          }
+
+          if (Write) {
+            Entry->WriteCount++;
+          }
+
+          if (Delete) {
+            Entry->DeleteCount++;
+          }
+
+          if (Cache) {
+            Entry->CacheCount++;
+          }
+
+          return;
+        }
+      }
+
+      if (Entry->Next == NULL) {
+        //
+        // If the entry is not in the table add it.
+        // Next iteration of the loop will fill in the data.
+        //
+        Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+        ASSERT (Entry->Next != NULL);
+
+        CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
+        Entry->Next->Name = AllocateZeroPool (StrSize (VariableName));
+        ASSERT (Entry->Next->Name != NULL);
+        StrCpyS (Entry->Next->Name, StrSize (VariableName)/sizeof (CHAR16), VariableName);
+        Entry->Next->Volatile = Volatile;
+      }
+    }
+  }
+}
+
+/**
+
+  Retrieve details about a variable and return them in VariableInfo->Header.
+
+  If VariableInfo->Buffer is given, this function will calculate its offset
+  relative to given variable storage via VariableStore; Otherwise, it will try
+  other internal variable storages or cached copies. It's assumed that, for all
+  copies of NV variable storage, all variables are stored in the same relative
+  position. If VariableInfo->Buffer is found in the range of any storage copies,
+  its offset relative to that storage should be the same in other copies.
+
+  If VariableInfo->Offset is given (non-zero) but not VariableInfo->Buffer,
+  this function will return the variable memory address inside VariableStore,
+  if given, via VariableInfo->Address; Otherwise, the address of other storage
+  copies will be returned, if any.
+
+  For a new variable whose offset has not been determined, a value of -1 as
+  VariableInfo->Offset should be passed to skip the offset calculation.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo->Address
+                                 and VariableInfo->Offset are NULL (0).
+  @retval EFI_NOT_FOUND          If given Address or Offset is out of range of
+                                 any given or internal storage copies.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfo (
+  IN OUT  PROTECTED_VARIABLE_INFO  *VariableInfo
+  )
+{
+  VARIABLE_STORE_HEADER          *Stores[2];
+  UINTN                          Index;
+  VARIABLE_HEADER                *VariablePtr;
+  VARIABLE_HEADER                *VariableBuffer;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariablePtr;
+  BOOLEAN                        AuthFlag;
+  UINTN                          NameSize;
+  UINTN                          DataSize;
+  UINTN                          VariableSize;
+
+  if ((VariableInfo == NULL) || (  (VariableInfo->Buffer == NULL)
+                                && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+  {
+    ASSERT (VariableInfo != NULL);
+    ASSERT (VariableInfo->Buffer != NULL || VariableInfo->StoreIndex != VAR_INDEX_INVALID);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Stores[0] = mNvVariableCache;
+  Stores[1] = (mVariableModuleGlobal != NULL)
+              ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
+              : NULL;
+
+  VariableBuffer = VariableInfo->Buffer;
+  VariablePtr    = NULL;
+  if (VariableInfo->StoreIndex != VAR_INDEX_INVALID) {
+    for (Index = 0; Index < ARRAY_SIZE (Stores); ++Index) {
+      if (Stores[Index] == NULL) {
+        continue;
+      }
+
+      if ((UINTN)VariableInfo->StoreIndex
+          < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index]))
+      {
+        VariablePtr          = (VARIABLE_HEADER *)((UINTN)Stores[Index] + (UINTN)VariableInfo->StoreIndex);
+        VariableInfo->Buffer = VariablePtr;
+        break;
+      }
+    }
+  } else {
+    VariablePtr = VariableInfo->Buffer;
+  }
+
+  if (VariablePtr == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  AuthFlag = VariableInfo->Flags.Auth;
+  ASSERT (AuthFlag == TRUE || AuthFlag == FALSE);
+
+  //
+  // Make a copy of the whole variable if a buffer is passed in.
+  //
+  if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+    VariableSize = (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag)
+                   - (UINTN)VariablePtr;
+    CopyMem (VariableBuffer, VariablePtr, VariableSize);
+  }
+
+  //
+  // AuthVariable header
+  //
+  if (AuthFlag) {
+    AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr;
+
+    VariableInfo->Header.State          = AuthVariablePtr->State;
+    VariableInfo->Header.Attributes     = AuthVariablePtr->Attributes;
+    VariableInfo->Header.PubKeyIndex    = AuthVariablePtr->PubKeyIndex;
+    VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+                                            &(AuthVariablePtr->MonotonicCount)
+                                            );
+    if (VariableInfo->Header.TimeStamp != NULL) {
+      CopyMem (
+        VariableInfo->Header.TimeStamp,
+        &AuthVariablePtr->TimeStamp,
+        sizeof (EFI_TIME)
+        );
+    } else if (VariableBuffer != NULL) {
+      AuthVariablePtr                = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+      VariableInfo->Header.TimeStamp = &AuthVariablePtr->TimeStamp;
+    }
+  } else {
+    VariableInfo->Header.State          = VariablePtr->State;
+    VariableInfo->Header.Attributes     = VariablePtr->Attributes;
+    VariableInfo->Header.PubKeyIndex    = 0;
+    VariableInfo->Header.MonotonicCount = 0;
+    VariableInfo->Header.TimeStamp      = NULL;
+  }
+
+  //
+  // VendorGuid
+  //
+  if (VariableInfo->Header.VendorGuid != NULL) {
+    CopyGuid (
+      VariableInfo->Header.VendorGuid,
+      GetVendorGuidPtr (VariablePtr, AuthFlag)
+      );
+  } else {
+    VariableInfo->Header.VendorGuid = GetVendorGuidPtr (VariablePtr, AuthFlag);
+  }
+
+  //
+  // VariableName
+  //
+  NameSize = NameSizeOfVariable (VariablePtr, AuthFlag);
+  if (  (VariableInfo->Header.VariableName != NULL)
+     && (VariableInfo->Header.NameSize >= NameSize))
+  {
+    CopyMem (
+      VariableInfo->Header.VariableName,
+      GetVariableNamePtr (VariablePtr, AuthFlag),
+      NameSize
+      );
+  } else if (VariableInfo->Header.VariableName != NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  } else {
+    VariableInfo->Header.VariableName = GetVariableNamePtr (VariablePtr, AuthFlag);
+  }
+
+  //
+  // Data
+  //
+  DataSize = DataSizeOfVariable (VariablePtr, AuthFlag);
+  if (  (VariableInfo->Header.Data != NULL)
+     && (VariableInfo->Header.DataSize >= DataSize))
+  {
+    CopyMem (
+      VariableInfo->Header.Data,
+      GetVariableDataPtr (VariablePtr, AuthFlag),
+      NameSize
+      );
+  } else if (VariableInfo->Header.Data != NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  } else {
+    VariableInfo->Header.Data = GetVariableDataPtr (VariablePtr, AuthFlag);
+  }
+
+  //
+  // Update size information about name & data.
+  //
+  VariableInfo->Header.NameSize = NameSize;
+  VariableInfo->Header.DataSize = DataSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VariableInfo->StoreIndex is invalid, the first one in VariableStore is returned.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo or VariableStore is NULL.
+  @retval EFI_NOT_FOUND          If the end of VariableStore is reached.
+  @retval EFI_SUCCESS            The next variable is retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextVariableInfo (
+  IN OUT  PROTECTED_VARIABLE_INFO  *VariableInfo
+  )
+{
+  VARIABLE_STORE_HEADER  *VarStore;
+  VARIABLE_HEADER        *VariablePtr;
+  VARIABLE_HEADER        *VariableStart;
+  VARIABLE_HEADER        *VariableEnd;
+  BOOLEAN                AuthFlag;
+
+  if (VariableInfo == NULL) {
+    ASSERT (VariableInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (mNvVariableCache != NULL) {
+    VarStore = mNvVariableCache;
+  } else if (mVariableModuleGlobal != NULL) {
+    VarStore = (VARIABLE_STORE_HEADER *)(UINTN)
+               mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+  } else {
+    return EFI_NOT_FOUND;
+  }
+
+  VariableStart = GetStartPointer (VarStore);
+  VariableEnd   = GetEndPointer (VarStore);
+
+  if ((VariableInfo->Flags.Auth != TRUE) && (VariableInfo->Flags.Auth != FALSE)) {
+    VariableInfo->Flags.Auth = CompareGuid (
+                                 &VarStore->Signature,
+                                 &gEfiAuthenticatedVariableGuid
+                                 );
+  }
+
+  AuthFlag = VariableInfo->Flags.Auth;
+
+  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+    VariablePtr = VariableStart;
+  } else {
+    VariablePtr = (VARIABLE_HEADER *)
+                  ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex);
+    if (VariablePtr >= VariableEnd) {
+      return EFI_NOT_FOUND;
+    }
+
+    VariablePtr = GetNextVariablePtr (VariablePtr, AuthFlag);
+  }
+
+  if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) {
+    return EFI_NOT_FOUND;
+  }
+
+  VariableInfo->StoreIndex = (UINTN)VariablePtr - (UINTN)VarStore;
+  return GetVariableInfo (VariableInfo);
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmmDxe.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmmDxe.c
new file mode 100644
index 000000000000..b2094fbcd6ea
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmmDxe.c
@@ -0,0 +1,575 @@
+/** @file -- VariablePolicySmmDxe.c
+This protocol allows communication with Variable Policy Engine.
+
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Protocol/VariablePolicy.h>
+#include <Protocol/MmCommunication2.h>
+
+#include <Guid/VarCheckPolicyMmi.h>
+
+#include "Variable.h"
+
+EDKII_VARIABLE_POLICY_PROTOCOL  mVariablePolicyProtocol;
+EFI_MM_COMMUNICATION2_PROTOCOL  *mMmCommunication;
+
+VOID      *mMmCommunicationBuffer;
+UINTN     mMmCommunicationBufferSize;
+EFI_LOCK  mMmCommunicationLock;
+
+/**
+  Internal helper function to consolidate communication method.
+
+  @param[in,out]  CommBuffer
+  @param[in,out]  CommSize    Size of the CommBuffer.
+
+  @retval   EFI_STATUS    Result from communication method.
+
+**/
+STATIC
+EFI_STATUS
+InternalMmCommunicate (
+  IN OUT VOID   *CommBuffer,
+  IN OUT UINTN  *CommSize
+  )
+{
+  EFI_STATUS  Status;
+
+  if ((CommBuffer == NULL) || (CommSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = mMmCommunication->Communicate (mMmCommunication, CommBuffer, CommBuffer, CommSize);
+  return Status;
+}
+
+/**
+  This API function disables the variable policy enforcement. If it's
+  already been called once, will return EFI_ALREADY_STARTED.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.
+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.
+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProtocolDisableVariablePolicy (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_MM_COMMUNICATE_HEADER     *CommHeader;
+  VAR_CHECK_POLICY_COMM_HEADER  *PolicyHeader;
+  UINTN                         BufferSize;
+
+  // Check the PCD for convenience.
+  // This would also be rejected by the lib, but why go to MM if we don't have to?
+  if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {
+    return EFI_WRITE_PROTECTED;
+  }
+
+  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  // Set up the MM communication.
+  BufferSize   = mMmCommunicationBufferSize;
+  CommHeader   = mMmCommunicationBuffer;
+  PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;
+  CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);
+  CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
+  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
+  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_DISABLE;
+
+  Status = InternalMmCommunicate (CommHeader, &BufferSize);
+  DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));
+
+  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result;
+}
+
+/**
+  This API function returns whether or not the policy engine is
+  currently being enforced.
+
+  @param[out]   State       Pointer to a return value for whether the policy enforcement
+                            is currently enabled.
+
+  @retval     EFI_SUCCESS
+  @retval     Others        An error has prevented this command from completing.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProtocolIsVariablePolicyEnabled (
+  OUT BOOLEAN  *State
+  )
+{
+  EFI_STATUS                               Status;
+  EFI_MM_COMMUNICATE_HEADER                *CommHeader;
+  VAR_CHECK_POLICY_COMM_HEADER             *PolicyHeader;
+  VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS  *CommandParams;
+  UINTN                                    BufferSize;
+
+  if (State == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  // Set up the MM communication.
+  BufferSize    = mMmCommunicationBufferSize;
+  CommHeader    = mMmCommunicationBuffer;
+  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;
+  CommandParams = (VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS *)(PolicyHeader + 1);
+  CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);
+  CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
+  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
+  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_IS_ENABLED;
+
+  Status = InternalMmCommunicate (CommHeader, &BufferSize);
+  DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));
+
+  if (!EFI_ERROR (Status)) {
+    Status = PolicyHeader->Result;
+    *State = CommandParams->State;
+  }
+
+  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  return Status;
+}
+
+/**
+  This API function validates and registers a new policy with
+  the policy enforcement engine.
+
+  @param[in]  NewPolicy     Pointer to the incoming policy structure.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.
+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.
+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.
+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.
+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.
+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProtocolRegisterVariablePolicy (
+  IN CONST VARIABLE_POLICY_ENTRY  *NewPolicy
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_MM_COMMUNICATE_HEADER     *CommHeader;
+  VAR_CHECK_POLICY_COMM_HEADER  *PolicyHeader;
+  VOID                          *PolicyBuffer;
+  UINTN                         BufferSize;
+  UINTN                         RequiredSize;
+
+  if (NewPolicy == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // First, make sure that the required size does not exceed the capabilities
+  // of the MmCommunication buffer.
+  RequiredSize = OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + sizeof (VAR_CHECK_POLICY_COMM_HEADER);
+  Status       = SafeUintnAdd (RequiredSize, NewPolicy->Size, &RequiredSize);
+  if (EFI_ERROR (Status) || (RequiredSize > mMmCommunicationBufferSize)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a - Policy too large for buffer! %r, %d > %d \n",
+      __FUNCTION__,
+      Status,
+      RequiredSize,
+      mMmCommunicationBufferSize
+      ));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  // Set up the MM communication.
+  BufferSize   = mMmCommunicationBufferSize;
+  CommHeader   = mMmCommunicationBuffer;
+  PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;
+  PolicyBuffer = (VOID *)(PolicyHeader + 1);
+  CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);
+  CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
+  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
+  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_REGISTER;
+
+  // Copy the policy into place. This copy is safe because we've already tested above.
+  CopyMem (PolicyBuffer, NewPolicy, NewPolicy->Size);
+
+  Status = InternalMmCommunicate (CommHeader, &BufferSize);
+  DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));
+
+  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result;
+}
+
+/**
+  This helper function takes care of the overhead of formatting, sending, and interpreting
+  the results for a single DumpVariablePolicy request.
+
+  @param[in]      PageRequested   The page of the paginated results from MM. 0 for metadata.
+  @param[out]     TotalSize       The total size of the entire buffer. Returned as part of metadata.
+  @param[out]     PageSize        The size of the current page being returned. Not valid as part of metadata.
+  @param[out]     HasMore         A flag indicating whether there are more pages after this one.
+  @param[out]     Buffer          The start of the current page from MM.
+
+  @retval     EFI_SUCCESS             Output params have been updated (either metadata or dump page).
+  @retval     EFI_INVALID_PARAMETER   One of the output params is NULL.
+  @retval     Others                  Response from MM handler.
+
+**/
+STATIC
+EFI_STATUS
+DumpVariablePolicyHelper (
+  IN  UINT32   PageRequested,
+  OUT UINT32   *TotalSize,
+  OUT UINT32   *PageSize,
+  OUT BOOLEAN  *HasMore,
+  OUT UINT8    **Buffer
+  )
+{
+  EFI_STATUS                         Status;
+  EFI_MM_COMMUNICATE_HEADER          *CommHeader;
+  VAR_CHECK_POLICY_COMM_HEADER       *PolicyHeader;
+  VAR_CHECK_POLICY_COMM_DUMP_PARAMS  *CommandParams;
+  UINTN                              BufferSize;
+
+  if ((TotalSize == NULL) || (PageSize == NULL) || (HasMore == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Set up the MM communication.
+  BufferSize    = mMmCommunicationBufferSize;
+  CommHeader    = mMmCommunicationBuffer;
+  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;
+  CommandParams = (VAR_CHECK_POLICY_COMM_DUMP_PARAMS *)(PolicyHeader + 1);
+  CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);
+  CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
+  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
+  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_DUMP;
+
+  CommandParams->PageRequested = PageRequested;
+
+  Status = InternalMmCommunicate (CommHeader, &BufferSize);
+  DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));
+
+  if (!EFI_ERROR (Status)) {
+    Status     = PolicyHeader->Result;
+    *TotalSize = CommandParams->TotalSize;
+    *PageSize  = CommandParams->PageSize;
+    *HasMore   = CommandParams->HasMore;
+    *Buffer    = (UINT8 *)(CommandParams + 1);
+  }
+
+  return Status;
+}
+
+/**
+  This API function will dump the entire contents of the variable policy table.
+
+  Similar to GetVariable, the first call can be made with a 0 size and it will return
+  the size of the buffer required to hold the entire table.
+
+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.
+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size
+                          of the data returned.
+
+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.
+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.
+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProtocolDumpVariablePolicy (
+  OUT UINT8      *Policy OPTIONAL,
+  IN OUT UINT32  *Size
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *Source;
+  UINT8       *Destination;
+  UINT32      PolicySize;
+  UINT32      PageSize;
+  BOOLEAN     HasMore;
+  UINT32      PageIndex;
+
+  if ((Size == NULL) || ((*Size > 0) && (Policy == NULL))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  // Repeat this whole process until we either have a failure case or get the entire buffer.
+  do {
+    // First, we must check the zero page to determine the buffer size and
+    // reset the internal state.
+    PolicySize = 0;
+    PageSize   = 0;
+    HasMore    = FALSE;
+    Status     = DumpVariablePolicyHelper (0, &PolicySize, &PageSize, &HasMore, &Source);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    // If we're good, we can at least check the required size now.
+    if (*Size < PolicySize) {
+      *Size  = PolicySize;
+      Status = EFI_BUFFER_TOO_SMALL;
+      break;
+    }
+
+    // On further thought, let's update the size either way.
+    *Size = PolicySize;
+    // And get ready to ROCK.
+    Destination = Policy;
+
+    // Keep looping and copying until we're either done or freak out.
+    for (PageIndex = 1; !EFI_ERROR (Status) && HasMore && PageIndex < MAX_UINT32; PageIndex++) {
+      Status = DumpVariablePolicyHelper (PageIndex, &PolicySize, &PageSize, &HasMore, &Source);
+      if (!EFI_ERROR (Status)) {
+        CopyMem (Destination, Source, PageSize);
+        Destination += PageSize;
+      }
+    }
+
+    // Next, we check to see whether
+  } while (Status == EFI_TIMEOUT);
+
+  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  // There's currently no use for this, but it shouldn't be hard to implement.
+  return Status;
+}
+
+/**
+  This API function locks the interface so that no more policy updates
+  can be performed or changes made to the enforcement until the next boot.
+
+  @retval     EFI_SUCCESS
+  @retval     Others        An error has prevented this command from completing.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProtocolLockVariablePolicy (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_MM_COMMUNICATE_HEADER     *CommHeader;
+  VAR_CHECK_POLICY_COMM_HEADER  *PolicyHeader;
+  UINTN                         BufferSize;
+
+  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  // Set up the MM communication.
+  BufferSize   = mMmCommunicationBufferSize;
+  CommHeader   = mMmCommunicationBuffer;
+  PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;
+  CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);
+  CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
+  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
+  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_LOCK;
+
+  Status = InternalMmCommunicate (CommHeader, &BufferSize);
+  DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));
+
+  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
+
+  return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result;
+}
+
+/**
+  This helper function locates the shared comm buffer and assigns it to input pointers.
+
+  @param[in,out]  BufferSize      On input, the minimum buffer size required INCLUDING the MM communicate header.
+                                  On output, the size of the matching buffer found.
+  @param[out]     LocatedBuffer   A pointer to the matching buffer.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER   One of the output pointers was NULL.
+  @retval     EFI_OUT_OF_RESOURCES    Not enough memory to allocate a comm buffer.
+
+**/
+STATIC
+EFI_STATUS
+InitMmCommonCommBuffer (
+  IN OUT  UINTN  *BufferSize,
+  OUT     VOID   **LocatedBuffer
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  // Make sure that we're working with good pointers.
+  if ((BufferSize == NULL) || (LocatedBuffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Allocate the runtime memory for the comm buffer.
+  *LocatedBuffer = AllocateRuntimePool (*BufferSize);
+  if (*LocatedBuffer == NULL) {
+    Status      = EFI_OUT_OF_RESOURCES;
+    *BufferSize = 0;
+  }
+
+  EfiInitializeLock (&mMmCommunicationLock, TPL_NOTIFY);
+
+  return Status;
+}
+
+/**
+  Convert internal pointer addresses to virtual addresses.
+
+  @param[in] Event      Event whose notification function is being invoked.
+  @param[in] Context    The pointer to the notification function's context, which
+                        is implementation-dependent.
+**/
+STATIC
+VOID
+EFIAPI
+VariablePolicyVirtualAddressCallback (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EfiConvertPointer (0, (VOID **)&mMmCommunication);
+  EfiConvertPointer (0, (VOID **)&mMmCommunicationBuffer);
+}
+
+/**
+  The driver's entry point.
+
+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.
+  @param[in] SystemTable  A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS     The entry point executed successfully.
+  @retval other           Some error occured when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+VariablePolicySmmDxeMain (
+  IN    EFI_HANDLE        ImageHandle,
+  IN    EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  BOOLEAN     ProtocolInstalled;
+  BOOLEAN     VirtualAddressChangeRegistered;
+  EFI_EVENT   VirtualAddressChangeEvent;
+
+  Status                         = EFI_SUCCESS;
+  ProtocolInstalled              = FALSE;
+  VirtualAddressChangeRegistered = FALSE;
+
+  // Update the minimum buffer size.
+  mMmCommunicationBufferSize = VAR_CHECK_POLICY_MM_COMM_BUFFER_SIZE;
+  // Locate the shared comm buffer to use for sending MM commands.
+  Status = InitMmCommonCommBuffer (&mMmCommunicationBufferSize, &mMmCommunicationBuffer);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to locate a viable MM comm buffer! %r\n", __FUNCTION__, Status));
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  // Locate the MmCommunication protocol.
+  Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **)&mMmCommunication);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to locate MmCommunication protocol! %r\n", __FUNCTION__, Status));
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  // Configure the VariablePolicy protocol structure.
+  mVariablePolicyProtocol.Revision                = EDKII_VARIABLE_POLICY_PROTOCOL_REVISION;
+  mVariablePolicyProtocol.DisableVariablePolicy   = ProtocolDisableVariablePolicy;
+  mVariablePolicyProtocol.IsVariablePolicyEnabled = ProtocolIsVariablePolicyEnabled;
+  mVariablePolicyProtocol.RegisterVariablePolicy  = ProtocolRegisterVariablePolicy;
+  mVariablePolicyProtocol.DumpVariablePolicy      = ProtocolDumpVariablePolicy;
+  mVariablePolicyProtocol.LockVariablePolicy      = ProtocolLockVariablePolicy;
+
+  // Register all the protocols and return the status.
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gEdkiiVariablePolicyProtocolGuid,
+                  &mVariablePolicyProtocol,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to install protocol! %r\n", __FUNCTION__, Status));
+    goto Exit;
+  } else {
+    ProtocolInstalled = TRUE;
+  }
+
+  // Normally, we might want to register a callback
+  // to lock the interface, but this is integrated
+  // into the existing callbacks in VaraiableSmm.c
+  // and VariableDxe.c.
+
+  //
+  // Register a VirtualAddressChange callback for the MmComm protocol and Comm buffer.
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  VariablePolicyVirtualAddressCallback,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &VirtualAddressChangeEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to create VirtualAddressChange event! %r\n", __FUNCTION__, Status));
+    goto Exit;
+  } else {
+    VirtualAddressChangeRegistered = TRUE;
+  }
+
+Exit:
+  //
+  // If we're about to return a failed status (and unload this driver), we must first undo anything that
+  // has been successfully done.
+  if (EFI_ERROR (Status)) {
+    if (ProtocolInstalled) {
+      gBS->UninstallProtocolInterface (&ImageHandle, &gEdkiiVariablePolicyProtocolGuid, &mVariablePolicyProtocol);
+    }
+
+    if (VirtualAddressChangeRegistered) {
+      gBS->CloseEvent (VirtualAddressChangeEvent);
+    }
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.c
new file mode 100644
index 000000000000..9bb30bc1e804
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.c
@@ -0,0 +1,158 @@
+/** @file
+  Functions related to managing the UEFI variable runtime cache. This file should only include functions
+  used by the SMM UEFI variable driver.
+
+  Caution: This module requires additional review when modified.
+  This driver will have external input - variable data. They may be input in SMM mode.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+extern VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
+extern VARIABLE_STORE_HEADER   *mNvVariableCache;
+
+/**
+  Copies any pending updates to runtime variable caches.
+
+  @retval EFI_UNSUPPORTED         The volatile store to be updated is not initialized properly.
+  @retval EFI_SUCCESS             The volatile store was updated successfully.
+
+**/
+EFI_STATUS
+FlushPendingRuntimeVariableCacheUpdates (
+  VOID
+  )
+{
+  VARIABLE_RUNTIME_CACHE_CONTEXT  *VariableRuntimeCacheContext;
+
+  VariableRuntimeCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;
+
+  if ((VariableRuntimeCacheContext->VariableRuntimeNvCache.Store == NULL) ||
+      (VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store == NULL) ||
+      (VariableRuntimeCacheContext->PendingUpdate == NULL))
+  {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (*(VariableRuntimeCacheContext->PendingUpdate)) {
+    if ((VariableRuntimeCacheContext->VariableRuntimeHobCache.Store != NULL) &&
+        (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0))
+    {
+      CopyMem (
+        (VOID *)(
+                 ((UINT8 *)(UINTN)VariableRuntimeCacheContext->VariableRuntimeHobCache.Store) +
+                 VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset
+                 ),
+        (VOID *)(
+                 ((UINT8 *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase) +
+                 VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset
+                 ),
+        VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength
+        );
+      VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;
+      VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;
+    }
+
+    CopyMem (
+      (VOID *)(
+               ((UINT8 *)(UINTN)VariableRuntimeCacheContext->VariableRuntimeNvCache.Store) +
+               VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset
+               ),
+      (VOID *)(
+               ((UINT8 *)(UINTN)mNvVariableCache) +
+               VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset
+               ),
+      VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength
+      );
+    VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength = 0;
+    VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;
+
+    CopyMem (
+      (VOID *)(
+               ((UINT8 *)(UINTN)VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store) +
+               VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset
+               ),
+      (VOID *)(
+               ((UINT8 *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase) +
+               VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset
+               ),
+      VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength
+      );
+    VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = 0;
+    VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;
+    *(VariableRuntimeCacheContext->PendingUpdate)                                 = FALSE;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Synchronizes the runtime variable caches with all pending updates outside runtime.
+
+  Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt
+  to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the
+  update is added as a pending update for the given variable store and it will be flushed to the runtime cache
+  at the next opportunity the ReadLock is available.
+
+  @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized.
+  @param[in] Offset               Offset in bytes to apply the update.
+  @param[in] Length               Length of data in bytes of the update.
+
+  @retval EFI_SUCCESS             The update was added as a pending update successfully. If the variable runtime
+                                  cache ReadLock was available, the runtime cache was updated successfully.
+  @retval EFI_UNSUPPORTED         The volatile store to be updated is not initialized properly.
+
+**/
+EFI_STATUS
+SynchronizeRuntimeVariableCache (
+  IN  VARIABLE_RUNTIME_CACHE  *VariableRuntimeCache,
+  IN  UINTN                   Offset,
+  IN  UINTN                   Length
+  )
+{
+  if (VariableRuntimeCache == NULL) {
+    return EFI_INVALID_PARAMETER;
+  } else if (VariableRuntimeCache->Store == NULL) {
+    // The runtime cache may not be active or allocated yet.
+    // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_YET.
+    return EFI_SUCCESS;
+  }
+
+  if ((mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate == NULL) ||
+      (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock == NULL))
+  {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) &&
+      (VariableRuntimeCache->PendingUpdateLength > 0))
+  {
+    VariableRuntimeCache->PendingUpdateLength =
+      (UINT32)(
+               MAX (
+                 (UINTN)(VariableRuntimeCache->PendingUpdateOffset + VariableRuntimeCache->PendingUpdateLength),
+                 Offset + Length
+                 ) - MIN ((UINTN)VariableRuntimeCache->PendingUpdateOffset, Offset)
+               );
+    VariableRuntimeCache->PendingUpdateOffset =
+      (UINT32)MIN ((UINTN)VariableRuntimeCache->PendingUpdateOffset, Offset);
+  } else {
+    VariableRuntimeCache->PendingUpdateLength = (UINT32)Length;
+    VariableRuntimeCache->PendingUpdateOffset = (UINT32)Offset;
+  }
+
+  *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) = TRUE;
+
+  if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock) == FALSE) {
+    return FlushPendingRuntimeVariableCacheUpdates ();
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
new file mode 100644
index 000000000000..f7bac0227577
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
@@ -0,0 +1,1268 @@
+/** @file
+  The sample implementation for SMM variable protocol. And this driver
+  implements an SMI handler to communicate with the DXE runtime driver
+  to provide variable services.
+
+  Caution: This module requires additional review when modified.
+  This driver will have external input - variable data and communicate buffer in SMM mode.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  SmmVariableHandler() will receive untrusted input and do basic validation.
+
+  Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
+  VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
+  SmmVariableGetStatistics() should also do validation based on its own knowledge.
+
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Protocol/SmmVariable.h>
+#include <Protocol/SmmFirmwareVolumeBlock.h>
+#include <Protocol/SmmFaultTolerantWrite.h>
+#include <Protocol/MmEndOfDxe.h>
+#include <Protocol/SmmVarCheck.h>
+
+#include <Library/MmServicesTableLib.h>
+#include <Library/VariablePolicyLib.h>
+
+#include <Guid/SmmVariableCommon.h>
+#include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableRuntimeCache.h"
+
+extern VARIABLE_STORE_HEADER  *mNvVariableCache;
+
+BOOLEAN  mAtRuntime              = FALSE;
+UINT8    *mVariableBufferPayload = NULL;
+UINTN    mVariableBufferPayloadSize;
+
+/**
+  SecureBoot Hook for SetVariable.
+
+  @param[in] VariableName                 Name of Variable to be found.
+  @param[in] VendorGuid                   Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid
+  )
+{
+  return;
+}
+
+/**
+
+  This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+  @param VariableName                     Name of Variable to be found.
+  @param VendorGuid                       Variable vendor GUID.
+  @param Attributes                       Attribute value of the variable found
+  @param DataSize                         Size of Data found. If size is less than the
+                                          data, this value contains the required size.
+  @param Data                             Data pointer.
+
+  @return EFI_INVALID_PARAMETER           Invalid parameter.
+  @return EFI_SUCCESS                     Set successfully.
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
+  @return EFI_NOT_FOUND                   Not found.
+  @return EFI_WRITE_PROTECTED             Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableSetVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
+  //
+  mRequestSource = VarCheckFromTrusted;
+  Status         = VariableServiceSetVariable (
+                     VariableName,
+                     VendorGuid,
+                     Attributes,
+                     DataSize,
+                     Data
+                     );
+  mRequestSource = VarCheckFromUntrusted;
+  return Status;
+}
+
+EFI_SMM_VARIABLE_PROTOCOL  gSmmVariable = {
+  VariableServiceGetVariable,
+  VariableServiceGetNextVariableName,
+  SmmVariableSetVariable,
+  VariableServiceQueryVariableInfo
+};
+
+EDKII_SMM_VAR_CHECK_PROTOCOL  mSmmVarCheck = {
+  VarCheckRegisterSetVariableCheckHandler,
+  VarCheckVariablePropertySet,
+  VarCheckVariablePropertyGet
+};
+
+/**
+  Return TRUE if ExitBootServices () has been called.
+
+  @retval TRUE If ExitBootServices () has been called.
+**/
+BOOLEAN
+AtRuntime (
+  VOID
+  )
+{
+  return mAtRuntime;
+}
+
+/**
+  Initializes a basic mutual exclusion lock.
+
+  This function initializes a basic mutual exclusion lock to the released state
+  and returns the lock.  Each lock provides mutual exclusion access at its task
+  priority level.  Since there is no preemption or multiprocessor support in EFI,
+  acquiring the lock only consists of raising to the locks TPL.
+  If Lock is NULL, then ASSERT().
+  If Priority is not a valid TPL value, then ASSERT().
+
+  @param  Lock       A pointer to the lock data structure to initialize.
+  @param  Priority   EFI TPL is associated with the lock.
+
+  @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+  IN OUT EFI_LOCK  *Lock,
+  IN EFI_TPL       Priority
+  )
+{
+  return Lock;
+}
+
+/**
+  Acquires lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function that will be removed when
+  EfiAcquireLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiAcquireLock() at boot time, and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  )
+{
+}
+
+/**
+  Releases lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function which will be removed when
+  EfiReleaseLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiReleaseLock() at boot time and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  )
+{
+}
+
+/**
+  Retrieve the SMM Fault Tolerent Write protocol interface.
+
+  @param[out] FtwProtocol       The interface of SMM Ftw protocol
+
+  @retval EFI_SUCCESS           The SMM FTW protocol instance was found and returned in FtwProtocol.
+  @retval EFI_NOT_FOUND         The SMM FTW protocol instance was not found.
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
+
+**/
+EFI_STATUS
+GetFtwProtocol (
+  OUT VOID  **FtwProtocol
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Locate Smm Fault Tolerent Write protocol
+  //
+  Status = gMmst->MmLocateProtocol (
+                    &gEfiSmmFaultTolerantWriteProtocolGuid,
+                    NULL,
+                    FtwProtocol
+                    );
+  return Status;
+}
+
+/**
+  Retrieve the SMM FVB protocol interface by HANDLE.
+
+  @param[in]  FvBlockHandle     The handle of SMM FVB protocol that provides services for
+                                reading, writing, and erasing the target block.
+  @param[out] FvBlock           The interface of SMM FVB protocol
+
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.
+  @retval EFI_UNSUPPORTED       The device does not support the SMM FVB protocol.
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
+
+**/
+EFI_STATUS
+GetFvbByHandle (
+  IN  EFI_HANDLE                          FvBlockHandle,
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock
+  )
+{
+  //
+  // To get the SMM FVB protocol interface on the handle
+  //
+  return gMmst->MmHandleProtocol (
+                  FvBlockHandle,
+                  &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+                  (VOID **)FvBlock
+                  );
+}
+
+/**
+  Function returns an array of handles that support the SMM FVB protocol
+  in a buffer allocated from pool.
+
+  @param[out]  NumberHandles    The number of handles returned in Buffer.
+  @param[out]  Buffer           A pointer to the buffer to return the requested
+                                array of  handles that support SMM FVB protocol.
+
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of
+                                handles in Buffer was returned in NumberHandles.
+  @retval EFI_NOT_FOUND         No SMM FVB handle was found.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
+
+**/
+EFI_STATUS
+GetFvbCountAndBuffer (
+  OUT UINTN       *NumberHandles,
+  OUT EFI_HANDLE  **Buffer
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+
+  if ((NumberHandles == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BufferSize     = 0;
+  *NumberHandles = 0;
+  *Buffer        = NULL;
+  Status         = gMmst->MmLocateHandle (
+                            ByProtocol,
+                            &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+                            NULL,
+                            &BufferSize,
+                            *Buffer
+                            );
+  if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
+    return EFI_NOT_FOUND;
+  }
+
+  *Buffer = AllocatePool (BufferSize);
+  if (*Buffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = gMmst->MmLocateHandle (
+                    ByProtocol,
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+                    NULL,
+                    &BufferSize,
+                    *Buffer
+                    );
+
+  *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
+  if (EFI_ERROR (Status)) {
+    *NumberHandles = 0;
+    FreePool (*Buffer);
+    *Buffer = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Get the variable statistics information from the information buffer pointed by gVariableInfo.
+
+  Caution: This function may be invoked at SMM runtime.
+  InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
+
+  @param[in, out]  InfoEntry    A pointer to the buffer of variable information entry.
+                                On input, point to the variable information returned last time. if
+                                InfoEntry->VendorGuid is zero, return the first information.
+                                On output, point to the next variable information.
+  @param[in, out]  InfoSize     On input, the size of the variable information buffer.
+                                On output, the returned variable information size.
+
+  @retval EFI_SUCCESS           The variable information is found and returned successfully.
+  @retval EFI_UNSUPPORTED       No variable inoformation exists in variable driver. The
+                                PcdVariableCollectStatistics should be set TRUE to support it.
+  @retval EFI_BUFFER_TOO_SMALL  The buffer is too small to hold the next variable information.
+  @retval EFI_INVALID_PARAMETER Input parameter is invalid.
+
+**/
+EFI_STATUS
+SmmVariableGetStatistics (
+  IN OUT VARIABLE_INFO_ENTRY  *InfoEntry,
+  IN OUT UINTN                *InfoSize
+  )
+{
+  VARIABLE_INFO_ENTRY  *VariableInfo;
+  UINTN                NameSize;
+  UINTN                StatisticsInfoSize;
+  CHAR16               *InfoName;
+  UINTN                InfoNameMaxSize;
+  EFI_GUID             VendorGuid;
+
+  if (InfoEntry == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableInfo = gVariableInfo;
+  if (VariableInfo == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY);
+  if (*InfoSize < StatisticsInfoSize) {
+    *InfoSize = StatisticsInfoSize;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  InfoName        = (CHAR16 *)(InfoEntry + 1);
+  InfoNameMaxSize = (*InfoSize - sizeof (VARIABLE_INFO_ENTRY));
+
+  CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);
+
+  if (IsZeroGuid (&VendorGuid)) {
+    //
+    // Return the first variable info
+    //
+    NameSize           = StrSize (VariableInfo->Name);
+    StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;
+    if (*InfoSize < StatisticsInfoSize) {
+      *InfoSize = StatisticsInfoSize;
+      return EFI_BUFFER_TOO_SMALL;
+    }
+
+    CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
+    CopyMem (InfoName, VariableInfo->Name, NameSize);
+    *InfoSize = StatisticsInfoSize;
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Get the next variable info
+  //
+  while (VariableInfo != NULL) {
+    if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {
+      NameSize = StrSize (VariableInfo->Name);
+      if (NameSize <= InfoNameMaxSize) {
+        if (CompareMem (VariableInfo->Name, InfoName, NameSize) == 0) {
+          //
+          // Find the match one
+          //
+          VariableInfo = VariableInfo->Next;
+          break;
+        }
+      }
+    }
+
+    VariableInfo = VariableInfo->Next;
+  }
+
+  if (VariableInfo == NULL) {
+    *InfoSize = 0;
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Output the new variable info
+  //
+  NameSize           = StrSize (VariableInfo->Name);
+  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;
+  if (*InfoSize < StatisticsInfoSize) {
+    *InfoSize = StatisticsInfoSize;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
+  CopyMem (InfoName, VariableInfo->Name, NameSize);
+  *InfoSize = StatisticsInfoSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Communication service SMI Handler entry.
+
+  This SMI handler provides services for the variable wrapper driver.
+
+  Caution: This function may receive untrusted input.
+  This variable data and communicate buffer are external input, so this function will do basic validation.
+  Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
+  VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
+  SmmVariableGetStatistics() should also do validation based on its own knowledge.
+
+  @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
+  @param[in]     RegisterContext Points to an optional handler context which was specified when the
+                                 handler was registered.
+  @param[in, out] CommBuffer     A pointer to a collection of data in memory that will
+                                 be conveyed from a non-SMM environment into an SMM environment.
+  @param[in, out] CommBufferSize The size of the CommBuffer.
+
+  @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers
+                                              should still be called.
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should
+                                              still be called.
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still
+                                              be called.
+  @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableHandler (
+  IN     EFI_HANDLE  DispatchHandle,
+  IN     CONST VOID  *RegisterContext,
+  IN OUT VOID        *CommBuffer,
+  IN OUT UINTN       *CommBufferSize
+  )
+{
+  EFI_STATUS                                               Status;
+  SMM_VARIABLE_COMMUNICATE_HEADER                          *SmmVariableFunctionHeader;
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE                 *SmmVariableHeader;
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME          *GetNextVariableName;
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO             *QueryVariableInfo;
+  SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE                *GetPayloadSize;
+  SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT  *RuntimeVariableCacheContext;
+  SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO          *GetRuntimeCacheInfo;
+  SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE                   *VariableToLock;
+  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY     *CommVariableProperty;
+  VARIABLE_INFO_ENTRY                                      *VariableInfo;
+  VARIABLE_RUNTIME_CACHE_CONTEXT                           *VariableCacheContext;
+  VARIABLE_STORE_HEADER                                    *VariableCache;
+  UINTN                                                    InfoSize;
+  UINTN                                                    NameBufferSize;
+  UINTN                                                    CommBufferPayloadSize;
+  UINTN                                                    TempCommBufferSize;
+
+  //
+  // If input is invalid, stop processing this SMI
+  //
+  if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
+    return EFI_SUCCESS;
+  }
+
+  TempCommBufferSize = *CommBufferSize;
+
+  if (TempCommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+    DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
+    return EFI_SUCCESS;
+  }
+
+  CommBufferPayloadSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+  if (CommBufferPayloadSize > mVariableBufferPayloadSize) {
+    DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
+    return EFI_SUCCESS;
+  }
+
+  if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+    DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
+    return EFI_SUCCESS;
+  }
+
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;
+  switch (SmmVariableFunctionHeader->Function) {
+    case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
+      if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+        DEBUG ((DEBUG_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      //
+      // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+      //
+      CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)mVariableBufferPayload;
+      if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+          ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize))
+      {
+        //
+        // Prevent InfoSize overflow happen
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
+                 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
+
+      //
+      // SMRAM range check already covered before
+      //
+      if (InfoSize > CommBufferPayloadSize) {
+        DEBUG ((DEBUG_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      //
+      // The VariableSpeculationBarrier() call here is to ensure the previous
+      // range/content checks for the CommBuffer have been completed before the
+      // subsequent consumption of the CommBuffer content.
+      //
+      VariableSpeculationBarrier ();
+      if ((SmmVariableHeader->NameSize < sizeof (CHAR16)) || (SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0')) {
+        //
+        // Make sure VariableName is A Null-terminated string.
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      Status = VariableServiceGetVariable (
+                 SmmVariableHeader->Name,
+                 &SmmVariableHeader->Guid,
+                 &SmmVariableHeader->Attributes,
+                 &SmmVariableHeader->DataSize,
+                 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
+                 );
+      CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+      break;
+
+    case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
+      if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+        DEBUG ((DEBUG_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      //
+      // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+      //
+      CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+      GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *)mVariableBufferPayload;
+      if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+        //
+        // Prevent InfoSize overflow happen
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + GetNextVariableName->NameSize;
+
+      //
+      // SMRAM range check already covered before
+      //
+      if (InfoSize > CommBufferPayloadSize) {
+        DEBUG ((DEBUG_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      NameBufferSize = CommBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
+      if ((NameBufferSize < sizeof (CHAR16)) || (GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0')) {
+        //
+        // Make sure input VariableName is A Null-terminated string.
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      Status = VariableServiceGetNextVariableName (
+                 &GetNextVariableName->NameSize,
+                 GetNextVariableName->Name,
+                 &GetNextVariableName->Guid
+                 );
+      CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+      break;
+
+    case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
+      if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+        DEBUG ((DEBUG_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      //
+      // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+      //
+      CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)mVariableBufferPayload;
+      if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+          ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize))
+      {
+        //
+        // Prevent InfoSize overflow happen
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
+                 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
+
+      //
+      // SMRAM range check already covered before
+      // Data buffer should not contain SMM range
+      //
+      if (InfoSize > CommBufferPayloadSize) {
+        DEBUG ((DEBUG_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      //
+      // The VariableSpeculationBarrier() call here is to ensure the previous
+      // range/content checks for the CommBuffer have been completed before the
+      // subsequent consumption of the CommBuffer content.
+      //
+      VariableSpeculationBarrier ();
+      if ((SmmVariableHeader->NameSize < sizeof (CHAR16)) || (SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0')) {
+        //
+        // Make sure VariableName is A Null-terminated string.
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      Status = VariableServiceSetVariable (
+                 SmmVariableHeader->Name,
+                 &SmmVariableHeader->Guid,
+                 SmmVariableHeader->Attributes,
+                 SmmVariableHeader->DataSize,
+                 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
+                 );
+      break;
+
+    case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
+      if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
+        DEBUG ((DEBUG_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *)SmmVariableFunctionHeader->Data;
+
+      Status = VariableServiceQueryVariableInfo (
+                 QueryVariableInfo->Attributes,
+                 &QueryVariableInfo->MaximumVariableStorageSize,
+                 &QueryVariableInfo->RemainingVariableStorageSize,
+                 &QueryVariableInfo->MaximumVariableSize
+                 );
+      break;
+
+    case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:
+      if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
+        DEBUG ((DEBUG_ERROR, "GetPayloadSize: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      GetPayloadSize                      = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *)SmmVariableFunctionHeader->Data;
+      GetPayloadSize->VariablePayloadSize = mVariableBufferPayloadSize;
+      Status                              = EFI_SUCCESS;
+      break;
+
+    case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
+      if (AtRuntime ()) {
+        Status = EFI_UNSUPPORTED;
+        break;
+      }
+
+      if (!mEndOfDxe) {
+        MorLockInitAtEndOfDxe ();
+        Status = LockVariablePolicy ();
+        ASSERT_EFI_ERROR (Status);
+        mEndOfDxe = TRUE;
+        VarCheckLibInitializeAtEndOfDxe (NULL);
+        //
+        // The initialization for variable quota.
+        //
+        InitializeVariableQuota ();
+      }
+
+      ReclaimForOS ();
+      Status = EFI_SUCCESS;
+      break;
+
+    case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
+      mAtRuntime = TRUE;
+      Status     = EFI_SUCCESS;
+      break;
+
+    case SMM_VARIABLE_FUNCTION_GET_STATISTICS:
+      VariableInfo = (VARIABLE_INFO_ENTRY *)SmmVariableFunctionHeader->Data;
+      InfoSize     = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+
+      //
+      // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
+      // It is covered by previous CommBuffer check
+      //
+
+      //
+      // Do not need to check CommBufferSize buffer as it should point to SMRAM
+      // that was used by SMM core to cache CommSize from SmmCommunication protocol.
+      //
+
+      Status          = SmmVariableGetStatistics (VariableInfo, &InfoSize);
+      *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+      break;
+
+    case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
+      if (mEndOfDxe) {
+        Status = EFI_ACCESS_DENIED;
+      } else {
+        VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *)SmmVariableFunctionHeader->Data;
+        Status         = VariableLockRequestToLock (
+                           NULL,
+                           VariableToLock->Name,
+                           &VariableToLock->Guid
+                           );
+      }
+
+      break;
+    case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET:
+      if (mEndOfDxe) {
+        Status = EFI_ACCESS_DENIED;
+      } else {
+        CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)SmmVariableFunctionHeader->Data;
+        Status               = VarCheckVariablePropertySet (
+                                 CommVariableProperty->Name,
+                                 &CommVariableProperty->Guid,
+                                 &CommVariableProperty->VariableProperty
+                                 );
+      }
+
+      break;
+    case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET:
+      if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+        DEBUG ((DEBUG_ERROR, "VarCheckVariablePropertyGet: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      //
+      // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+      //
+      CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+      CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *)mVariableBufferPayload;
+      if ((UINTN)(~0) - CommVariableProperty->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+        //
+        // Prevent InfoSize overflow happen
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + CommVariableProperty->NameSize;
+
+      //
+      // SMRAM range check already covered before
+      //
+      if (InfoSize > CommBufferPayloadSize) {
+        DEBUG ((DEBUG_ERROR, "VarCheckVariablePropertyGet: Data size exceed communication buffer size limit!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      //
+      // The VariableSpeculationBarrier() call here is to ensure the previous
+      // range/content checks for the CommBuffer have been completed before the
+      // subsequent consumption of the CommBuffer content.
+      //
+      VariableSpeculationBarrier ();
+      if ((CommVariableProperty->NameSize < sizeof (CHAR16)) || (CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof (CHAR16) - 1] != L'\0')) {
+        //
+        // Make sure VariableName is A Null-terminated string.
+        //
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      Status = VarCheckVariablePropertyGet (
+                 CommVariableProperty->Name,
+                 &CommVariableProperty->Guid,
+                 &CommVariableProperty->VariableProperty
+                 );
+      CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+      break;
+    case SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT:
+      if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM communication buffer size invalid!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      if (mEndOfDxe) {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init context after end of DXE!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      //
+      // Copy the input communicate buffer payload to the pre-allocated SMM variable payload buffer.
+      //
+      CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+      RuntimeVariableCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *)mVariableBufferPayload;
+
+      //
+      // Verify required runtime cache buffers are provided.
+      //
+      if ((RuntimeVariableCacheContext->RuntimeVolatileCache == NULL) ||
+          (RuntimeVariableCacheContext->RuntimeNvCache == NULL) ||
+          (RuntimeVariableCacheContext->PendingUpdate == NULL) ||
+          (RuntimeVariableCacheContext->ReadLock == NULL) ||
+          (RuntimeVariableCacheContext->HobFlushComplete == NULL))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required runtime cache buffer is NULL!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      //
+      // Verify minimum size requirements for the runtime variable store buffers.
+      //
+      if (((RuntimeVariableCacheContext->RuntimeHobCache != NULL) &&
+           (RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof (VARIABLE_STORE_HEADER))) ||
+          (RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof (VARIABLE_STORE_HEADER)) ||
+          (RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof (VARIABLE_STORE_HEADER)))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime cache buffer size is invalid!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      //
+      // Verify runtime buffers do not overlap with SMRAM ranges.
+      //
+      if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL) &&
+          !VariableSmmIsBufferOutsideSmmValid (
+             (UINTN)RuntimeVariableCacheContext->RuntimeHobCache,
+             (UINTN)RuntimeVariableCacheContext->RuntimeHobCache->Size
+             ))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime HOB cache buffer in SMRAM or overflow!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      if (!VariableSmmIsBufferOutsideSmmValid (
+             (UINTN)RuntimeVariableCacheContext->RuntimeVolatileCache,
+             (UINTN)RuntimeVariableCacheContext->RuntimeVolatileCache->Size
+             ))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime volatile cache buffer in SMRAM or overflow!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      if (!VariableSmmIsBufferOutsideSmmValid (
+             (UINTN)RuntimeVariableCacheContext->RuntimeNvCache,
+             (UINTN)RuntimeVariableCacheContext->RuntimeNvCache->Size
+             ))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime non-volatile cache buffer in SMRAM or overflow!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      if (!VariableSmmIsBufferOutsideSmmValid (
+             (UINTN)RuntimeVariableCacheContext->PendingUpdate,
+             sizeof (*(RuntimeVariableCacheContext->PendingUpdate))
+             ))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache pending update buffer in SMRAM or overflow!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      if (!VariableSmmIsBufferOutsideSmmValid (
+             (UINTN)RuntimeVariableCacheContext->ReadLock,
+             sizeof (*(RuntimeVariableCacheContext->ReadLock))
+             ))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache read lock buffer in SMRAM or overflow!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      if (!VariableSmmIsBufferOutsideSmmValid (
+             (UINTN)RuntimeVariableCacheContext->HobFlushComplete,
+             sizeof (*(RuntimeVariableCacheContext->HobFlushComplete))
+             ))
+      {
+        DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache HOB flush complete buffer in SMRAM or overflow!\n"));
+        Status = EFI_ACCESS_DENIED;
+        goto EXIT;
+      }
+
+      VariableCacheContext                                     = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;
+      VariableCacheContext->VariableRuntimeHobCache.Store      = RuntimeVariableCacheContext->RuntimeHobCache;
+      VariableCacheContext->VariableRuntimeVolatileCache.Store = RuntimeVariableCacheContext->RuntimeVolatileCache;
+      VariableCacheContext->VariableRuntimeNvCache.Store       = RuntimeVariableCacheContext->RuntimeNvCache;
+      VariableCacheContext->PendingUpdate                      = RuntimeVariableCacheContext->PendingUpdate;
+      VariableCacheContext->ReadLock                           = RuntimeVariableCacheContext->ReadLock;
+      VariableCacheContext->HobFlushComplete                   = RuntimeVariableCacheContext->HobFlushComplete;
+
+      // Set up the intial pending request since the RT cache needs to be in sync with SMM cache
+      VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;
+      VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;
+      if ((mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) &&
+          (VariableCacheContext->VariableRuntimeHobCache.Store != NULL))
+      {
+        VariableCache                                                     = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+        VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = (UINT32)((UINTN)GetEndPointer (VariableCache) - (UINTN)VariableCache);
+        CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store->Signature), &(VariableCache->Signature));
+      }
+
+      VariableCache                                                          = (VARIABLE_STORE_HEADER  *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+      VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;
+      VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32)((UINTN)GetEndPointer (VariableCache) - (UINTN)VariableCache);
+      CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Store->Signature), &(VariableCache->Signature));
+
+      VariableCache                                                    = (VARIABLE_STORE_HEADER  *)(UINTN)mNvVariableCache;
+      VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;
+      VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = (UINT32)((UINTN)GetEndPointer (VariableCache) - (UINTN)VariableCache);
+      CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store->Signature), &(VariableCache->Signature));
+
+      *(VariableCacheContext->PendingUpdate)    = TRUE;
+      *(VariableCacheContext->ReadLock)         = FALSE;
+      *(VariableCacheContext->HobFlushComplete) = FALSE;
+
+      Status = EFI_SUCCESS;
+      break;
+    case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE:
+      Status = FlushPendingRuntimeVariableCacheUpdates ();
+      break;
+    case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO:
+      if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) {
+        DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication buffer size invalid!\n"));
+        return EFI_SUCCESS;
+      }
+
+      GetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *)SmmVariableFunctionHeader->Data;
+
+      if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {
+        VariableCache                            = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+        GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size;
+      } else {
+        GetRuntimeCacheInfo->TotalHobStorageSize = 0;
+      }
+
+      VariableCache                                   = (VARIABLE_STORE_HEADER  *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+      GetRuntimeCacheInfo->TotalVolatileStorageSize   = VariableCache->Size;
+      VariableCache                                   = (VARIABLE_STORE_HEADER  *)(UINTN)mNvVariableCache;
+      GetRuntimeCacheInfo->TotalNvStorageSize         = (UINTN)VariableCache->Size;
+      GetRuntimeCacheInfo->AuthenticatedVariableUsage = mVariableModuleGlobal->VariableGlobal.AuthFormat;
+
+      Status = EFI_SUCCESS;
+      break;
+
+    default:
+      Status = EFI_UNSUPPORTED;
+  }
+
+EXIT:
+
+  SmmVariableFunctionHeader->ReturnStatus = Status;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  SMM END_OF_DXE protocol notification event handler.
+
+  @param  Protocol   Points to the protocol's unique identifier
+  @param  Interface  Points to the interface instance
+  @param  Handle     The handle on which the interface was installed
+
+  @retval EFI_SUCCESS   SmmEndOfDxeCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeCallback (
+  IN CONST EFI_GUID  *Protocol,
+  IN VOID            *Interface,
+  IN EFI_HANDLE      Handle
+  )
+{
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "[Variable]SMM_END_OF_DXE is signaled\n"));
+  MorLockInitAtEndOfDxe ();
+  Status = LockVariablePolicy ();
+  ASSERT_EFI_ERROR (Status);
+  mEndOfDxe = TRUE;
+  VarCheckLibInitializeAtEndOfDxe (NULL);
+  //
+  // The initialization for variable quota.
+  //
+  InitializeVariableQuota ();
+  if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
+    ReclaimForOS ();
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initializes variable write service for SMM.
+
+**/
+VOID
+VariableWriteServiceInitializeSmm (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = ProtectedVariableLibWriteInit ();
+  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+    DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed. Status = %r\n", Status));
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+  Status = VariableWriteServiceInitialize ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
+  }
+
+  //
+  // Notify the variable wrapper driver the variable write service is ready
+  //
+  VariableNotifySmmWriteReady ();
+}
+
+/**
+  SMM Fault Tolerant Write protocol notification event handler.
+
+  Non-Volatile variable write may needs FTW protocol to reclaim when
+  writting variable.
+
+  @param  Protocol   Points to the protocol's unique identifier
+  @param  Interface  Points to the interface instance
+  @param  Handle     The handle on which the interface was installed
+
+  @retval EFI_SUCCESS   SmmEventCallback runs successfully
+  @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
+
+ **/
+EFI_STATUS
+EFIAPI
+SmmFtwNotificationEvent (
+  IN CONST EFI_GUID  *Protocol,
+  IN VOID            *Interface,
+  IN EFI_HANDLE      Handle
+  )
+{
+  EFI_STATUS                              Status;
+  EFI_PHYSICAL_ADDRESS                    VariableStoreBase;
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;
+  EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;
+  EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;
+  UINTN                                   FtwMaxBlockSize;
+  UINT32                                  NvStorageVariableSize;
+  UINT64                                  NvStorageVariableSize64;
+
+  if (mVariableModuleGlobal->FvbInstance != NULL) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Ensure SMM FTW protocol is installed.
+  //
+  Status = GetFtwProtocol ((VOID **)&FtwProtocol);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GetVariableFlashNvStorageInfo (&NvStorageVariableBase, &NvStorageVariableSize64);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SafeUint64ToUint32 (NvStorageVariableSize64, &NvStorageVariableSize);
+  // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
+  ASSERT_EFI_ERROR (Status);
+
+  ASSERT (NvStorageVariableBase != 0);
+  VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;
+
+  Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+  if (!EFI_ERROR (Status)) {
+    ASSERT (NvStorageVariableSize <= FtwMaxBlockSize);
+  }
+
+  //
+  // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
+  //
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+
+  //
+  // Find the proper FVB protocol for variable.
+  //
+  Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;
+
+  //
+  // Initializes variable write service after FTW was ready.
+  //
+  VariableWriteServiceInitializeSmm ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Variable Driver main entry point. The Variable driver places the 4 EFI
+  runtime services in the EFI System Table and installs arch protocols
+  for variable read and write services being available. It also registers
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+  @retval EFI_SUCCESS       Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MmVariableServiceInitialize (
+  VOID
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_HANDLE                     VariableHandle;
+  VOID                           *SmmFtwRegistration;
+  VOID                           *SmmEndOfDxeRegistration;
+  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
+
+  //
+  // Initialize protected variable service, if enabled.
+  //
+  ContextIn.StructSize    = sizeof (ContextIn);
+  ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+  ContextIn.FindVariableSmm     = NULL;
+  ContextIn.GetVariableInfo     = GetVariableInfo;
+  ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+  ContextIn.UpdateVariableStore = VariableExLibUpdateNvVariable;
+  ContextIn.UpdateVariable      = VariableExLibUpdateVariable;
+
+  ContextIn.MaxVariableSize     = (UINT32)GetMaxVariableSize ();
+  ContextIn.VariableServiceUser = FromSmmModule;
+
+  Status = ProtectedVariableLibInitialize (&ContextIn);
+  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // Variable initialize.
+  //
+  Status = VariableCommonInitialize ();
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Install the Smm Variable Protocol on a new handle.
+  //
+  VariableHandle = NULL;
+  Status         = gMmst->MmInstallProtocolInterface (
+                            &VariableHandle,
+                            &gEfiSmmVariableProtocolGuid,
+                            EFI_NATIVE_INTERFACE,
+                            &gSmmVariable
+                            );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gMmst->MmInstallProtocolInterface (
+                    &VariableHandle,
+                    &gEdkiiSmmVarCheckProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mSmmVarCheck
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  mVariableBufferPayloadSize =  GetMaxVariableSize () +
+                               OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) -
+                               GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
+
+  Status = gMmst->MmAllocatePool (
+                    EfiRuntimeServicesData,
+                    mVariableBufferPayloadSize,
+                    (VOID **)&mVariableBufferPayload
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Register SMM variable SMI handler
+  ///
+  VariableHandle = NULL;
+  Status         = gMmst->MmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Notify the variable wrapper driver the variable service is ready
+  //
+  VariableNotifySmmReady ();
+
+  //
+  // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+  //
+  Status = gMmst->MmRegisterProtocolNotify (
+                    &gEfiMmEndOfDxeProtocolGuid,
+                    SmmEndOfDxeCallback,
+                    &SmmEndOfDxeRegistration
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+    //
+    // Register FtwNotificationEvent () notify function.
+    //
+    Status = gMmst->MmRegisterProtocolNotify (
+                      &gEfiSmmFaultTolerantWriteProtocolGuid,
+                      SmmFtwNotificationEvent,
+                      &SmmFtwRegistration
+                      );
+    ASSERT_EFI_ERROR (Status);
+
+    SmmFtwNotificationEvent (NULL, NULL, NULL);
+  } else {
+    //
+    // Emulated non-volatile variable mode does not depend on FVB and FTW.
+    //
+    VariableWriteServiceInitializeSmm ();
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.c
new file mode 100644
index 000000000000..b88f75370ad8
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -0,0 +1,1895 @@
+/** @file
+  Implement all four UEFI Runtime Variable services for the nonvolatile
+  and volatile storage space and install variable architecture protocol
+  based on SMM variable module.
+
+  Caution: This module requires additional review when modified.
+  This driver will have external input - variable data.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
+  to receive data buffer. The size should be checked carefully.
+
+  InitCommunicateBuffer() is really function to check the variable data size.
+
+Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiDxe.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Variable.h>
+#include <Protocol/MmCommunication2.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/VarCheck.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmUnblockMemoryLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/SmmVariableCommon.h>
+
+#include "PrivilegePolymorphic.h"
+#include "Variable.h"
+#include "VariableParsing.h"
+
+EFI_HANDLE                      mHandle                              = NULL;
+EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable                        = NULL;
+EFI_EVENT                       mVirtualAddressChangeEvent           = NULL;
+EFI_MM_COMMUNICATION2_PROTOCOL  *mMmCommunication2                   = NULL;
+UINT8                           *mVariableBuffer                     = NULL;
+UINT8                           *mVariableBufferPhysical             = NULL;
+VARIABLE_INFO_ENTRY             *mVariableInfo                       = NULL;
+VARIABLE_STORE_HEADER           *mVariableRuntimeHobCacheBuffer      = NULL;
+VARIABLE_STORE_HEADER           *mVariableRuntimeNvCacheBuffer       = NULL;
+VARIABLE_STORE_HEADER           *mVariableRuntimeVolatileCacheBuffer = NULL;
+VARIABLE_STORE_HEADER           *mNvVariableCache                    = NULL;
+VARIABLE_MODULE_GLOBAL          *mVariableModuleGlobal               = NULL;
+UINTN                           mVariableBufferSize;
+UINTN                           mVariableRuntimeHobCacheBufferSize;
+UINTN                           mVariableRuntimeNvCacheBufferSize;
+UINTN                           mVariableRuntimeVolatileCacheBufferSize;
+UINTN                           mVariableBufferPayloadSize;
+BOOLEAN                         mVariableRuntimeCachePendingUpdate;
+BOOLEAN                         mVariableRuntimeCacheReadLock;
+BOOLEAN                         mVariableAuthFormat;
+BOOLEAN                         mHobFlushComplete;
+EFI_LOCK                        mVariableServicesLock;
+EDKII_VARIABLE_LOCK_PROTOCOL    mVariableLock;
+EDKII_VAR_CHECK_PROTOCOL        mVarCheck;
+
+/**
+  The logic to initialize the VariablePolicy engine is in its own file.
+
+**/
+EFI_STATUS
+EFIAPI
+VariablePolicySmmDxeMain (
+  IN    EFI_HANDLE        ImageHandle,
+  IN    EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+  Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData (
+  VOID
+  );
+
+/**
+  Acquires lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function that will be removed when
+  EfiAcquireLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiAcquireLock() at boot time, and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  )
+{
+  if (!EfiAtRuntime ()) {
+    EfiAcquireLock (Lock);
+  }
+}
+
+/**
+  Releases lock only at boot time. Simply returns at runtime.
+
+  This is a temperary function which will be removed when
+  EfiReleaseLock() in UefiLib can handle the call in UEFI
+  Runtimer driver in RT phase.
+  It calls EfiReleaseLock() at boot time and simply returns
+  at runtime.
+
+  @param  Lock         A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+  IN EFI_LOCK  *Lock
+  )
+{
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (Lock);
+  }
+}
+
+/**
+  Return TRUE if ExitBootServices () has been called.
+
+  @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
+**/
+BOOLEAN
+AtRuntime (
+  VOID
+  )
+{
+  return EfiAtRuntime ();
+}
+
+/**
+  Initialize the variable cache buffer as an empty variable store.
+
+  @param[out]     VariableCacheBuffer     A pointer to pointer of a cache variable store.
+  @param[in,out]  TotalVariableCacheSize  On input, the minimum size needed for the UEFI variable store cache
+                                          buffer that is allocated. On output, the actual size of the buffer allocated.
+                                          If TotalVariableCacheSize is zero, a buffer will not be allocated and the
+                                          function will return with EFI_SUCCESS.
+
+  @retval EFI_SUCCESS             The variable cache was allocated and initialized successfully.
+  @retval EFI_INVALID_PARAMETER   A given pointer is NULL or an invalid variable store size was specified.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available to allocate the variable store cache buffer.
+
+**/
+EFI_STATUS
+InitVariableCache (
+  OUT    VARIABLE_STORE_HEADER  **VariableCacheBuffer,
+  IN OUT UINTN                  *TotalVariableCacheSize
+  )
+{
+  VARIABLE_STORE_HEADER  *VariableCacheStorePtr;
+  EFI_STATUS             Status;
+
+  if (TotalVariableCacheSize == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*TotalVariableCacheSize == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if ((VariableCacheBuffer == NULL) || (*TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));
+
+  //
+  // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
+  //
+  *VariableCacheBuffer =  (VARIABLE_STORE_HEADER *)AllocateRuntimePages (
+                                                     EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)
+                                                     );
+  if (*VariableCacheBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Request to unblock the newly allocated cache region to be accessible from inside MM
+  //
+  Status = MmUnblockMemoryRequest (
+             (EFI_PHYSICAL_ADDRESS)(UINTN)*VariableCacheBuffer,
+             EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)
+             );
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  VariableCacheStorePtr = *VariableCacheBuffer;
+  SetMem32 ((VOID *)VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32)0xFFFFFFFF);
+
+  ZeroMem ((VOID *)VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));
+  VariableCacheStorePtr->Size   = (UINT32)*TotalVariableCacheSize;
+  VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;
+  VariableCacheStorePtr->State  = VARIABLE_STORE_HEALTHY;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize the communicate buffer using DataSize and Function.
+
+  The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
+  DataSize.
+
+  Caution: This function may receive untrusted input.
+  The data size external input, so this function will validate it carefully to avoid buffer overflow.
+
+  @param[out]      DataPtr          Points to the data in the communicate buffer.
+  @param[in]       DataSize         The data size to send to SMM.
+  @param[in]       Function         The function number to initialize the communicate header.
+
+  @retval EFI_INVALID_PARAMETER     The data size is too big.
+  @retval EFI_SUCCESS               Find the specified variable.
+
+**/
+EFI_STATUS
+InitCommunicateBuffer (
+  OUT     VOID   **DataPtr OPTIONAL,
+  IN      UINTN  DataSize,
+  IN      UINTN  Function
+  )
+{
+  EFI_MM_COMMUNICATE_HEADER        *SmmCommunicateHeader;
+  SMM_VARIABLE_COMMUNICATE_HEADER  *SmmVariableFunctionHeader;
+
+  if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)mVariableBuffer;
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+  SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+  SmmVariableFunctionHeader->Function = Function;
+  if (DataPtr != NULL) {
+    *DataPtr = SmmVariableFunctionHeader->Data;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Send the data in communicate buffer to SMM.
+
+  @param[in]   DataSize               This size of the function header and the data.
+
+  @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
+  @retval      Others                 Failure is returned from the function in SMM.
+
+**/
+EFI_STATUS
+SendCommunicateBuffer (
+  IN      UINTN  DataSize
+  )
+{
+  EFI_STATUS                       Status;
+  UINTN                            CommSize;
+  EFI_MM_COMMUNICATE_HEADER        *SmmCommunicateHeader;
+  SMM_VARIABLE_COMMUNICATE_HEADER  *SmmVariableFunctionHeader;
+
+  CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+  Status   = mMmCommunication2->Communicate (
+                                  mMmCommunication2,
+                                  mVariableBufferPhysical,
+                                  mVariableBuffer,
+                                  &CommSize
+                                  );
+  ASSERT_EFI_ERROR (Status);
+
+  SmmCommunicateHeader      = (EFI_MM_COMMUNICATE_HEADER *)mVariableBuffer;
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+  return SmmVariableFunctionHeader->ReturnStatus;
+}
+
+/**
+  Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+  @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.
+  @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.
+  @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.
+
+  @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked
+                                as pending to be read-only.
+  @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
+                                Or VariableName is an empty string.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock request.
+**/
+EFI_STATUS
+EFIAPI
+VariableLockRequestToLock (
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL  *This,
+  IN       CHAR16                        *VariableName,
+  IN       EFI_GUID                      *VendorGuid
+  )
+{
+  EFI_STATUS                              Status;
+  UINTN                                   VariableNameSize;
+  UINTN                                   PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE  *VariableToLock;
+
+  if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableNameSize = StrSize (VariableName);
+  VariableToLock   = NULL;
+
+  //
+  // If VariableName exceeds SMM payload limit. Return failure
+  //
+  if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+  //
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
+  Status      = InitCommunicateBuffer ((VOID **)&VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (VariableToLock != NULL);
+
+  CopyGuid (&VariableToLock->Guid, VendorGuid);
+  VariableToLock->NameSize = VariableNameSize;
+  CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
+
+  //
+  // Send data to SMM.
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  Register SetVariable check handler.
+
+  @param[in] Handler            Pointer to check handler.
+
+  @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
+  @retval EFI_INVALID_PARAMETER Handler is NULL.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
+  @retval EFI_UNSUPPORTED       This interface is not implemented.
+                                For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+  IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER  Handler
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Variable property set.
+
+  @param[in] Name               Pointer to the variable name.
+  @param[in] Guid               Pointer to the vendor GUID.
+  @param[in] VariableProperty   Pointer to the input variable property.
+
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+                                or the fields of VariableProperty are not valid.
+  @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+                                already been signaled.
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+  IN CHAR16                       *Name,
+  IN EFI_GUID                     *Guid,
+  IN VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty
+  )
+{
+  EFI_STATUS                                            Status;
+  UINTN                                                 VariableNameSize;
+  UINTN                                                 PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY  *CommVariableProperty;
+
+  if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableProperty == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableNameSize     = StrSize (Name);
+  CommVariableProperty = NULL;
+
+  //
+  // If VariableName exceeds SMM payload limit. Return failure
+  //
+  if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+  //
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
+  Status      = InitCommunicateBuffer ((VOID **)&CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (CommVariableProperty != NULL);
+
+  CopyGuid (&CommVariableProperty->Guid, Guid);
+  CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
+  CommVariableProperty->NameSize = VariableNameSize;
+  CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
+
+  //
+  // Send data to SMM.
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  Variable property get.
+
+  @param[in]  Name              Pointer to the variable name.
+  @param[in]  Guid              Pointer to the vendor GUID.
+  @param[out] VariableProperty  Pointer to the output variable property.
+
+  @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
+  @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+  @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+  IN CHAR16                        *Name,
+  IN EFI_GUID                      *Guid,
+  OUT VAR_CHECK_VARIABLE_PROPERTY  *VariableProperty
+  )
+{
+  EFI_STATUS                                            Status;
+  UINTN                                                 VariableNameSize;
+  UINTN                                                 PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY  *CommVariableProperty;
+
+  if ((Name == NULL) || (Name[0] == 0) || (Guid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableProperty == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableNameSize     = StrSize (Name);
+  CommVariableProperty = NULL;
+
+  //
+  // If VariableName exceeds SMM payload limit. Return failure
+  //
+  if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+  //
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
+  Status      = InitCommunicateBuffer ((VOID **)&CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (CommVariableProperty != NULL);
+
+  CopyGuid (&CommVariableProperty->Guid, Guid);
+  CommVariableProperty->NameSize = VariableNameSize;
+  CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
+
+  //
+  // Send data to SMM.
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+  if (Status == EFI_SUCCESS) {
+    CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
+  }
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  Signals SMM to synchronize any pending variable updates with the runtime cache(s).
+
+**/
+VOID
+SyncRuntimeCache (
+  VOID
+  )
+{
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+  //
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);
+
+  //
+  // Send data to SMM.
+  //
+  SendCommunicateBuffer (0);
+}
+
+/**
+  Check whether a SMI must be triggered to retrieve pending cache updates.
+
+  If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
+  will prevent the HOB cache from being used for future runtime cache hits.
+
+**/
+VOID
+CheckForRuntimeCacheSync (
+  VOID
+  )
+{
+  if (mVariableRuntimeCachePendingUpdate) {
+    SyncRuntimeCache ();
+  }
+
+  ASSERT (!mVariableRuntimeCachePendingUpdate);
+
+  //
+  // The HOB variable data may have finished being flushed in the runtime cache sync update
+  //
+  if (mHobFlushComplete && (mVariableRuntimeHobCacheBuffer != NULL)) {
+    if (!EfiAtRuntime ()) {
+      FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));
+    }
+
+    mVariableRuntimeHobCacheBuffer = NULL;
+  }
+}
+
+/**
+  Finds the given variable in a runtime cache variable store.
+
+  Caution: This function may receive untrusted input.
+  The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+  @param[in]      VariableName       Name of Variable to be found.
+  @param[in]      VendorGuid         Variable vendor GUID.
+  @param[out]     Attributes         Attribute value of the variable found.
+  @param[in, out] DataSize           Size of Data found. If size is less than the
+                                     data, this value contains the required size.
+  @param[out]     Data               Data pointer.
+
+  @retval EFI_SUCCESS                Found the specified variable.
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_NOT_FOUND              The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInRuntimeCache (
+  IN      CHAR16    *VariableName,
+  IN      EFI_GUID  *VendorGuid,
+  OUT     UINT32    *Attributes OPTIONAL,
+  IN OUT  UINTN     *DataSize,
+  OUT     VOID      *Data OPTIONAL
+  )
+{
+  EFI_STATUS              Status;
+  VARIABLE_POINTER_TRACK  RtPtrTrack;
+  VARIABLE_STORE_TYPE     StoreType;
+  VARIABLE_STORE_HEADER   *VariableStoreList[VariableStoreTypeMax];
+
+  Status = EFI_NOT_FOUND;
+
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack));
+
+  //
+  // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
+  // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
+  // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
+  // cache read lock should always be free when entering this function.
+  //
+  ASSERT (!mVariableRuntimeCacheReadLock);
+
+  mVariableRuntimeCacheReadLock = TRUE;
+  CheckForRuntimeCacheSync ();
+
+  if (!mVariableRuntimeCachePendingUpdate) {
+    //
+    // 0: Volatile, 1: HOB, 2: Non-Volatile.
+    // The index and attributes mapping must be kept in this order as FindVariable
+    // makes use of this mapping to implement search algorithm.
+    //
+    VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
+    VariableStoreList[VariableStoreTypeHob]      = mVariableRuntimeHobCacheBuffer;
+    VariableStoreList[VariableStoreTypeNv]       = mVariableRuntimeNvCacheBuffer;
+
+    for (StoreType = (VARIABLE_STORE_TYPE)0; StoreType < VariableStoreTypeMax; StoreType++) {
+      if (VariableStoreList[StoreType] == NULL) {
+        continue;
+      }
+
+      RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+      RtPtrTrack.EndPtr   = GetEndPointer (VariableStoreList[StoreType]);
+      RtPtrTrack.Volatile = (BOOLEAN)(StoreType == VariableStoreTypeVolatile);
+
+      Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);
+      if (!EFI_ERROR (Status)) {
+        break;
+      }
+    }
+
+    if (!EFI_ERROR (Status)) {
+      //
+      // Get data size
+      //
+      if (!RtPtrTrack.Volatile) {
+        //
+        // Currently only non-volatile variable needs protection.
+        //
+        Status = ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize, mVariableAuthFormat);
+      }
+
+      if (RtPtrTrack.Volatile || (Status == EFI_UNSUPPORTED)) {
+        Status = GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)DataSize, mVariableAuthFormat);
+      }
+
+      if (!EFI_ERROR (Status)) {
+        UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, FALSE, &mVariableInfo);
+      }
+    }
+  }
+
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
+    if ((Attributes != NULL) && (RtPtrTrack.CurrPtr != NULL)) {
+      *Attributes = RtPtrTrack.CurrPtr->Attributes;
+    }
+  }
+
+  mVariableRuntimeCacheReadLock = FALSE;
+
+  return Status;
+}
+
+/**
+  Finds the given variable in a variable store in SMM.
+
+  Caution: This function may receive untrusted input.
+  The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+  @param[in]      VariableName       Name of Variable to be found.
+  @param[in]      VendorGuid         Variable vendor GUID.
+  @param[out]     Attributes         Attribute value of the variable found.
+  @param[in, out] DataSize           Size of Data found. If size is less than the
+                                     data, this value contains the required size.
+  @param[out]     Data               Data pointer.
+
+  @retval EFI_SUCCESS                Found the specified variable.
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_NOT_FOUND              The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+FindVariableInSmm (
+  IN      CHAR16    *VariableName,
+  IN      EFI_GUID  *VendorGuid,
+  OUT     UINT32    *Attributes OPTIONAL,
+  IN OUT  UINTN     *DataSize,
+  OUT     VOID      *Data OPTIONAL
+  )
+{
+  EFI_STATUS                                Status;
+  UINTN                                     PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
+  UINTN                                     TempDataSize;
+  UINTN                                     VariableNameSize;
+
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  TempDataSize      = *DataSize;
+  VariableNameSize  = StrSize (VariableName);
+  SmmVariableHeader = NULL;
+
+  //
+  // If VariableName exceeds SMM payload limit. Return failure
+  //
+  if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+  //
+  if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
+    //
+    // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
+    //
+    TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
+  }
+
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
+
+  Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (SmmVariableHeader != NULL);
+
+  CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
+  SmmVariableHeader->DataSize = TempDataSize;
+  SmmVariableHeader->NameSize = VariableNameSize;
+  if (Attributes == NULL) {
+    SmmVariableHeader->Attributes = 0;
+  } else {
+    SmmVariableHeader->Attributes = *Attributes;
+  }
+
+  CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
+
+  //
+  // Send data to SMM.
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+
+  //
+  // Get data from SMM.
+  //
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
+    //
+    // SMM CommBuffer DataSize can be a trimed value
+    // Only update DataSize when needed
+    //
+    *DataSize = SmmVariableHeader->DataSize;
+  }
+
+  if (Attributes != NULL) {
+    *Attributes = SmmVariableHeader->Attributes;
+  }
+
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  if (Data != NULL) {
+    CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+  }
+
+Done:
+  return Status;
+}
+
+/**
+  This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+  Caution: This function may receive untrusted input.
+  The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+  @param[in]      VariableName       Name of Variable to be found.
+  @param[in]      VendorGuid         Variable vendor GUID.
+  @param[out]     Attributes         Attribute value of the variable found.
+  @param[in, out] DataSize           Size of Data found. If size is less than the
+                                     data, this value contains the required size.
+  @param[out]     Data               Data pointer.
+
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_SUCCESS                Find the specified variable.
+  @retval EFI_NOT_FOUND              Not found.
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceGetVariable (
+  IN      CHAR16    *VariableName,
+  IN      EFI_GUID  *VendorGuid,
+  OUT     UINT32    *Attributes OPTIONAL,
+  IN OUT  UINTN     *DataSize,
+  OUT     VOID      *Data
+  )
+{
+  EFI_STATUS  Status;
+
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableName[0] == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+    Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);
+  } else {
+    Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);
+  }
+
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+  return Status;
+}
+
+/**
+  Finds the next available variable in a runtime cache variable store.
+
+  @param[in, out] VariableNameSize   Size of the variable name.
+  @param[in, out] VariableName       Pointer to variable name.
+  @param[in, out] VendorGuid         Variable Vendor Guid.
+
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_SUCCESS                Find the specified variable.
+  @retval EFI_NOT_FOUND              Not found.
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
+
+**/
+EFI_STATUS
+GetNextVariableNameInRuntimeCache (
+  IN OUT  UINTN     *VariableNameSize,
+  IN OUT  CHAR16    *VariableName,
+  IN OUT  EFI_GUID  *VendorGuid
+  )
+{
+  EFI_STATUS             Status;
+  UINTN                  VarNameSize;
+  VARIABLE_HEADER        *VariablePtr;
+  VARIABLE_STORE_HEADER  *VariableStoreHeader[VariableStoreTypeMax];
+
+  Status = EFI_NOT_FOUND;
+
+  //
+  // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
+  // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
+  // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
+  // cache read lock should always be free when entering this function.
+  //
+  ASSERT (!mVariableRuntimeCacheReadLock);
+
+  CheckForRuntimeCacheSync ();
+
+  mVariableRuntimeCacheReadLock = TRUE;
+  if (!mVariableRuntimeCachePendingUpdate) {
+    //
+    // 0: Volatile, 1: HOB, 2: Non-Volatile.
+    // The index and attributes mapping must be kept in this order as FindVariable
+    // makes use of this mapping to implement search algorithm.
+    //
+    VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
+    VariableStoreHeader[VariableStoreTypeHob]      = mVariableRuntimeHobCacheBuffer;
+    VariableStoreHeader[VariableStoreTypeNv]       = mVariableRuntimeNvCacheBuffer;
+
+    Status =  VariableServiceGetNextVariableInternal (
+                VariableName,
+                VendorGuid,
+                VariableStoreHeader,
+                &VariablePtr,
+                mVariableAuthFormat
+                );
+    if (!EFI_ERROR (Status)) {
+      VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);
+      ASSERT (VarNameSize != 0);
+      if (VarNameSize <= *VariableNameSize) {
+        CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);
+        CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));
+        Status = EFI_SUCCESS;
+      } else {
+        Status = EFI_BUFFER_TOO_SMALL;
+      }
+
+      *VariableNameSize = VarNameSize;
+    }
+  }
+
+  mVariableRuntimeCacheReadLock = FALSE;
+
+  return Status;
+}
+
+/**
+  Finds the next available variable in a SMM variable store.
+
+  @param[in, out] VariableNameSize   Size of the variable name.
+  @param[in, out] VariableName       Pointer to variable name.
+  @param[in, out] VendorGuid         Variable Vendor Guid.
+
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_SUCCESS                Find the specified variable.
+  @retval EFI_NOT_FOUND              Not found.
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
+
+**/
+EFI_STATUS
+GetNextVariableNameInSmm (
+  IN OUT  UINTN     *VariableNameSize,
+  IN OUT  CHAR16    *VariableName,
+  IN OUT  EFI_GUID  *VendorGuid
+  )
+{
+  EFI_STATUS                                       Status;
+  UINTN                                            PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME  *SmmGetNextVariableName;
+  UINTN                                            OutVariableNameSize;
+  UINTN                                            InVariableNameSize;
+
+  OutVariableNameSize    = *VariableNameSize;
+  InVariableNameSize     = StrSize (VariableName);
+  SmmGetNextVariableName = NULL;
+
+  //
+  // If input string exceeds SMM payload limit. Return failure
+  //
+  if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+  //
+  if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+    //
+    // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
+    //
+    OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
+  }
+
+  //
+  // Payload should be Guid + NameSize + MAX of Input & Output buffer
+  //
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
+
+  Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (SmmGetNextVariableName != NULL);
+
+  //
+  // SMM comm buffer->NameSize is buffer size for return string
+  //
+  SmmGetNextVariableName->NameSize = OutVariableNameSize;
+
+  CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
+  //
+  // Copy whole string
+  //
+  CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
+  if (OutVariableNameSize > InVariableNameSize) {
+    ZeroMem ((UINT8 *)SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
+  }
+
+  //
+  // Send data to SMM
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+
+  //
+  // Get data from SMM.
+  //
+  if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
+    //
+    // SMM CommBuffer NameSize can be a trimed value
+    // Only update VariableNameSize when needed
+    //
+    *VariableNameSize = SmmGetNextVariableName->NameSize;
+  }
+
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
+  CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
+
+Done:
+  return Status;
+}
+
+/**
+  This code Finds the Next available variable.
+
+  @param[in, out] VariableNameSize   Size of the variable name.
+  @param[in, out] VariableName       Pointer to variable name.
+  @param[in, out] VendorGuid         Variable Vendor Guid.
+
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_SUCCESS                Find the specified variable.
+  @retval EFI_NOT_FOUND              Not found.
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceGetNextVariableName (
+  IN OUT  UINTN     *VariableNameSize,
+  IN OUT  CHAR16    *VariableName,
+  IN OUT  EFI_GUID  *VendorGuid
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       MaxLen;
+
+  Status = EFI_NOT_FOUND;
+
+  if ((VariableNameSize == NULL) || (VariableName == NULL) || (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Calculate the possible maximum length of name string, including the Null terminator.
+  //
+  MaxLen = *VariableNameSize / sizeof (CHAR16);
+  if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
+    //
+    // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
+    // follow spec to return EFI_INVALID_PARAMETER.
+    //
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+    Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);
+  } else {
+    Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);
+  }
+
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+  return Status;
+}
+
+/**
+  This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+  Caution: This function may receive untrusted input.
+  The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
+
+  @param[in] VariableName                 Name of Variable to be found.
+  @param[in] VendorGuid                   Variable vendor GUID.
+  @param[in] Attributes                   Attribute value of the variable found
+  @param[in] DataSize                     Size of Data found. If size is less than the
+                                          data, this value contains the required size.
+  @param[in] Data                         Data pointer.
+
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.
+  @retval EFI_SUCCESS                     Set successfully.
+  @retval EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
+  @retval EFI_NOT_FOUND                   Not found.
+  @retval EFI_WRITE_PROTECTED             Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceSetVariable (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINT32    Attributes,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  EFI_STATUS                                Status;
+  UINTN                                     PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
+  UINTN                                     VariableNameSize;
+
+  //
+  // Check input parameters.
+  //
+  if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((DataSize != 0) && (Data == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableNameSize  = StrSize (VariableName);
+  SmmVariableHeader = NULL;
+
+  //
+  // If VariableName or DataSize exceeds SMM payload limit. Return failure
+  //
+  if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+      (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+  //
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
+  Status      = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (SmmVariableHeader != NULL);
+
+  CopyGuid ((EFI_GUID *)&SmmVariableHeader->Guid, VendorGuid);
+  SmmVariableHeader->DataSize   = DataSize;
+  SmmVariableHeader->NameSize   = VariableNameSize;
+  SmmVariableHeader->Attributes = Attributes;
+  CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
+  CopyMem ((UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
+
+  //
+  // Send data to SMM.
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+  if (!EfiAtRuntime ()) {
+    if (!EFI_ERROR (Status)) {
+      SecureBootHook (
+        VariableName,
+        VendorGuid
+        );
+    }
+  }
+
+  return Status;
+}
+
+/**
+  This code returns information about the EFI variables.
+
+  @param[in]  Attributes                   Attributes bitmask to specify the type of variables
+                                           on which to return information.
+  @param[out] MaximumVariableStorageSize   Pointer to the maximum size of the storage space available
+                                           for the EFI variables associated with the attributes specified.
+  @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+                                           for EFI variables associated with the attributes specified.
+  @param[out] MaximumVariableSize          Pointer to the maximum size of an individual EFI variables
+                                           associated with the attributes specified.
+
+  @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.
+  @retval EFI_SUCCESS                      Query successfully.
+  @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceQueryVariableInfo (
+  IN  UINT32  Attributes,
+  OUT UINT64  *MaximumVariableStorageSize,
+  OUT UINT64  *RemainingVariableStorageSize,
+  OUT UINT64  *MaximumVariableSize
+  )
+{
+  EFI_STATUS                                    Status;
+  UINTN                                         PayloadSize;
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO  *SmmQueryVariableInfo;
+
+  SmmQueryVariableInfo = NULL;
+
+  if ((MaximumVariableStorageSize == NULL) || (RemainingVariableStorageSize == NULL) || (MaximumVariableSize == NULL) || (Attributes == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
+  //
+  PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
+  Status      = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  ASSERT (SmmQueryVariableInfo != NULL);
+
+  SmmQueryVariableInfo->Attributes = Attributes;
+
+  //
+  // Send data to SMM.
+  //
+  Status = SendCommunicateBuffer (PayloadSize);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Get data from SMM.
+  //
+  *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;
+  *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;
+  *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  Exit Boot Services Event notification handler.
+
+  Notify SMM variable driver about the event.
+
+  @param[in]  Event     Event whose notification function is being invoked.
+  @param[in]  Context   Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnExitBootServices (
+  IN      EFI_EVENT  Event,
+  IN      VOID       *Context
+  )
+{
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+  //
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
+
+  //
+  // Send data to SMM.
+  //
+  SendCommunicateBuffer (0);
+}
+
+/**
+  On Ready To Boot Services Event notification handler.
+
+  Notify SMM variable driver about the event.
+
+  @param[in]  Event     Event whose notification function is being invoked
+  @param[in]  Context   Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+  IN      EFI_EVENT  Event,
+  IN      VOID       *Context
+  )
+{
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+  //
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
+
+  //
+  // Send data to SMM.
+  //
+  SendCommunicateBuffer (0);
+
+  //
+  // Install the system configuration table for variable info data captured
+  //
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {
+    if (mVariableAuthFormat) {
+      gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);
+    } else {
+      gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);
+    }
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+  It convers pointer to new virtual address.
+
+  @param[in]  Event        Event whose notification function is being invoked.
+  @param[in]  Context      Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableAddressChangeEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EfiConvertPointer (0x0, (VOID **)&mVariableBuffer);
+  EfiConvertPointer (0x0, (VOID **)&mMmCommunication2);
+  EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mVariableRuntimeHobCacheBuffer);
+  EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mVariableRuntimeNvCacheBuffer);
+  EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mVariableRuntimeVolatileCacheBuffer);
+}
+
+/**
+  This code gets variable payload size.
+
+  @param[out] VariablePayloadSize   Output pointer to variable payload size.
+
+  @retval EFI_SUCCESS               Get successfully.
+  @retval Others                    Get unsuccessfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariablePayloadSize (
+  OUT UINTN  *VariablePayloadSize
+  )
+{
+  EFI_STATUS                                 Status;
+  SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE  *SmmGetPayloadSize;
+  EFI_MM_COMMUNICATE_HEADER                  *SmmCommunicateHeader;
+  SMM_VARIABLE_COMMUNICATE_HEADER            *SmmVariableFunctionHeader;
+  UINTN                                      CommSize;
+  UINT8                                      *CommBuffer;
+
+  SmmGetPayloadSize = NULL;
+  CommBuffer        = NULL;
+
+  if (VariablePayloadSize == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+  //
+  CommSize   = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+  CommBuffer = AllocateZeroPool (CommSize);
+  if (CommBuffer == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+  SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+  SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
+  SmmGetPayloadSize                   = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *)SmmVariableFunctionHeader->Data;
+
+  //
+  // Send data to SMM.
+  //
+  Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SmmVariableFunctionHeader->ReturnStatus;
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Get data from SMM.
+  //
+  *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
+
+Done:
+  if (CommBuffer != NULL) {
+    FreePool (CommBuffer);
+  }
+
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  This code gets information needed from SMM for runtime cache initialization.
+
+  @param[out] TotalHobStorageSize         Output pointer for the total HOB storage size in bytes.
+  @param[out] TotalNvStorageSize          Output pointer for the total non-volatile storage size in bytes.
+  @param[out] TotalVolatileStorageSize    Output pointer for the total volatile storage size in bytes.
+  @param[out] AuthenticatedVariableUsage  Output pointer that indicates if authenticated variables are to be used.
+
+  @retval EFI_SUCCESS                     Retrieved the size successfully.
+  @retval EFI_INVALID_PARAMETER           TotalNvStorageSize parameter is NULL.
+  @retval EFI_OUT_OF_RESOURCES            The memory resources needed for a CommBuffer are not available.
+  @retval Others                          Could not retrieve the size successfully.
+
+**/
+EFI_STATUS
+GetRuntimeCacheInfo (
+  OUT UINTN    *TotalHobStorageSize,
+  OUT UINTN    *TotalNvStorageSize,
+  OUT UINTN    *TotalVolatileStorageSize,
+  OUT BOOLEAN  *AuthenticatedVariableUsage
+  )
+{
+  EFI_STATUS                                       Status;
+  SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO  *SmmGetRuntimeCacheInfo;
+  EFI_MM_COMMUNICATE_HEADER                        *SmmCommunicateHeader;
+  SMM_VARIABLE_COMMUNICATE_HEADER                  *SmmVariableFunctionHeader;
+  UINTN                                            CommSize;
+  UINT8                                            *CommBuffer;
+
+  SmmGetRuntimeCacheInfo = NULL;
+  CommBuffer             = mVariableBuffer;
+
+  if ((TotalHobStorageSize == NULL) || (TotalNvStorageSize == NULL) || (TotalVolatileStorageSize == NULL) || (AuthenticatedVariableUsage == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (CommBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
+  ZeroMem (CommBuffer, CommSize);
+
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+  SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
+
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+  SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;
+  SmmGetRuntimeCacheInfo              = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *)SmmVariableFunctionHeader->Data;
+
+  //
+  // Send data to SMM.
+  //
+  Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);
+  ASSERT_EFI_ERROR (Status);
+  if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    goto Done;
+  }
+
+  Status = SmmVariableFunctionHeader->ReturnStatus;
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Get data from SMM.
+  //
+  *TotalHobStorageSize        = SmmGetRuntimeCacheInfo->TotalHobStorageSize;
+  *TotalNvStorageSize         = SmmGetRuntimeCacheInfo->TotalNvStorageSize;
+  *TotalVolatileStorageSize   = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;
+  *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  Sends the runtime variable cache context information to SMM.
+
+  @retval EFI_SUCCESS               Retrieved the size successfully.
+  @retval EFI_INVALID_PARAMETER     TotalNvStorageSize parameter is NULL.
+  @retval EFI_OUT_OF_RESOURCES      The memory resources needed for a CommBuffer are not available.
+  @retval Others                    Could not retrieve the size successfully.;
+
+**/
+EFI_STATUS
+SendRuntimeVariableCacheContextToSmm (
+  VOID
+  )
+{
+  EFI_STATUS                                               Status;
+  SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT  *SmmRuntimeVarCacheContext;
+  EFI_MM_COMMUNICATE_HEADER                                *SmmCommunicateHeader;
+  SMM_VARIABLE_COMMUNICATE_HEADER                          *SmmVariableFunctionHeader;
+  UINTN                                                    CommSize;
+  UINT8                                                    *CommBuffer;
+
+  SmmRuntimeVarCacheContext = NULL;
+  CommBuffer                = mVariableBuffer;
+
+  if (CommBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+  //
+  // Init the communicate buffer. The buffer data size is:
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+  //
+  CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+  ZeroMem (CommBuffer, CommSize);
+
+  SmmCommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+  SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+
+  SmmVariableFunctionHeader           = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+  SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;
+  SmmRuntimeVarCacheContext           = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *)SmmVariableFunctionHeader->Data;
+
+  SmmRuntimeVarCacheContext->RuntimeHobCache      = mVariableRuntimeHobCacheBuffer;
+  SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;
+  SmmRuntimeVarCacheContext->RuntimeNvCache       = mVariableRuntimeNvCacheBuffer;
+  SmmRuntimeVarCacheContext->PendingUpdate        = &mVariableRuntimeCachePendingUpdate;
+  SmmRuntimeVarCacheContext->ReadLock             = &mVariableRuntimeCacheReadLock;
+  SmmRuntimeVarCacheContext->HobFlushComplete     = &mHobFlushComplete;
+
+  //
+  // Request to unblock this region to be accessible from inside MM environment
+  // These fields "should" be all on the same page, but just to be on the safe side...
+  //
+  Status = MmUnblockMemoryRequest (
+             (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE ((UINTN)SmmRuntimeVarCacheContext->PendingUpdate - EFI_PAGE_SIZE + 1, EFI_PAGE_SIZE),
+             EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCachePendingUpdate))
+             );
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = MmUnblockMemoryRequest (
+             (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE ((UINTN)SmmRuntimeVarCacheContext->ReadLock - EFI_PAGE_SIZE + 1, EFI_PAGE_SIZE),
+             EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCacheReadLock))
+             );
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = MmUnblockMemoryRequest (
+             (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE ((UINTN)SmmRuntimeVarCacheContext->HobFlushComplete - EFI_PAGE_SIZE + 1, EFI_PAGE_SIZE),
+             EFI_SIZE_TO_PAGES (sizeof (mHobFlushComplete))
+             );
+  if ((Status != EFI_UNSUPPORTED) && EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Send data to SMM.
+  //
+  Status = mMmCommunication2->Communicate (mMmCommunication2, CommBuffer, CommBuffer, &CommSize);
+  ASSERT_EFI_ERROR (Status);
+  if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    goto Done;
+  }
+
+  Status = SmmVariableFunctionHeader->ReturnStatus;
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+Done:
+  ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+  return Status;
+}
+
+/**
+  Initialize variable service and install Variable Architectural protocol.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmVariableReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
+
+  Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **)&mMmCommunication2);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Allocate memory for variable communicate buffer.
+  //
+  Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
+  ASSERT_EFI_ERROR (Status);
+  mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
+  mVariableBuffer     = AllocateRuntimePool (mVariableBufferSize);
+  ASSERT (mVariableBuffer != NULL);
+
+  //
+  // Save the buffer physical address used for SMM conmunication.
+  //
+  mVariableBufferPhysical = mVariableBuffer;
+
+  if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+    DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));
+    //
+    // Allocate runtime variable cache memory buffers.
+    //
+    Status =  GetRuntimeCacheInfo (
+                &mVariableRuntimeHobCacheBufferSize,
+                &mVariableRuntimeNvCacheBufferSize,
+                &mVariableRuntimeVolatileCacheBufferSize,
+                &mVariableAuthFormat
+                );
+    if (!EFI_ERROR (Status)) {
+      Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);
+      if (!EFI_ERROR (Status)) {
+        Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);
+        if (!EFI_ERROR (Status)) {
+          Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);
+          if (!EFI_ERROR (Status)) {
+            Status = SendRuntimeVariableCacheContextToSmm ();
+            if (!EFI_ERROR (Status)) {
+              SyncRuntimeCache ();
+            }
+          }
+        }
+      }
+
+      if (EFI_ERROR (Status)) {
+        mVariableRuntimeHobCacheBuffer      = NULL;
+        mVariableRuntimeNvCacheBuffer       = NULL;
+        mVariableRuntimeVolatileCacheBuffer = NULL;
+      }
+    }
+
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));
+  }
+
+  gRT->GetVariable         = RuntimeServiceGetVariable;
+  gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
+  gRT->SetVariable         = RuntimeServiceSetVariable;
+  gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;
+
+  //
+  // Install the Variable Architectural Protocol on a new handle.
+  //
+  Status = gBS->InstallProtocolInterface (
+                  &mHandle,
+                  &gEfiVariableArchProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  mVariableLock.RequestToLock = VariableLockRequestToLock;
+  Status                      = gBS->InstallMultipleProtocolInterfaces (
+                                       &mHandle,
+                                       &gEdkiiVariableLockProtocolGuid,
+                                       &mVariableLock,
+                                       NULL
+                                       );
+  ASSERT_EFI_ERROR (Status);
+
+  mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
+  mVarCheck.VariablePropertySet             = VarCheckVariablePropertySet;
+  mVarCheck.VariablePropertyGet             = VarCheckVariablePropertyGet;
+  Status                                    = gBS->InstallMultipleProtocolInterfaces (
+                                                     &mHandle,
+                                                     &gEdkiiVarCheckProtocolGuid,
+                                                     &mVarCheck,
+                                                     NULL
+                                                     );
+  ASSERT_EFI_ERROR (Status);
+
+  ContextIn.StructSize    = sizeof (ContextIn);
+  ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+
+  ContextIn.FindVariableSmm     = FindVariableInSmm;
+  ContextIn.GetVariableInfo     = GetVariableInfo;
+  ContextIn.GetNextVariableInfo = GetNextVariableInfo;
+  ContextIn.VariableServiceUser = FromRuntimeModule;
+  ContextIn.MaxVariableSize     = 0;
+  ContextIn.UpdateVariableStore = NULL;
+  ContextIn.UpdateVariable      = NULL;
+
+  Status = ProtectedVariableLibInitialize (&ContextIn);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: %d ProtectedVariableLibInitialize() return status: %r\n",
+      __FUNCTION__,
+      __LINE__,
+      Status
+      ));
+  }
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  SMM Non-Volatile variable write service is ready notify event handler.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmVariableWriteReady (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *ProtocolOps;
+
+  //
+  // Check whether the protocol is installed or not.
+  //
+  Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **)&ProtocolOps);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
+  // Secure Boot Policy Variable change.  Record their initial value.
+  //
+  RecordSecureBootPolicyVarData ();
+
+  Status = gBS->InstallProtocolInterface (
+                  &mHandle,
+                  &gEfiVariableWriteArchProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Variable Driver main entry point. The Variable driver places the 4 EFI
+  runtime services in the EFI System Table and installs arch protocols
+  for variable read and write services being available. It also registers
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableSmmRuntimeInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  VOID       *SmmVariableRegistration;
+  VOID       *SmmVariableWriteRegistration;
+  EFI_EVENT  OnReadyToBootEvent;
+  EFI_EVENT  ExitBootServiceEvent;
+  EFI_EVENT  LegacyBootEvent;
+
+  EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
+
+  //
+  // Smm variable service is ready
+  //
+  EfiCreateProtocolNotifyEvent (
+    &gEfiSmmVariableProtocolGuid,
+    TPL_CALLBACK,
+    SmmVariableReady,
+    NULL,
+    &SmmVariableRegistration
+    );
+
+  //
+  // Smm Non-Volatile variable write service is ready
+  //
+  EfiCreateProtocolNotifyEvent (
+    &gSmmVariableWriteGuid,
+    TPL_CALLBACK,
+    SmmVariableWriteReady,
+    NULL,
+    &SmmVariableWriteRegistration
+    );
+
+  //
+  // Register the event to reclaim variable for OS usage.
+  //
+  EfiCreateEventReadyToBootEx (
+    TPL_NOTIFY,
+    OnReadyToBoot,
+    NULL,
+    &OnReadyToBootEvent
+    );
+
+  //
+  // Register the event to inform SMM variable that it is at runtime.
+  //
+  gBS->CreateEventEx (
+         EVT_NOTIFY_SIGNAL,
+         TPL_NOTIFY,
+         OnExitBootServices,
+         NULL,
+         &gEfiEventExitBootServicesGuid,
+         &ExitBootServiceEvent
+         );
+
+  //
+  // Register the event to inform SMM variable that it is at runtime for legacy boot.
+  // Reuse OnExitBootServices() here.
+  //
+  EfiCreateEventLegacyBootEx (
+    TPL_NOTIFY,
+    OnExitBootServices,
+    NULL,
+    &LegacyBootEvent
+    );
+
+  //
+  // Register the event to convert the pointer for runtime.
+  //
+  gBS->CreateEventEx (
+         EVT_NOTIFY_SIGNAL,
+         TPL_NOTIFY,
+         VariableAddressChangeEvent,
+         NULL,
+         &gEfiEventVirtualAddressChangeGuid,
+         &mVirtualAddressChangeEvent
+         );
+
+  // Initialize the VariablePolicy protocol and engine.
+  VariablePolicySmmDxeMain (ImageHandle, SystemTable);
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.c
new file mode 100644
index 000000000000..943993eb6738
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.c
@@ -0,0 +1,89 @@
+/** @file
+
+  Parts of the SMM/MM implementation that are specific to standalone MM
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+
+/**
+  This function checks if the buffer is valid per processor architecture and
+  does not overlap with SMRAM.
+
+  @param Buffer The buffer start address to be checked.
+  @param Length The buffer length to be checked.
+
+  @retval TRUE  This buffer is valid per processor architecture and does not
+                overlap with SMRAM.
+  @retval FALSE This buffer is not valid per processor architecture or overlaps
+                with SMRAM.
+**/
+BOOLEAN
+VariableSmmIsBufferOutsideSmmValid (
+  IN EFI_PHYSICAL_ADDRESS  Buffer,
+  IN UINT64                Length
+  )
+{
+  return TRUE;
+}
+
+/**
+  Notify the system that the SMM variable driver is ready.
+**/
+VOID
+VariableNotifySmmReady (
+  VOID
+  )
+{
+}
+
+/**
+  Notify the system that the SMM variable write driver is ready.
+**/
+VOID
+VariableNotifySmmWriteReady (
+  VOID
+  )
+{
+}
+
+/**
+  Variable service MM driver entry point.
+
+  @param[in] ImageHandle    A handle for the image that is initializing this
+                            driver
+  @param[in] MmSystemTable  A pointer to the MM system table
+
+  @retval EFI_SUCCESS       Variable service successfully initialized.
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_MM_SYSTEM_TABLE  *MmSystemTable
+  )
+{
+  return MmVariableServiceInitialize ();
+}
+
+/**
+  Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
+  This information is used by the MorLock code to infer whether an existing
+  MOR variable is legitimate or not.
+
+  @retval TRUE  Either the TCG or TCG2 protocol is installed in the UEFI
+                protocol database
+  @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
+                protocol database
+**/
+BOOLEAN
+VariableHaveTcgProtocols (
+  VOID
+  )
+{
+  return FALSE;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditionalMm.c b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditionalMm.c
new file mode 100644
index 000000000000..0369c3cd01b1
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditionalMm.c
@@ -0,0 +1,130 @@
+/** @file
+
+  Parts of the SMM/MM implementation that are specific to traditional MM
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmMemLib.h>
+#include "Variable.h"
+
+/**
+  This function checks if the buffer is valid per processor architecture and
+  does not overlap with SMRAM.
+
+  @param Buffer The buffer start address to be checked.
+  @param Length The buffer length to be checked.
+
+  @retval TRUE  This buffer is valid per processor architecture and does not
+                overlap with SMRAM.
+  @retval FALSE This buffer is not valid per processor architecture or overlaps
+                with SMRAM.
+**/
+BOOLEAN
+VariableSmmIsBufferOutsideSmmValid (
+  IN EFI_PHYSICAL_ADDRESS  Buffer,
+  IN UINT64                Length
+  )
+{
+  return SmmIsBufferOutsideSmmValid (Buffer, Length);
+}
+
+/**
+  Notify the system that the SMM variable driver is ready.
+**/
+VOID
+VariableNotifySmmReady (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  Handle = NULL;
+  Status = gBS->InstallProtocolInterface (
+                  &Handle,
+                  &gEfiSmmVariableProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  Notify the system that the SMM variable write driver is ready.
+**/
+VOID
+VariableNotifySmmWriteReady (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  Handle = NULL;
+  Status = gBS->InstallProtocolInterface (
+                  &Handle,
+                  &gSmmVariableWriteGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  Variable service MM driver entry point
+
+  @param[in] ImageHandle    A handle for the image that is initializing this
+                            driver
+  @param[in] SystemTable    A pointer to the EFI system table
+
+  @retval EFI_SUCCESS       Variable service successfully initialized.
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  return MmVariableServiceInitialize ();
+}
+
+/**
+  Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
+  This information is used by the MorLock code to infer whether an existing
+  MOR variable is legitimate or not.
+
+  @retval TRUE  Either the TCG or TCG2 protocol is installed in the UEFI
+                protocol database
+  @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
+                protocol database
+**/
+BOOLEAN
+VariableHaveTcgProtocols (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Interface;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiTcg2ProtocolGuid,
+                  NULL,                     // Registration
+                  &Interface
+                  );
+  if (!EFI_ERROR (Status)) {
+    return TRUE;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiTcgProtocolGuid,
+                  NULL,                     // Registration
+                  &Interface
+                  );
+  return !EFI_ERROR (Status);
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.uni b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.uni
new file mode 100644
index 000000000000..227b8c6fad24
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides variable service.
+//
+// This module installs variable arch protocol and variable write arch protocol to provide
+// variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable data.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Provides variable service"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This module installs variable arch protocol and variable write arch protocol to provide variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo. Caution: This module requires additional review when modified. This driver will have external input - variable data. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxeExtra.uni b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxeExtra.uni
new file mode 100644
index 000000000000..f0976418ff81
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"VariableRuntimeDxe module"
+
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
new file mode 100644
index 000000000000..414c7cdc7c05
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Provides SMM variable service.
+//
+// This module installs SMM variable protocol into SMM protocol database,
+// which can be used by SMM driver, and installs SMM variable protocol
+// into BS protocol database, which can be used to notify the SMM Runtime
+// Dxe driver that the SMM variable service is ready.
+// This module should be used with SMM Runtime DXE module together. The
+// SMM Runtime DXE module would install variable arch protocol and variable
+// write arch protocol based on SMM variable module.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable data and communicate buffer in SMM mode.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Provides SMM variable service"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This module installs SMM variable protocol into SMM protocol database, which can be used by SMM driver, and installs SMM variable protocol into BS protocol database, which can be used to notify the SMM Runtime DXE driver that the SMM variable service is ready. This module should be used with SMM Runtime DXE module together. The SMM Runtime DXE module would install variable arch protocol and variable write arch protocol based on SMM variable module. Caution: This module requires additional review when modified. This driver will have external input - variable data and communicate buffer in SMM mode. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.uni b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.uni
new file mode 100644
index 000000000000..f724209f3dc2
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"VariableSmm module"
+
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.uni b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.uni
new file mode 100644
index 000000000000..9639f00077a0
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// This module is the Runtime DXE part correspond to SMM variable module.
+//
+// It installs variable arch protocol and variable write arch protocol to provide
+// four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo
+// and works with SMM variable module together.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable data.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "The Runtime DXE part corresponding to the SMM variable module"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "It installs variable arch protocol and variable write arch protocol to provide four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo and works with SMM variable module together."
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni
new file mode 100644
index 000000000000..bbabdf82736b
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// VariableSmmRuntimeDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"VariableSmmRuntimeDxe module"
+
+
-- 
2.35.1.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#95989): https://edk2.groups.io/g/devel/message/95989
Mute This Topic: https://groups.io/mt/94840825/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list