public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v5 00/19] UEFI variable protection
@ 2022-11-06  7:34 Judah Vang
  2022-11-06  7:34 ` [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid Judah Vang
                   ` (20 more replies)
  0 siblings, 21 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel

Patch 07 - Add PEI Variable Protection into a new directory and leave the
existing PEI Variable unchanged.

Patch 08 - Add RuntimeDxe Variable Protection into a new directory and
keep existing Variable for RuntimeDxe unchanged.

Patch 09 - Add reference to new Protected Variable libs.

Patch 16 - Applied code review comments by adding PEIM to library class

Patch 18 - Applied code review comments by removing unused API.

Notes:
The CryptoPkg changes are now being tracked separately.
Patches 21 on is no longer needed due to reorganization of the new
protected variable modules.

Judah Vang (19):
  MdePkg: Add reference to new Ppi Guid
  MdeModulePkg: Update AUTH_VARIABLE_INFO struct
  MdeModulePkg: Add new ProtectedVariable GUIDs
  MdeModulePkg: Add new include files
  MdeModulePkg: Add new GUID for Variable Store Info
  MdeModulePkg: Add Null ProtectedVariable Library
  MdeModulePkg: Add new Variable functionality
  MdeModulePkg: Add support for Protected Variables
  MdeModulePkg: Reference Null ProtectedVariableLib
  SecurityPkg: Add new GUIDs for
  SecurityPkg: Add new KeyService types and defines
  SecurityPkg: Add new variable types and functions
  SecurityPkg: Update RPMC APIs with index
  SecurityPkg: Fix GetVariableKey API
  SecurityPkg: Add null encryption variable libs
  SecurityPkg: Add VariableKey library function
  SecurityPkg: Add EncryptionVariable lib with AES
  SecurityPkg: Add Protected Variable Services
  SecurityPkg: Add references to new *.inf files

 MdeModulePkg/MdeModulePkg.dec                                                                                 |   13 +-
 SecurityPkg/SecurityPkg.dec                                                                                   |   43 +-
 MdeModulePkg/MdeModulePkg.dsc                                                                                 |   20 +-
 MdeModulePkg/Test/MdeModulePkgHostTest.dsc                                                                    |    8 +
 SecurityPkg/SecurityPkg.dsc                                                                                   |   13 +-
 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf                                    |   34 +
 MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf                                                 |   79 +
 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 +
 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf                                           |   43 +
 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf                                   |   34 +
 SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf                                          |   64 +
 SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf                                          |   68 +
 SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf                                          |   67 +
 SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf                                   |   62 +
 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf                                                         |   36 +
 MdeModulePkg/Include/Guid/ProtectedVariable.h                                                                 |   22 +
 MdeModulePkg/Include/Library/AuthVariableLib.h                                                                |    4 +-
 MdeModulePkg/Include/Library/EncryptionVariableLib.h                                                          |  165 +
 MdeModulePkg/Include/Library/ProtectedVariableLib.h                                                           |  607 +++
 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h                                                      |  225 ++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h                                               |  309 ++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h                                                 |  116 +
 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 +
 MdePkg/Include/Ppi/ReadOnlyVariable2.h                                                                        |    4 +-
 SecurityPkg/Include/Library/RpmcLib.h                                                                         |   15 +-
 SecurityPkg/Include/Library/VariableKeyLib.h                                                                  |   37 +-
 SecurityPkg/Include/Ppi/KeyServicePpi.h                                                                       |   57 +
 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h                                                |   49 +
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h                                          |  589 +++
 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c                                             |  336 ++
 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c                                                      |  628 +++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c                                               |  941 +++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c                                                 |  307 ++
 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 +
 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c                                                |  734 ++++
 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c                                            |   92 +
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c                                            | 2103 ++++++++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c                                               |  163 +
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c                                               | 1327 +++++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c                                               |  209 +
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c                                      |  967 +++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c                                        |  233 ++
 SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c                                                                 |    8 +-
 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c                                                           |   59 +
 SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c                                                   |    8 +-
 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni                                                 |   16 +
 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni                                            |   14 +
 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 +
 80 files changed, 26556 insertions(+), 48 deletions(-)
 create mode 100644 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.inf
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.inf
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.inf
 create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
 create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
 create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
 create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
 create mode 100644 MdeModulePkg/Include/Library/EncryptionVariableLib.h
 create mode 100644 MdeModulePkg/Include/Library/ProtectedVariableLib.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphic.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.h
 create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
 create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
 create mode 100644 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierDxe.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierSmm.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequestToLock.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmmDxe.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCache.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditionalMm.c
 create mode 100644 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
 create mode 100644 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
 create mode 100644 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
 create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxeExtra.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.uni
 create mode 100644 MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni

-- 
2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-06  7:34 ` [PATCH v5 02/19] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

Add reference to gEfiPeiVariableStoreDiscoveredPpiGuid which
contains information whether variable store is available.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
---
 MdePkg/Include/Ppi/ReadOnlyVariable2.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MdePkg/Include/Ppi/ReadOnlyVariable2.h b/MdePkg/Include/Ppi/ReadOnlyVariable2.h
index 926c0bc82a43..c5a8470565bb 100644
--- a/MdePkg/Include/Ppi/ReadOnlyVariable2.h
+++ b/MdePkg/Include/Ppi/ReadOnlyVariable2.h
@@ -2,7 +2,7 @@
   This file declares Read-only Variable Service2 PPI.
   This ppi permits read-only access to the UEFI variable store during the PEI phase.
 
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
   @par Revision Reference:
@@ -106,4 +106,6 @@ struct _EFI_PEI_READ_ONLY_VARIABLE2_PPI {
 
 extern EFI_GUID  gEfiPeiReadOnlyVariable2PpiGuid;
 
+extern EFI_GUID  gEfiPeiVariableStoreDiscoveredPpiGuid;
+
 #endif
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 02/19] MdeModulePkg: Update AUTH_VARIABLE_INFO struct
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
  2022-11-06  7:34 ` [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-06  7:34 ` [PATCH v5 03/19] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

Added NameSize and State to AUTH_VARIABLE_INFO struct.
The size of the name and state is needed when creating
the variable digest.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
---
 MdeModulePkg/Include/Library/AuthVariableLib.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/Include/Library/AuthVariableLib.h b/MdeModulePkg/Include/Library/AuthVariableLib.h
index 37aceba699e6..32391bbf2b61 100644
--- a/MdeModulePkg/Include/Library/AuthVariableLib.h
+++ b/MdeModulePkg/Include/Library/AuthVariableLib.h
@@ -1,7 +1,7 @@
 /** @file
   Provides services to initialize and process authenticated variables.
 
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -25,9 +25,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
                                        (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
 
 typedef struct {
+  UINTN       NameSize;
   CHAR16      *VariableName;
   EFI_GUID    *VendorGuid;
   UINT32      Attributes;
+  UINT8       State;
   UINTN       DataSize;
   VOID        *Data;
   UINT32      PubKeyIndex;
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 03/19] MdeModulePkg: Add new ProtectedVariable GUIDs
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
  2022-11-06  7:34 ` [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid Judah Vang
  2022-11-06  7:34 ` [PATCH v5 02/19] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-06  7:34 ` [PATCH v5 04/19] MdeModulePkg: Add new include files Judah Vang
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

New ProtectVariable GUIDs for passing variable information
from PEI phase to SMM phase.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
---
 MdeModulePkg/Include/Guid/ProtectedVariable.h | 22 ++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/MdeModulePkg/Include/Guid/ProtectedVariable.h b/MdeModulePkg/Include/Guid/ProtectedVariable.h
new file mode 100644
index 000000000000..0c6e19e0456b
--- /dev/null
+++ b/MdeModulePkg/Include/Guid/ProtectedVariable.h
@@ -0,0 +1,22 @@
+/** @file
+  The GUID definitions specific for protected variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROTECTED_VARIABLE_H_
+#define PROTECTED_VARIABLE_H_
+
+#define EDKII_PROTECTED_VARIABLE_GLOBAL_GUID \
+  { 0x8ebf379a, 0xf18e, 0x4728, { 0xa4, 0x10, 0x0, 0xcf, 0x9a, 0x65, 0xbe, 0x91 } }
+
+#define EDKII_METADATA_HMAC_VARIABLE_GUID \
+  { 0xb54cda50, 0xec54, 0x4b20, { 0x85, 0xb4, 0x57, 0xbf, 0x52, 0x98, 0x68, 0x3d } }
+
+extern EFI_GUID  gEdkiiProtectedVariableGlobalGuid;
+extern EFI_GUID  gEdkiiMetaDataHmacVariableGuid;
+extern EFI_GUID  gEdkiiProtectedVariableContextGuid;
+
+#endif // __PROTECTED_VARIABLE_H__
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 04/19] MdeModulePkg: Add new include files
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (2 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 03/19] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-22  6:31   ` Wang, Jian J
  2022-11-06  7:34 ` [PATCH v5 05/19] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
                   ` (16 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

V4: Updated with review comments for misspellings, mismatch
function prototype, missing function header comments, incorrect
function description.

V1: Add EncryptionVariableLib.h for providing encryption and
decryption services for protected variables.
Add ProtectedVariableLib.h for providing integrity or
variables.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 ++++++
 MdeModulePkg/Include/Library/ProtectedVariableLib.h  | 607 ++++++++++++++++++++
 2 files changed, 772 insertions(+)

diff --git a/MdeModulePkg/Include/Library/EncryptionVariableLib.h b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
new file mode 100644
index 000000000000..68981f5aad6a
--- /dev/null
+++ b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
@@ -0,0 +1,165 @@
+/** @file
+  Provides services to encrypt/decrypt variables.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ENCRYPTION_VARIABLE_LIB_H_
+#define ENCRYPTION_VARIABLE_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+
+#include <Guid/VariableFormat.h>
+
+#include <Library/AuthVariableLib.h>
+
+#define ENC_TYPE_NULL  0
+#define ENC_TYPE_AES   TPM_ALG_AES
+
+typedef struct  _VARIABLE_ENCRYPTION_FLAGS {
+  BOOLEAN    Auth;            // Variable is authenticated or not
+  BOOLEAN    DecryptInPlace;  // Do decryption in place
+  BOOLEAN    Protected;       // Variable is protected or not
+} VARIABLE_ENCRYPTION_FLAGS;
+
+typedef struct _VARIABLE_ENCRYPTION_INFO {
+  AUTH_VARIABLE_INFO           Header;            // Authenticated varabile header
+  VARIABLE_HEADER              *Buffer;           // Pointer to variable buffer
+  UINT64                       StoreIndex;        // Variable store index
+  VOID                         *PlainData;        // Pointer to plain data
+  UINT32                       PlainDataSize;     // Size of plain data
+  VOID                         *CipherData;       // Pointer to cipher data
+  UINT32                       CipherDataSize;    // Size of cipher data
+  UINT32                       CipherHeaderSize;  // Size of cipher header
+  UINT32                       CipherDataType;    // Type of cipher data
+  VOID                         *Key;              // Pointer to encrypt/decrypt key
+  UINT32                       KeySize;           // Size of key
+  VARIABLE_ENCRYPTION_FLAGS    Flags;             // Encryption flags
+} VARIABLE_ENCRYPTION_INFO;
+
+/**
+  Encrypt variable data.
+
+  @param[in, out]   VarInfo   Pointer to structure containing detailed information about a variable.
+
+  @retval EFI_SUCCESS               Function successfully executed.
+  @retval EFI_INVALID_PARAMETER     If ProtectedVarLibContextIn == NULL or ProtectedVarLibContextOut == NULL.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process encrypted variable.
+
+**/
+EFI_STATUS
+EFIAPI
+EncryptVariable (
+  IN OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
+  );
+
+/**
+  Decrypt variable data.
+
+  If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
+  decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
+  VarEncInfo->Header.Data.
+
+  If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
+  back in the same buffer as cipher buffer got above, after encryption header,
+  which helps to identify later if the data in buffer is decrypted or not. This
+  can avoid repeat decryption when accessing the same variable more than once.
+
+  If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
+  passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
+  with its size.
+
+  Note the VarEncInfo->PlainData is always pointing to the buffer address with
+  decrypted data without encryption header, and VarEncInfo->PlainDataSize is
+  always the size of original variable data, if this function returned
+  successfully.
+
+  @param[in, out]   VarInfo   Pointer to structure containing detailed
+                              information about a variable.
+
+  @retval EFI_SUCCESS             Variable was decrypted successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_BUFFER_TOO_SMALL    VarEncInfo->PlainData is not NULL but
+                                  VarEncInfo->PlainDataSize is too small.
+  @retval EFI_ABORTED             Unknown error occurred during decrypting.
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate enough resource.
+  @retval EFI_COMPROMISED_DATA    The cipher header is not valid.
+  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+DecryptVariable (
+  IN OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
+  );
+
+/**
+  Get cipher information about a variable, including plaindata size,
+  cipher algorithm type, etc.
+
+  For data passed in with VarEncInfo,
+
+    VarEncInfo->Header.Data
+      - The variable data in normal variable structure.
+    VarEncInfo->Header.DataSize
+      - The size of variable data.
+
+  For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
+
+    VarEncInfo->CipherDataType
+      - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
+      - ENC_TYPE_AES, if the variable is encrypted.
+    VarEncInfo->CipherHeaderSize
+      - Size of cipher header put before encrypted or decrypted data.
+    VarEncInfo->PlainData
+      - NULL, if the variable is encrypted; Or
+      - pointer to original variable data, if the variable has been decrypted.
+    VarEncInfo->PlainDataSize
+      - The size of original variable data
+    VarEncInfo->CipherData
+      - NULL, if the variable is decrypted; Or
+      - pointer to start of encrypted variable data, including encryption header;
+    VarEncInfo->CipherDataSize
+      - The size of encrypted variable data, including encryption header.
+
+  @param[in, out]   VarInfo   Pointer to structure containing detailed
+                              information about a variable.
+
+  @retval EFI_SUCCESS             The information was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_NOT_FOUND           No cipher information recognized.
+  @retval EFI_UNSUPPORTED         Unsupported interface.
+
+**/
+EFI_STATUS
+EFIAPI
+GetCipherDataInfo (
+  IN  OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
+  );
+
+/**
+  Force set cipher information for a variable, like plaindata size,
+  cipher algorithm type, cipher data etc.
+
+  The destination buffer must be passed via VarEncInfo->Header.Data.
+
+  This method is only used to update and/or change plain data information.
+
+  @param[in, out]   VarInfo   Pointer to structure containing detailed
+                              information about a variable.
+
+  @retval EFI_SUCCESS             The information was updated successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_UNSUPPORTED         If this method is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCipherDataInfo (
+  IN  OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
+  );
+
+#endif //_ENCRYPTION_VARIABLE_LIB_H_
diff --git a/MdeModulePkg/Include/Library/ProtectedVariableLib.h b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
new file mode 100644
index 000000000000..d31432a0c2b0
--- /dev/null
+++ b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
@@ -0,0 +1,607 @@
+/** @file
+  Defines interfaces of protected variable services for non-volatile variable
+  storage.
+
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROTECTED_VARIABLE_LIB_H_
+#define PROTECTED_VARIABLE_LIB_H_
+
+#include <PiPei.h>
+#include <PiDxe.h>
+
+#include <Guid/VariableFormat.h>
+
+#include <Protocol/VarCheck.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/UefiLib.h>
+#include <Library/EncryptionVariableLib.h>
+
+#pragma pack(1)
+
+typedef struct _VARIABLE_DIGEST_FLAGS {
+  BOOLEAN    Auth;                           // Authenticated variable format
+  BOOLEAN    Valid;                          // Valid variable data in current variable
+  BOOLEAN    Protected;                      // Protected variable (used in calculating HMAC)
+  BOOLEAN    Encrypted;                      // Encrypted variable
+  BOOLEAN    Freeable;                       // Memory reserved for current node can be freed
+  BOOLEAN    CacheIndexAhead;                // Indicates if CacheIndex is Ahead relative to Global structure
+  BOOLEAN    Reserved[2];                    // Reserved fields
+} VARIABLE_DIGEST_FLAGS;
+
+typedef struct _VARIABLE_DIGEST {
+  ///
+  /// Pointer to digest of next variable in a pre-defined rule of order for
+  /// integration verification. In other words, the final HMAC of all
+  /// protected variables is calculated by concatenating digest of each
+  /// variable in the order of this singly linked list.
+  ///
+  EFI_PHYSICAL_ADDRESS     Prev;
+  EFI_PHYSICAL_ADDRESS     Next;
+  ///
+  /// Index to variable in physical store, used to locate the variable directly
+  /// inside the store (Implementation dependent).
+  ///
+  EFI_PHYSICAL_ADDRESS     StoreIndex;
+  ///
+  /// Index to variable in memory cache, used to locate the variable directly
+  /// inside the cache (Implementation dependent).
+  ///
+  EFI_PHYSICAL_ADDRESS     CacheIndex;
+
+  ///
+  /// Pointer to Cache offset within Global Structure
+  ///
+  UINT32                   CacheOffset;
+
+  ///
+  /// Frequently accessed information relating to the variable.
+  ///
+  UINT16                   DigestSize;    // Size of digest value
+  UINT16                   NameSize;      // Size of variable name
+  UINT32                   DataSize;      // Size of variable data
+  UINT32                   PlainDataSize; // Size of plain data of current variable (if encrypted)
+  UINT32                   State;         // State of current variable
+  UINT32                   Attributes;    // Attributes of current variable
+
+  EFI_GUID                 VendorGuid;    // GUID
+  VARIABLE_DIGEST_FLAGS    Flags;         // Variable digest flags
+  //
+  // Data with variable length are put at the end of this structure.
+  //
+  // CHAR16                VariableName[NameSize/2];
+  // UINT8                 DigestValue[DigestSize];
+} VARIABLE_DIGEST;
+
+#pragma pack()
+
+#define VAR_DIG_NAMEOFF(VarDig)  (sizeof (VARIABLE_DIGEST))
+#define VAR_DIG_DIGOFF(VarDig)   (VAR_DIG_NAMEOFF (VarDig) + (VarDig)->NameSize)
+
+#define VAR_DIG_END(VarDig)  (VAR_DIG_DIGOFF (VarDig) + (VarDig)->DigestSize)
+
+#define VAR_DIG_VALUE(VarDig)  (VOID *)((UINTN)(VarDig) + VAR_DIG_DIGOFF (VarDig))
+#define VAR_DIG_NAME(VarDig)   (CHAR16 *)((UINTN)(VarDig) + VAR_DIG_NAMEOFF (VarDig))
+#define VAR_DIG_GUID(VarDig)   &(VAR_DIG_PTR (VarDig)->VendorGuid)
+
+#define VAR_DIG_PTR(Addr)     ((VARIABLE_DIGEST *)(UINTN)(Addr))
+#define VAR_DIG_ADR(Ptr)      ((EFI_PHYSICAL_ADDRESS)(UINTN)(Ptr))
+#define VAR_DIG_NEXT(VarDig)  (VAR_DIG_PTR ((VarDig)->Next))
+#define VAR_DIG_PREV(VarDig)  (VAR_DIG_PTR ((VarDig)->Prev))
+
+#define VAR_INDEX_INVALID  ((UINT64)(-1))
+
+#define VAR_HDR_PTR(Addr)  ((VARIABLE_HEADER *)(UINTN)(Addr))
+
+typedef VARIABLE_ENCRYPTION_INFO PROTECTED_VARIABLE_INFO;
+
+/**
+
+  This function writes data to the NV variable storage at given position.
+
+  Note: Per current variable service architecture, only SMM is allowed to
+        (directly) change NV variable storage.
+
+  @param VariableInfo             Pointer to structure holding details of a variable.
+  @param Offset                   Offset to the given variable to write from.
+  @param Size                     Size of data to be written.
+  @param Buffer                   Pointer to the buffer from which data is written.
+
+  @retval EFI_INVALID_PARAMETER  Invalid parameters passed in.
+  @retval EFI_UNSUPPORTED        Updating NV variable storage is not supported.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to complete the operation.
+  @retval EFI_SUCCESS            Variable store successfully updated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE)(
+  IN  PROTECTED_VARIABLE_INFO     *VariableInfo,
+  IN  UINTN                       Offset,
+  IN  UINT32                      Size,
+  IN  UINT8                       *Buffer
+  );
+
+/**
+  Update the variable region with Variable information.
+
+  @param[in] AuthVariableInfo       Pointer to 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.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE)(
+  IN AUTH_VARIABLE_INFO     *AuthVariableInfo
+  );
+
+/**
+
+  Retrieve details about a variable and return them in VariableInfo->Header.
+
+  If VariableInfo->Address 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->Address 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->Address,
+  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.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_GET_VAR_INFO)(
+  IN  OUT PROTECTED_VARIABLE_INFO   *VariableInfo
+  );
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+  VariableStart and/or VariableEnd can be given optionally for the situation
+  in which the valid storage space is smaller than the VariableStore->Size.
+  This usually happens when PEI variable services make a compact variable
+  cache to save memory, which cannot make use VariableStore->Size to determine
+  the correct variable storage range.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL.
+  @retval EFI_NOT_FOUND          If the end of VariableInfo is reached.
+  @retval EFI_SUCCESS            The next variable is retrieved successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO)(
+  IN  OUT PROTECTED_VARIABLE_INFO   *VariableInfo
+  );
+
+/**
+
+  Initiate a variable retrieval in SMM environment from non-SMM environment.
+
+  This is usually required in BS/RT environment when local cached copy is in
+  encrypted form. Variable decryption can only be done in SMM environment.
+
+  @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.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_FIND_VAR_SMM)(
+  IN      CHAR16                 *VariableName,
+  IN      EFI_GUID               *VendorGuid,
+  OUT UINT32                     *Attributes OPTIONAL,
+  IN  OUT UINTN                  *DataSize,
+  OUT VOID                       *Data OPTIONAL
+  );
+
+/**
+  Check if a HOB variable store is available or not.
+
+  @retval EFI_NOT_READY  HOB variable store info not available.
+  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
+  @retval EFI_SUCCESS    HOB variable store is available.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE)(
+  VOID
+  );
+
+typedef enum {
+  FromPeiModule,
+  FromBootServiceModule,
+  FromRuntimeModule,
+  FromSmmModule
+} VARIABLE_SERVICE_USER;
+
+#pragma pack(1)
+
+#define PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION  0x02
+
+typedef struct _PROTECTED_VARIABLE_CONTEXT_IN {
+  UINT32                                     StructVersion;
+  UINT32                                     StructSize;
+  UINT32                                     MaxVariableSize;
+
+  VARIABLE_SERVICE_USER                      VariableServiceUser;
+
+  PROTECTED_VAR_LIB_FIND_VAR_SMM             FindVariableSmm;
+  PROTECTED_VAR_LIB_GET_VAR_INFO             GetVariableInfo;
+  PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO        GetNextVariableInfo;
+  PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE    UpdateVariableStore;
+  PROTECTED_VAR_LIB_UPDATE_VARIABLE          UpdateVariable;
+  PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE      IsHobVariableStoreAvailable;
+} PROTECTED_VARIABLE_CONTEXT_IN;
+
+#pragma pack()
+
+/**
+
+  Initialization for protected variable services.
+
+  If this initialization failed upon any error, the whole variable services
+  should not be used.  A system reset might be needed to re-construct NV
+  variable storage to be the default state.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected variables.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  );
+
+/**
+
+  An alternative version of ProtectedVariableLibGetData to get plain data, if
+  encrypted, from given variable, for different use cases.
+
+  @param[in,out]      VarInfo     Pointer to structure containing variable information.
+
+  @retval EFI_SUCCESS               Found the specified variable.
+  @retval EFI_INVALID_PARAMETER     VarInfo is NULL or both VarInfo->Address and
+                                    VarInfo->Offset are invalid.
+  @retval EFI_NOT_FOUND             The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  );
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was be found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByName (
+  IN      CONST  CHAR16    *VariableName,
+  IN      CONST  EFI_GUID  *VariableGuid,
+  OUT UINT32               *Attributes,
+  IN  OUT UINTN            *DataSize,
+  OUT VOID                 *Data OPTIONAL
+  );
+
+/**
+
+  Retrieve plain data, if encrypted, of given variable.
+
+  If variable encryption is employed, this function will initiate a SMM request
+  to get the plain data. Due to security consideration, the decryption can only
+  be done in SMM environment.
+
+  @param[in]      Variable           Pointer to header of a Variable.
+  @param[out]     Data               Pointer to plain data of the given variable.
+  @param[in, out] DataSize           Size of data returned or data buffer needed.
+  @param[in]      AuthFlag           Auth-variable indicator.
+
+  @retval EFI_SUCCESS                Found the specified variable.
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_NOT_FOUND              The specified variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL       If *DataSize is smaller than needed.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByBuffer (
+  IN      VARIABLE_HEADER  *Variable,
+  IN  OUT VOID             *Data,
+  IN  OUT UINT32           *DataSize,
+  IN      BOOLEAN          AuthFlag
+  );
+
+/**
+
+  Prepare for variable update.
+
+  This is needed only once during current boot to mitigate replay attack. Its
+  major job is to advance RPMC (Replay Protected Monotonic Counter).
+
+  @retval EFI_SUCCESS             Variable is ready to update hereafter.
+  @retval EFI_UNSUPPORTED         Updating variable is not supported.
+  @retval EFI_DEVICE_ERROR        Error in advancing RPMC.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+  VOID
+  );
+
+/**
+
+  Update a variable with protection provided by this library.
+
+  If variable encryption is employed, the new variable data will be encrypted
+  before being written to NV variable storage.
+
+  A special variable, called "MetaDataHmacVar", will always be updated along
+  with variable being updated to reflect the changes (HMAC value) of all
+  protected valid variables. The only exceptions, currently, are variable
+  "MetaDataHmacVar" itself and variable "VarErrorLog".
+
+  The buffer passed by NewVariable must be double of maximum variable size,
+  which allows to pass the "MetaDataHmacVar" back to caller along with encrypted
+  new variable data, if any. This can make sure the new variable data and
+  "MetaDataHmacVar" can be written at almost the same time to reduce the chance
+  of compromising the integrity.
+
+  If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
+  and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
+  case because of less variables in storage. NewVariable should be always passed
+  in to convey new "MetaDataHmacVar" back.
+
+  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
+                                      adding a new variable.
+  @param[in,out]  CurrVariableInDel   In-delete-transition copy of updating variable.
+  @param[in]      NewVariable         Buffer of new variable data.
+  @param[out]     NewVariable         Buffer of "MetaDataHmacVar" and new
+                                      variable (encrypted).
+  @param[in]      NewVariableSize     Size of NewVariable.
+  @param[out]     NewVariableSize     Size of (encrypted) NewVariable and
+                                      "MetaDataHmacVar".
+
+  @retval EFI_SUCCESS             The variable is updated with protection successfully.
+  @retval EFI_INVALID_PARAMETER   NewVariable is NULL.
+  @retval EFI_NOT_FOUND           Information missing to finish the operation.
+  @retval EFI_ABORTED             Failed to encrypt variable or calculate HMAC.
+  @retval EFI_NOT_READY           The RPMC device is not yet initialized.
+  @retval EFI_DEVICE_ERROR        The RPMC device has error in updating.
+  @retval EFI_ACCESS_DENIED       The given variable is not allowed to update.
+                                  Currently this only happens on updating
+                                  "MetaDataHmacVar" from code outside of this
+                                  library.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+  IN  OUT VARIABLE_HEADER  *CurrVariable OPTIONAL,
+  IN  OUT VARIABLE_HEADER  *CurrVariableInDel OPTIONAL,
+  IN  OUT VARIABLE_HEADER  *NewVariable,
+  IN  OUT UINTN            *NewVariableSize
+  );
+
+/**
+
+  Finalize a variable updating after it's written to NV variable storage
+  successfully.
+
+  This usually includes works like increasing RPMC, synchronizing local cache,
+  updating new position of "MetaDataHmacVar", deleting old copy of "MetaDataHmacVar"
+  completely, etc.
+
+  @param[in]      NewVariable       Buffer of new variables and MetaDataHmacVar.
+  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
+  @param[in]      StoreIndex        StoreIndex to NV variable storage from where the new
+                                    variable and MetaDataHmacVar have been written.
+
+  @retval EFI_SUCCESS         No problem in winding up the variable write operation.
+  @retval Others              Failed to updating state of old copy of updated
+                              variable, or failed to increase RPMC, etc.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+  IN  VARIABLE_HEADER  *NewVariable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex
+  );
+
+/**
+  Find the request variable.
+
+  @param[in, out]  VarInfo      Pointer to variable data.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_INVALID_PARAMETER Variable info is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFind (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  );
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+                            On return, the size of the variable name buffer.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNext (
+  IN OUT UINTN     *VariableNameSize,
+  IN OUT CHAR16    *VariableName,
+  IN OUT EFI_GUID  *VariableGuid
+  );
+
+/**
+  Find variable via information in data structure PROTECTED_VARIABLE_INFO.
+
+   If VarInfo->StoreIndex is given and valid, always used it to search variable
+   in store. Otherwise, search the variable via variable name and guid pointed
+   by VarInfo->Header.VariableName and VarInfo->Header.VendorGuid.
+
+  @param VarInfo    Pointer to data containing variable information.
+
+  @return EFI_SUCCESS           Found the variable.
+  @return EFI_INVALID_PARAMETER No valid variable information is given.
+  @return EFI_NOT_FOUND         The given variable was not found or no more
+                                variables available.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNextEx (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  );
+
+/**
+  Refresh variable information changed by variable service.
+
+  @param Variable         Pointer to buffer of the updated variable.
+  @param VariableSize     Size of variable pointed by Variable.
+  @param StoreIndex       New index of the variable in store.
+  @param RefreshData      Flag to indicate if the variable has been updated.
+
+  @return EFI_SUCCESS     No error occurred in updating.
+  @return EFI_NOT_FOUND   The given variable was not found in
+                          ProtectedVariableLib.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibRefresh (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex,
+  IN  BOOLEAN          RefreshData
+  );
+
+/**
+  Get sorted protected variable list.
+
+  @param Buffer           Pointer to a pointer of buffer.
+  @param NumElements      Pointer to number of elements in list.
+
+  @return EFI_SUCCESS     Successfully retrieved sorted list.
+  @return others          Unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetSortedList (
+  IN  OUT  EFI_PHYSICAL_ADDRESS  **Buffer,
+  IN  OUT  UINTN                 *NumElements
+  );
+
+/**
+
+  Determine if the variable is the HMAC variable
+
+  @param VariableName   Pointer to variable name.
+
+  @return TRUE      Variable is HMAC variable
+  @return FALSE     Variable is not HMAC variable
+
+**/
+BOOLEAN
+ProtectedVariableLibIsHmac (
+  IN CHAR16  *VariableName
+  );
+
+#endif
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 05/19] MdeModulePkg: Add new GUID for Variable Store Info
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (3 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 04/19] MdeModulePkg: Add new include files Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-06  7:34 ` [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

Discover if Variable Store Info HOB has been published
by platform driver. It contains information in regards
to HOB or NV Variable Store availability

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 58e6ab004882..e896dd038479 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -4,7 +4,7 @@
 # and libraries instances, which are used for those modules.
 #
 # Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
-# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
 # (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
 # Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
@@ -93,6 +93,14 @@ [LibraryClasses]
   #
   TpmMeasurementLib|Include/Library/TpmMeasurementLib.h
 
+  ## @libraryclass  Provides interfaces to encrypt/decrypt variable.
+  #
+  EncryptionVariableLib|Include/Library/EncryptionVariableLib.h
+
+  ## @libraryclass  Provides interfaces to encrypt/decrypt variable.
+  #
+  ProtectedVariableLib|Include/Library/ProtectedVariableLib.h
+
   ## @libraryclass  Provides authenticated variable services.
   #
   AuthVariableLib|Include/Library/AuthVariableLib.h
@@ -516,6 +524,9 @@ [Ppis]
   gEdkiiPeiCapsuleOnDiskPpiGuid             = { 0x71a9ea61, 0x5a35, 0x4a5d, { 0xac, 0xef, 0x9c, 0xf8, 0x6d, 0x6d, 0x67, 0xe0 } }
   gEdkiiPeiBootInCapsuleOnDiskModePpiGuid   = { 0xb08a11e4, 0xe2b7, 0x4b75, { 0xb5, 0x15, 0xaf, 0x61, 0x6, 0x68, 0xbf, 0xd1  } }
 
+  ## Include/Ppi/ReadOnlyVariable2.h
+  gEfiPeiVariableStoreDiscoveredPpiGuid     = { 0xa2fc038d, 0xfdf5, 0x4501, { 0xaf, 0x8e, 0x69, 0xb0, 0x20, 0xec, 0xe6, 0x63 } }
+
 [Protocols]
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.
   #  Include/Protocol/LoadPe32Image.h
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (4 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 05/19] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-22  6:39   ` Wang, Jian J
  2022-11-06  7:34 ` [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality Judah Vang
                   ` (14 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

V4: Applied code review comments - removed APIs that are not being
used.

V1: Add Null versions of the ProtectedVariable Library.
This will be the default libraries for platforms that
do not support ProtectedVariable.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf |  34 ++
 MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c          | 336 ++++++++++++++++++++
 2 files changed, 370 insertions(+)

diff --git a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
new file mode 100644
index 000000000000..6a17191c4e1e
--- /dev/null
+++ b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+#  Provides null version of protected variable services.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = ProtectedVariableLibNull
+  FILE_GUID                      = 352C6A1B-403A-4E37-8517-FAA50BC45251
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 0.1
+  LIBRARY_CLASS                  = ProtectedVariableLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  ProtectedVariable.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+
diff --git a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
new file mode 100644
index 000000000000..074559f84f52
--- /dev/null
+++ b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
@@ -0,0 +1,336 @@
+/** @file
+  NULL version of ProtectedVariableLib used to disable protected variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ProtectedVariableLib.h>
+
+/**
+
+  Initialization for protected varibale services.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Prepare for variable update.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Update a variable with protection provided by this library.
+
+  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
+                                      adding a new variable.
+  @param[in]      CurrVariableInDel   In-delete-transiion copy of updating variable.
+  @param[in,out]  NewVariable         Buffer of new variable data.
+                                      Buffer of "MetaDataHmacVar" and new
+                                      variable (encrypted).
+  @param[in,out]  NewVariableSize     Size of NewVariable.
+                                      Size of (encrypted) NewVariable and
+                                      "MetaDataHmacVar".
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+  IN  OUT VARIABLE_HEADER  *CurrVariable,
+  IN      VARIABLE_HEADER  *CurrVariableInDel,
+  IN  OUT VARIABLE_HEADER  *NewVariable,
+  IN  OUT UINTN            *NewVariableSize
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Finalize a variable updating after it's written to NV variable storage
+  successfully.
+
+  @param[in]      NewVariable       Buffer of new variables and MetaDataHmacVar.
+  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
+  @param[in]      StoreIndex        New index of the variable in store.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+  IN  VARIABLE_HEADER  *NewVariable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Retrieve plain data, if encrypted, of given variable.
+
+  @param[in]      Variable           Pointer to header of a Variable.
+  @param[in,out]  Data               Pointer to plain data of the given variable.
+  @param[in,out]  DataSize           Size of data returned or data buffer needed.
+  @param[in]      AuthFlag           Auth-variable indicator.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetData (
+  IN      VARIABLE_HEADER  *Variable,
+  IN  OUT VOID             *Data,
+  IN  OUT UINT32           *DataSize,
+  IN      BOOLEAN          AuthFlag
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Get the specified protected variable.
+
+  @param[in]      VariableName      Pointer to variable name.
+  @param[in]      VariableGuid      Pointer to vairable GUID.
+  @param[out]     Attributes        Pointer to attributes.
+  @param[in,out]  DataSize          Pointer to data size.
+  @param[out]     Data              Pointer to data.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGet (
+  IN      CONST  CHAR16    *VariableName,
+  IN      CONST  EFI_GUID  *VariableGuid,
+  OUT UINT32               *Attributes,
+  IN  OUT UINTN            *DataSize,
+  OUT VOID                 *Data OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Find the protected variable.
+
+  @param[in,out]      VarInfo     Pointer to structure containing variable information.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFind (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Find next protected variable.
+
+  @param[in,out]      VariableNameSize    Pointer to size of variable name.
+  @param[in,out]      VariableName        Pointer to variable name.
+  @param[in,out]      VariableGuid        Pointer to vairable GUID.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNext (
+  IN OUT UINTN     *VariableNameSize,
+  IN OUT CHAR16    *VariableName,
+  IN OUT EFI_GUID  *VariableGuid
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Find next protected variable stub.
+
+  @param[in,out]      VarInfo     Pointer to structure containing variable information.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNextEx (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Get protected variable by information.
+
+  @param[in,out]      VarInfo     Pointer to structure containing variable information.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Get protected variable by name.
+
+  @param[in]      VariableName      Pointer to variable name.
+  @param[in]      VariableGuid      Pointer to vairable GUID.
+  @param[out]     Attributes        Pointer to attributes.
+  @param[in,out]  DataSize          Pointer to data size.
+  @param[out]     Data              Pointer to data.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByName (
+  IN      CONST  CHAR16    *VariableName,
+  IN      CONST  EFI_GUID  *VariableGuid,
+  OUT UINT32               *Attributes,
+  IN  OUT UINTN            *DataSize,
+  OUT VOID                 *Data OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Get protected variable by name.
+
+  @param[in]      Variable      Pointer to variable name.
+  @param[in,out]  Data          Pointer to variable data.
+  @param[in,out]  DataSize      Pointer to data size.
+  @param[in]      AuthFlag      Authenticate flag.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByBuffer (
+  IN      VARIABLE_HEADER  *Variable,
+  IN  OUT VOID             *Data,
+  IN  OUT UINT32           *DataSize,
+  IN      BOOLEAN          AuthFlag
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Refresh variable information changed by variable service.
+
+  @param[in]  Variable         Pointer to buffer of the updated variable.
+  @param[in]  VariableSize     Size of variable pointed by Variable.
+  @param[in]  StoreIndex       New index of the variable in store.
+  @param[in]  RefreshData      Flag to indicate if the variable has been updated.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibRefresh (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex,
+  IN  BOOLEAN          RefreshData
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Get sorted protected variable list.
+
+  @param[in,out]  Buffer        Pointer to buffer.
+  @param[in,out]  NumElements   Pointer to number of elements.
+
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetSortedList (
+  IN  OUT  EFI_PHYSICAL_ADDRESS  **Buffer,
+  IN  OUT  UINTN                 *NumElements
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Determine if the variable is the HMAC variable.
+
+  @param[in]  VariableName   Pointer to variable name.
+
+  @return FALSE     Variable is not HMAC variable
+
+**/
+BOOLEAN
+ProtectedVariableLibIsHmac (
+  IN CHAR16  *VariableName
+  )
+{
+  return FALSE;
+}
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (5 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-14  3:43   ` Wang, Jian J
       [not found]   ` <1727569A8ECB6F9D.19699@groups.io>
  2022-11-06  7:34 ` [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Judah Vang
                   ` (13 subsequent siblings)
  20 siblings, 2 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Hao A Wu, Nishant C Mistry

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

V5: Add PEI Variable Protection into a new directory and leave the
existing PEI Variable unchanged.

V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo()
and SafeUint64ToUint32().

V1: Provide new APIs for retrieving variable information.
Add new function stubs for retrieving Protected
variable information.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Acked-by: Hao A Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf      |  79 ++
 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h           | 225 +++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h    | 309 +++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h      | 116 +++
 MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c           | 628 +++++++++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c    | 941 ++++++++++++++++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c      | 307 +++++++
 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni      |  16 +
 MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni |  14 +
 9 files changed, 2635 insertions(+)

diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
new file mode 100644
index 000000000000..953a7c6b884f
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
@@ -0,0 +1,79 @@
+## @file
+#  Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+#  This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PeiVariable
+  MODULE_UNI_FILE                = PeiVariable.uni
+  FILE_GUID                      = 8D104D19-593B-4DDF-81CF-8168A9EDE9C7
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PeimInitializeVariableServices
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  Variable.c
+  Variable.h
+  VariableStore.c
+  VariableStore.h
+  VariableParsing.c
+  VariableParsing.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  PcdLib
+  HobLib
+  PeimEntryPoint
+  DebugLib
+  PeiServicesTablePointerLib
+  PeiServicesLib
+  SafeIntLib
+  VariableFlashInfoLib
+  ProtectedVariableLib
+
+[Guids]
+  ## CONSUMES             ## GUID # Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  gEfiAuthenticatedVariableGuid
+  ## SOMETIMES_CONSUMES   ## GUID # Variable store header
+  ## SOMETIMES_CONSUMES   ## HOB
+  gEfiVariableGuid
+  ## SOMETIMES_PRODUCES   ## HOB
+  ## SOMETIMES_CONSUMES   ## HOB
+  gEfiVariableIndexTableGuid
+  gEfiSystemNvDataFvGuid            ## SOMETIMES_CONSUMES   ## GUID
+  ## SOMETIMES_CONSUMES   ## HOB
+  ## CONSUMES             ## GUID # Dependence
+  gEdkiiFaultTolerantWriteGuid
+
+[Ppis]
+  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
+  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ## SOMETIMES_CONSUMES
+
+[Depex]
+  gEdkiiFaultTolerantWriteGuid
+
+# [BootMode]
+# RECOVERY_FULL             ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  PeiVariableExtra.uni
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
new file mode 100644
index 000000000000..1bdbdd2b807b
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
@@ -0,0 +1,225 @@
+/** @file
+  The internal header file includes the common header files, defines
+  internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_H_
+#define PEI_VARIABLE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/VariableFlashInfoLib.h>
+#include <Library/ProtectedVariableLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/VariableIndexTable.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
+#include <Guid/ProtectedVariable.h>
+
+typedef enum {
+  VariableStoreTypeHob,
+  VariableStoreTypeNv,
+  VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+  VARIABLE_STORE_HEADER                   *VariableStoreHeader;
+  VARIABLE_INDEX_TABLE                    *IndexTable;
+  //
+  // If it is not NULL, it means there may be an inconsecutive variable whose
+  // partial content is still in NV storage, but another partial content is backed up
+  // in spare block.
+  //
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA    *FtwLastWriteData;
+  BOOLEAN                                 AuthFlag;
+} VARIABLE_STORE_INFO;
+
+//
+// Functions
+//
+
+/**
+  Provide the functionality of the variable services.
+
+  @param  FileHandle  Handle of the file being invoked.
+                      Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+  @param  PeiServices  General purpose services available to every PEIM.
+
+  @retval EFI_SUCCESS  If the interface could be successfully installed
+  @retval Others       Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  );
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN CONST  CHAR16                           *VariableName,
+  IN CONST  EFI_GUID                         *VariableGuid,
+  OUT       UINT32                           *Attributes,
+  IN OUT    UINTN                            *DataSize,
+  OUT       VOID                             *Data OPTIONAL
+  );
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+
+  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  );
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN CONST  CHAR16                           *VariableName,
+  IN CONST  EFI_GUID                         *VariableGuid,
+  OUT       UINT32                           *Attributes,
+  IN OUT    UINTN                            *DataSize,
+  OUT       VOID                             *Data OPTIONAL
+  );
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+
+  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
new file mode 100644
index 000000000000..d7af6cb6e8be
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
@@ -0,0 +1,309 @@
+/** @file
+  The internal header file includes the common header files, defines
+  internal structure and functions used by PeiVariable module.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_PARSING_H_
+#define PEI_VARIABLE_PARSING_H_
+
+#include "Variable.h"
+
+/**
+
+  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
+  );
+
+/**
+  This code checks if variable header is valid or not.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+
+  @retval TRUE      Variable header is valid.
+  @retval FALSE     Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER  *Variable
+  );
+
+/**
+  This code gets the pointer to the next variable header.
+
+  @param[in]  StoreInfo         Pointer to variable store info structure.
+  @param[in]  Variable          Pointer to the Variable Header.
+  @param[in]  VariableHeader    Pointer to the Variable Header that has consecutive content.
+
+  @return  A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_STORE_INFO  *StoreInfo,
+  IN  VARIABLE_HEADER      *Variable,
+  IN  VARIABLE_HEADER      *VariableHeader
+  );
+
+/**
+  This code gets the pointer to the variable guid.
+
+  @param[in]  Variable   Pointer to the Variable Header.
+  @param[in]  AuthFlag   Authenticated variable flag.
+
+  @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the pointer to the variable name.
+
+  @param[in]   Variable  Pointer to the Variable Header.
+  @param[in]   AuthFlag  Authenticated variable flag.
+
+  @return  A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the size of name of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the size of data of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  );
+
+/**
+  This code gets the pointer to the variable data.
+
+  @param[in]   Variable         Pointer to the Variable Header.
+  @param[in]   VariableHeader   Pointer to the Variable Header that has consecutive content.
+  @param[in]   AuthFlag         Authenticated variable flag.
+
+  @return  A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  VARIABLE_HEADER  *VariableHeader,
+  IN  BOOLEAN          AuthFlag
+  );
+
+/**
+  Get variable header that has consecutive content.
+
+  @param[in]  StoreInfo      Pointer to variable store info structure.
+  @param[in]  Variable       Pointer to the Variable Header.
+  @param[out] VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+  @retval TRUE          Variable header is valid.
+  @retval FALSE         Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN VARIABLE_HEADER      *Variable,
+  OUT VARIABLE_HEADER     **VariableHeader
+  );
+
+/**
+  This code gets the size of variable header.
+
+  @param[in] AuthFlag   Authenticated variable flag.
+
+  @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+  IN  BOOLEAN  AuthFlag
+  );
+
+/**
+  Get variable name or data to output buffer.
+
+  @param[in]  StoreInfo     Pointer to variable store info structure.
+  @param[in]  NameOrData    Pointer to the variable name/data that may be inconsecutive.
+  @param[in]  Size          Variable name/data size.
+  @param[out] Buffer        Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN UINT8                *NameOrData,
+  IN UINTN                Size,
+  OUT UINT8               *Buffer
+  );
+
+/**
+  This function compares a variable with variable entries in database.
+
+  @param[in]  StoreInfo     Pointer to variable store info structure.
+  @param[in]  Variable      Pointer to the variable in our database
+  @param[in]  VariableHeader Pointer to the Variable Header that has consecutive content.
+  @param[in]  VariableName  Name of the variable to compare to 'Variable'
+  @param[in]  VendorGuid    GUID of the variable to compare to 'Variable'
+  @param[out] PtrTrack      Variable Track Pointer structure that contains Variable Information.
+
+  @retval EFI_SUCCESS    Found match variable
+  @retval EFI_NOT_FOUND  Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+  IN  VARIABLE_STORE_INFO     *StoreInfo,
+  IN  VARIABLE_HEADER         *Variable,
+  IN  VARIABLE_HEADER         *VariableHeader,
+  IN  CONST CHAR16            *VariableName,
+  IN  CONST EFI_GUID          *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  );
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VarInfo->Address is NULL, the first one in VariableStore is returned.
+
+  VariableStart and/or VariableEnd can be given optionally for the situation
+  in which the valid storage space is smaller than the VariableStore->Size.
+  This usually happens when PEI variable services make a compact variable
+  cache to save memory, which cannot make use VariableStore->Size to determine
+  the correct variable storage range.
+
+  @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->Address 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->Address 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->Address,
+  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
+  );
+
+/**
+
+  Find variable specified with input parameters.
+
+  @param[in] StoreInfo             Pointer to variable information.
+  @param[in] VariableName          Pointer to variable name.
+  @param[in] VendorGuid            Pointer to variable GUID.
+  @param[in] PtrTrack              Pointer to variable track.
+
+  @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
+FindVariableEx (
+  IN VARIABLE_STORE_INFO      *StoreInfo,
+  IN CONST CHAR16             *VariableName,
+  IN CONST EFI_GUID           *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
new file mode 100644
index 000000000000..6e2f6f939bab
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
@@ -0,0 +1,116 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEI_VARIABLE_STORE_H_
+#define PEI_VARIABLE_STORE_H_
+
+/**
+  Get variable store status.
+
+  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
+
+  @retval  EfiRaw      Variable store is raw
+  @retval  EfiValid    Variable store is valid
+  @retval  EfiInvalid  Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+  IN VARIABLE_STORE_HEADER  *VarStoreHeader
+  );
+
+/**
+  Reports HOB variable store is available or not.
+
+  @retval EFI_NOT_READY  HOB variable store info not available.
+  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
+  @retval EFI_SUCCESS    HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+  VOID
+  );
+
+/**
+  Get HOB variable store.
+
+  @param[out] StoreInfo             Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  );
+
+/**
+  Get NV variable store.
+
+  @param[out] StoreInfo             Return the store info.
+  @param[out] VariableStoreHeader   Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+  OUT VARIABLE_STORE_INFO         *StoreInfo,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
+  );
+
+/**
+  Return the variable store header and the store info based on the Index.
+
+  @param[in]  Type       The type of the variable store.
+  @param[out] StoreInfo  Return the store info.
+
+  @return  Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+  IN VARIABLE_STORE_TYPE   Type,
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  );
+
+/**
+  Make a cached copy of NV variable storage.
+
+  To save memory in PEI phase, only valid variables are copied into cache.
+  An IndexTable could be used to store the offset (relative to NV storage
+  base) of each copied variable, in case we need to restore the storage
+  as the same (valid) variables layout as in original one.
+
+  Variables with valid format and following state can be taken as valid:
+    - with state VAR_ADDED;
+    - with state VAR_IN_DELETED_TRANSITION but without the same variable
+      with state VAR_ADDED;
+    - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
+      MetaDataHmacVar.
+
+  @param[out]     StoreCacheBase    Base address of variable storage cache.
+  @param[in,out]  StoreCacheSize    Size of space in StoreCacheBase.
+  @param[out]     IndexTable        Buffer of index (offset) table with entries of
+                                    VariableNumber.
+  @param[out]     VariableNumber    Number of valid variables.
+  @param[out]     AuthFlag          Aut-variable indicator.
+
+  @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or StoreCacheBase.
+  @return EFI_VOLUME_CORRUPTED  Invalid or no NV variable storage found.
+  @return EFI_BUFFER_TOO_SMALL  StoreCacheSize is smaller than needed.
+  @return EFI_SUCCESS           NV variable storage is cached successfully.
+**/
+EFI_STATUS
+EFIAPI
+InitNvVariableStore (
+  OUT  EFI_PHYSICAL_ADDRESS  StoreCacheBase OPTIONAL,
+  IN OUT  UINT32             *StoreCacheSize,
+  OUT  UINT32                *IndexTable OPTIONAL,
+  OUT  UINT32                *VariableNumber OPTIONAL,
+  OUT  BOOLEAN               *AuthFlag OPTIONAL
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
new file mode 100644
index 000000000000..ce790946626e
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
@@ -0,0 +1,628 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableParsing.h"
+#include "VariableStore.h"
+
+//
+// Module globals
+//
+EFI_PEI_READ_ONLY_VARIABLE2_PPI  mVariablePpi = {
+  PeiGetVariableEx,
+  PeiGetNextVariableNameEx
+};
+
+EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiPeiReadOnlyVariable2PpiGuid,
+  &mVariablePpi
+};
+
+/**
+  Provide the functionality of the variable services.
+
+  @param  FileHandle   Handle of the file being invoked.
+                       Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+  @param  PeiServices  General purpose services available to every PEIM.
+
+  @retval EFI_SUCCESS  If the interface could be successfully installed
+  @retval Others       Returned from PeiServicesInstallPpi()
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
+
+  //
+  // If protected variable services are not supported, EFI_UNSUPPORTED should
+  // be always returned. Check it here.
+  //
+  ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
+  ContextIn.StructSize    = sizeof (ContextIn);
+
+  ContextIn.MaxVariableSize             = 0;
+  ContextIn.VariableServiceUser         = FromPeiModule;
+  ContextIn.GetVariableInfo             = GetVariableInfo;
+  ContextIn.GetNextVariableInfo         = GetNextVariableInfo;
+  ContextIn.FindVariableSmm             = NULL;
+  ContextIn.UpdateVariableStore         = NULL;
+  ContextIn.UpdateVariable              = NULL;
+  ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
+
+  Status = ProtectedVariableLibInitialize (&ContextIn);
+  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+    return Status;
+  }
+
+  return PeiServicesInstallPpi (&mPpiListVariable);
+}
+
+/**
+  Find the variable in the specified variable store.
+
+  @param  StoreInfo           Pointer to the store info structure.
+  @param  VariableName        Name of the variable to be found
+  @param  VendorGuid          Vendor GUID to be found.
+  @param  PtrTrack            Variable Track Pointer structure that contains Variable Information.
+
+  @retval  EFI_SUCCESS            Variable found successfully
+  @retval  EFI_NOT_FOUND          Variable not found
+  @retval  EFI_INVALID_PARAMETER  Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableEx (
+  IN VARIABLE_STORE_INFO      *StoreInfo,
+  IN CONST CHAR16             *VariableName,
+  IN CONST EFI_GUID           *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  )
+{
+  VARIABLE_HEADER        *Variable;
+  VARIABLE_HEADER        *LastVariable;
+  VARIABLE_HEADER        *MaxIndex;
+  UINTN                  Index;
+  UINTN                  Offset;
+  BOOLEAN                StopRecord;
+  VARIABLE_HEADER        *InDeletedVariable;
+  VARIABLE_STORE_HEADER  *VariableStoreHeader;
+  VARIABLE_INDEX_TABLE   *IndexTable;
+  VARIABLE_HEADER        *VariableHeader;
+
+  VariableStoreHeader = StoreInfo->VariableStoreHeader;
+
+  if (VariableStoreHeader == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (~VariableStoreHeader->Size == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  IndexTable         = StoreInfo->IndexTable;
+  PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
+  PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader);
+
+  InDeletedVariable = NULL;
+
+  //
+  // No Variable Address equals zero, so 0 as initial value is safe.
+  //
+  MaxIndex       = NULL;
+  VariableHeader = NULL;
+
+  if (IndexTable != NULL) {
+    //
+    // traverse the variable index table to look for varible.
+    // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.
+    //
+    for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
+      ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
+      Offset  += IndexTable->Index[Index];
+      MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset);
+      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
+      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+          InDeletedVariable = PtrTrack->CurrPtr;
+        } else {
+          return EFI_SUCCESS;
+        }
+      }
+    }
+
+    if (IndexTable->GoneThrough != 0) {
+      //
+      // If the table has all the existing variables indexed, return.
+      //
+      PtrTrack->CurrPtr = InDeletedVariable;
+      return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+    }
+  }
+
+  if (MaxIndex != NULL) {
+    //
+    // HOB exists but the variable cannot be found in HOB
+    // If not found in HOB, then let's start from the MaxIndex we've found.
+    //
+    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
+    LastVariable = MaxIndex;
+  } else {
+    //
+    // Start Pointers for the variable.
+    // Actual Data Pointer where data can be written.
+    //
+    Variable     = PtrTrack->StartPtr;
+    LastVariable = PtrTrack->StartPtr;
+  }
+
+  //
+  // Find the variable by walk through variable store
+  //
+  StopRecord = FALSE;
+  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+      //
+      // Record Variable in VariableIndex HOB
+      //
+      if ((IndexTable != NULL) && !StopRecord) {
+        Offset = (UINTN)Variable - (UINTN)LastVariable;
+        if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {
+          //
+          // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),
+          // or the record buffer is full.
+          //
+          StopRecord = TRUE;
+        } else {
+          IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;
+          LastVariable                            = Variable;
+        }
+      }
+
+      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+          InDeletedVariable = PtrTrack->CurrPtr;
+        } else {
+          return EFI_SUCCESS;
+        }
+      }
+    }
+
+    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
+  }
+
+  //
+  // If gone through the VariableStore, that means we never find in Firmware any more.
+  //
+  if ((IndexTable != NULL) && !StopRecord) {
+    IndexTable->GoneThrough = 1;
+  }
+
+  PtrTrack->CurrPtr = InDeletedVariable;
+
+  return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+/**
+  Find the variable in HOB and Non-Volatile variable storages.
+
+  @param  VariableName  Name of the variable to be found
+  @param  VendorGuid    Vendor GUID to be found.
+  @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.
+  @param  StoreInfo     Return the store info.
+
+  @retval  EFI_SUCCESS            Variable found successfully
+  @retval  EFI_NOT_FOUND          Variable not found
+  @retval  EFI_INVALID_PARAMETER  Invalid variable name
+**/
+EFI_STATUS
+FindVariable (
+  IN CONST  CHAR16            *VariableName,
+  IN CONST  EFI_GUID          *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
+  OUT VARIABLE_STORE_INFO     *StoreInfo
+  )
+{
+  EFI_STATUS           Status;
+  VARIABLE_STORE_TYPE  Type;
+
+  if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+    GetVariableStore (Type, StoreInfo);
+    Status = FindVariableEx (
+               StoreInfo,
+               VariableName,
+               VendorGuid,
+               PtrTrack
+               );
+    if (!EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was be found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN CONST  CHAR16                           *VariableName,
+  IN CONST  EFI_GUID                         *VariableGuid,
+  OUT       UINT32                           *Attributes,
+  IN OUT    UINTN                            *DataSize,
+  OUT       VOID                             *Data OPTIONAL
+  )
+{
+  VARIABLE_POINTER_TRACK  Variable;
+  UINTN                   VarDataSize;
+  EFI_STATUS              Status;
+  VARIABLE_STORE_INFO     StoreInfo;
+  VARIABLE_HEADER         *VariableHeader;
+
+  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VariableName[0] == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  VariableHeader = NULL;
+
+  //
+  // Find existing variable
+  //
+  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+
+  //
+  // Get data size
+  //
+  VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+  if (*DataSize >= VarDataSize) {
+    if (Data == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (Attributes != NULL) {
+    *Attributes = VariableHeader->Attributes;
+  }
+
+  *DataSize = VarDataSize;
+
+  return Status;
+}
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+                            On return, the size of the variable name buffer.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  )
+{
+  VARIABLE_STORE_TYPE     Type;
+  VARIABLE_POINTER_TRACK  Variable;
+  VARIABLE_POINTER_TRACK  VariableInHob;
+  VARIABLE_POINTER_TRACK  VariablePtrTrack;
+  UINTN                   VarNameSize;
+  EFI_STATUS              Status;
+  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
+  VARIABLE_HEADER         *VariableHeader;
+  VARIABLE_STORE_INFO     StoreInfo;
+  VARIABLE_STORE_INFO     StoreInfoForNv;
+  VARIABLE_STORE_INFO     StoreInfoForHob;
+
+  if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableHeader = NULL;
+
+  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
+  if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {
+    return Status;
+  }
+
+  if (VariableName[0] != 0) {
+    //
+    // If variable name is not NULL, get next variable
+    //
+    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+  }
+
+  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
+  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
+
+  while (TRUE) {
+    //
+    // Switch from HOB to Non-Volatile.
+    //
+    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
+      //
+      // Find current storage index
+      //
+      for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
+        if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+          break;
+        }
+      }
+
+      ASSERT (Type < VariableStoreTypeMax);
+      //
+      // Switch to next storage
+      //
+      for (Type++; Type < VariableStoreTypeMax; Type++) {
+        if (VariableStoreHeader[Type] != NULL) {
+          break;
+        }
+      }
+
+      //
+      // Capture the case that
+      // 1. current storage is the last one, or
+      // 2. no further storage
+      //
+      if (Type == VariableStoreTypeMax) {
+        return EFI_NOT_FOUND;
+      }
+
+      Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+      Variable.EndPtr   = GetEndPointer (VariableStoreHeader[Type]);
+      Variable.CurrPtr  = Variable.StartPtr;
+      GetVariableStore (Type, &StoreInfo);
+    }
+
+    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
+      if (VariableHeader->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.
+        //
+        Status = FindVariableEx (
+                   &StoreInfo,
+                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+                   &VariablePtrTrack
+                   );
+        if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr)) {
+          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+          continue;
+        }
+      }
+
+      //
+      // Don't return NV variable when HOB overrides it
+      //
+      if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
+          (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
+          )
+      {
+        Status = FindVariableEx (
+                   &StoreInfoForHob,
+                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+                   &VariableInHob
+                   );
+        if (!EFI_ERROR (Status)) {
+          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+          continue;
+        }
+      }
+
+      VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+      ASSERT (VarNameSize != 0);
+
+      if (VarNameSize <= *VariableNameSize) {
+        GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);
+
+        CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
+
+        Status = EFI_SUCCESS;
+      } else {
+        Status = EFI_BUFFER_TOO_SMALL;
+      }
+
+      *VariableNameSize = VarNameSize;
+      //
+      // Variable is found
+      //
+      return Status;
+    } else {
+      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+    }
+  }
+}
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was be found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariableEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN CONST  CHAR16                           *VariableName,
+  IN CONST  EFI_GUID                         *VariableGuid,
+  OUT       UINT32                           *Attributes,
+  IN OUT    UINTN                            *DataSize,
+  OUT       VOID                             *Data OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // If variable protection is employed, always get variable data through
+  // ProtectedVariableLib.
+  //
+  Status = ProtectedVariableLibGetByName (VariableName, VariableGuid, Attributes, DataSize, Data);
+  if (Status != EFI_UNSUPPORTED) {
+    return Status;
+  }
+
+  return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize, Data);
+}
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+                            On return, the size of the variable name buffer.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableNameEx (
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
+  IN OUT UINTN                               *VariableNameSize,
+  IN OUT CHAR16                              *VariableName,
+  IN OUT EFI_GUID                            *VariableGuid
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // If variable protection is employed, always get next variable through
+  // ProtectedVariableLib.
+  //
+  Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName, VariableGuid);
+  if (Status != EFI_UNSUPPORTED) {
+    return Status;
+  }
+
+  return PeiGetNextVariableName (This, VariableNameSize, VariableName, VariableGuid);
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
new file mode 100644
index 000000000000..2d605d39cbb6
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
@@ -0,0 +1,941 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Variable.h"
+#include "VariableStore.h"
+
+/**
+
+  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);
+}
+
+/**
+  This code checks if variable header is valid or not.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+
+  @retval TRUE      Variable header is valid.
+  @retval FALSE     Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER  *Variable
+  )
+{
+  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  This code gets the size of variable header.
+
+  @param[in] AuthFlag   Authenticated variable flag.
+
+  @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+  IN  BOOLEAN  AuthFlag
+  )
+{
+  UINTN  Value;
+
+  if (AuthFlag) {
+    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]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFlag) {
+    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 gets the size of data of variable.
+
+  @param[in]  Variable  Pointer to the Variable Header.
+  @param[in]  AuthFlag  Authenticated variable flag.
+
+  @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFlag) {
+    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 gets the pointer to the variable name.
+
+  @param[in]   Variable  Pointer to the Variable Header.
+  @param[in]   AuthFlag  Authenticated variable flag.
+
+  @return  A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  )
+{
+  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+/**
+  This code gets the pointer to the variable guid.
+
+  @param[in] Variable   Pointer to the Variable Header.
+  @param[in] AuthFlag   Authenticated variable flag.
+
+  @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+  IN VARIABLE_HEADER  *Variable,
+  IN BOOLEAN          AuthFlag
+  )
+{
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+  if (AuthFlag) {
+    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]   VariableHeader   Pointer to the Variable Header that has consecutive content.
+  @param[in]   AuthFlag         Authenticated variable flag.
+
+  @return  A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  VARIABLE_HEADER  *VariableHeader,
+  IN  BOOLEAN          AuthFlag
+  )
+{
+  UINTN  Value;
+
+  //
+  // Be careful about pad size for alignment
+  //
+  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
+  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+  return (UINT8 *)Value;
+}
+
+/**
+  This code gets the pointer to the next variable header.
+
+  @param[in]  StoreInfo         Pointer to variable store info structure.
+  @param[in]  Variable          Pointer to the Variable Header.
+  @param[in]  VariableHeader    Pointer to the Variable Header that has consecutive content.
+
+  @return  A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_STORE_INFO  *StoreInfo,
+  IN  VARIABLE_HEADER      *Variable,
+  IN  VARIABLE_HEADER      *VariableHeader
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  UINTN                 Value;
+
+  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+  //
+  // Be careful about pad size for alignment
+  //
+  Value = HEADER_ALIGN (Value);
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {
+      //
+      // Next variable is in spare block.
+      //
+      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
+    }
+  }
+
+  return (VARIABLE_HEADER *)Value;
+}
+
+/**
+  Compare two variable names, one of them may be inconsecutive.
+
+  @param[in] StoreInfo      Pointer to variable store info structure.
+  @param[in] Name1          Pointer to one variable name.
+  @param[in] Name2          Pointer to another variable name.
+  @param[in] NameSize       Variable name size.
+
+  @retval TRUE          Name1 and Name2 are identical.
+  @retval FALSE         Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN CONST CHAR16         *Name1,
+  IN CONST CHAR16         *Name2,
+  IN UINTN                NameSize
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  UINTN                 PartialNameSize;
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {
+      //
+      // Name1 is inconsecutive.
+      //
+      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
+      //
+      // Partial content is in NV storage.
+      //
+      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {
+        //
+        // Another partial content is in spare block.
+        //
+        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+          return TRUE;
+        }
+      }
+
+      return FALSE;
+    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {
+      //
+      // Name2 is inconsecutive.
+      //
+      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
+      //
+      // Partial content is in NV storage.
+      //
+      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {
+        //
+        // Another partial content is in spare block.
+        //
+        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+          return TRUE;
+        }
+      }
+
+      return FALSE;
+    }
+  }
+
+  //
+  // Both Name1 and Name2 are consecutive.
+  //
+  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  This function compares a variable with variable entries in database.
+
+  @param[in]   StoreInfo        Pointer to variable store info structure.
+  @param[in]   Variable         Pointer to the variable in our database
+  @param[in]   VariableHeader   Pointer to the Variable Header that has
+                                consecutive content.
+  @param[in]   VariableName     Name of the variable to compare to 'Variable'
+  @param[in]   VendorGuid       GUID of the variable to compare to 'Variable'
+  @param[out]  PtrTrack         Variable Track Pointer structure that contains
+                                Variable Information.
+
+  @retval EFI_SUCCESS    Found match variable
+  @retval EFI_NOT_FOUND  Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+  IN  VARIABLE_STORE_INFO     *StoreInfo,
+  IN  VARIABLE_HEADER         *Variable,
+  IN  VARIABLE_HEADER         *VariableHeader,
+  IN  CONST CHAR16            *VariableName,
+  IN  CONST EFI_GUID          *VendorGuid,
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack
+  )
+{
+  VOID      *Point;
+  EFI_GUID  *TempVendorGuid;
+
+  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+  if (VariableName[0] == 0) {
+    PtrTrack->CurrPtr = Variable;
+    return EFI_SUCCESS;
+  } else {
+    //
+    // Don't use CompareGuid function here for performance reasons.
+    // Instead we compare the GUID a UINT32 at a time and branch
+    // on the first failed comparison.
+    //
+    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
+        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
+        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
+        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
+        )
+    {
+      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+      if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+        PtrTrack->CurrPtr = Variable;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get variable header that has consecutive content.
+
+  @param[in]  StoreInfo       Pointer to variable store info structure.
+  @param[in]  Variable        Pointer to the Variable Header.
+  @param[out] VariableHeader  Pointer to Pointer to the Variable Header
+                              that has consecutive content.
+
+  @retval TRUE          Variable header is valid.
+  @retval FALSE         Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN VARIABLE_HEADER      *Variable,
+  OUT VARIABLE_HEADER     **VariableHeader
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  EFI_HOB_GUID_TYPE     *GuidHob;
+  UINTN                 PartialHeaderSize;
+
+  if (Variable == NULL) {
+    return FALSE;
+  }
+
+  //
+  // First assume variable header pointed by Variable is consecutive.
+  //
+  *VariableHeader = Variable;
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)Variable > (UINTN)SpareAddress) &&
+        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
+    {
+      //
+      // Reach the end of variable store.
+      //
+      return FALSE;
+    }
+
+    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
+      //
+      // Variable header pointed by Variable is inconsecutive,
+      // create a guid hob to combine the two partial variable header content together.
+      //
+      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+      if (GuidHob != NULL) {
+        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+      } else {
+        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
+        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
+        //
+        // Partial content is in NV storage.
+        //
+        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);
+        //
+        // Another partial content is in spare block.
+        //
+        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
+      }
+    }
+  } else {
+    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+      //
+      // Reach the end of variable store.
+      //
+      return FALSE;
+    }
+  }
+
+  return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+  Get variable name or data to output buffer.
+
+  @param[in]   StoreInfo     Pointer to variable store info structure.
+  @param[in]   NameOrData    Pointer to the variable name/data that may be inconsecutive.
+  @param[in]   Size          Variable name/data size.
+  @param[out]  Buffer        Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+  IN VARIABLE_STORE_INFO  *StoreInfo,
+  IN UINT8                *NameOrData,
+  IN UINTN                Size,
+  OUT UINT8               *Buffer
+  )
+{
+  EFI_PHYSICAL_ADDRESS  TargetAddress;
+  EFI_PHYSICAL_ADDRESS  SpareAddress;
+  UINTN                 PartialSize;
+
+  if (StoreInfo->FtwLastWriteData != NULL) {
+    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
+    if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
+      //
+      // Variable name/data is inconsecutive.
+      //
+      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
+      //
+      // Partial content is in NV storage.
+      //
+      CopyMem (Buffer, NameOrData, PartialSize);
+      //
+      // Another partial content is in spare block.
+      //
+      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);
+      return;
+    }
+  }
+
+  //
+  // Variable name/data is consecutive.
+  //
+  CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
+
+  Internal function to retrieve variable information.
+
+  @param[in,out] VariableInfo     Pointer to variable information.
+  @param[in]     StoreInfo        Pointer to store copy of variable (optional).
+  @param[in]     VariablePtr      Pointer to variable buffer.
+  @param[in]     VariableHeader   Pointer to variable header.
+
+  @retval EFI_INVALID_PARAMETER  One ore more required parameters are NULL.
+  @retval EFI_BUFFER_TOO_SMALL   Given buffer is too small to hold data.
+  @retval EFI_SUCCESS            Variable details are retrieved successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableInfoInternal (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo,
+  IN      VARIABLE_STORE_INFO      *StoreInfo OPTIONAL,
+  IN      VARIABLE_HEADER          *VariablePtr,
+  IN      VARIABLE_HEADER          *VariableHeader
+  )
+{
+  VARIABLE_HEADER                *VariableBuffer;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariableHeader;
+  UINTN                          NameSize;
+  UINTN                          DataSize;
+  UINTN                          VariableSize;
+
+  if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader == NULL)) {
+    ASSERT (VariableInfo != NULL);
+    ASSERT (VariablePtr != NULL);
+    ASSERT (VariableHeader != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariableBuffer = VariableInfo->Buffer;
+
+  //
+  // Make a copy of the whole variable if VariableInfo->Buffer is given. But
+  // don't do this if StoreInfo is not given, because VariableInfo->Buffer
+  // has already hold a copy of variable in such situation.
+  //
+  NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+  DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
+  if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
+    if (StoreInfo != NULL) {
+      CopyMem (
+        VariableBuffer,
+        VariableHeader,
+        GetVariableHeaderSize (VariableInfo->Flags.Auth)
+        );
+      GetVariableNameOrData (
+        StoreInfo,
+        (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+        NameSize,
+        (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
+        );
+      GetVariableNameOrData (
+        StoreInfo,
+        (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo->Flags.Auth),
+        DataSize,
+        (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader, VariableInfo->Flags.Auth)
+        );
+    } else {
+      //
+      // Suppose the variable is in consecutive space.
+      //
+      VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
+                     + NameSize + GET_PAD_SIZE (NameSize)
+                     + DataSize;
+      CopyMem (VariableBuffer, VariablePtr, VariableSize);
+    }
+  }
+
+  //
+  // Generally, if no consecutive buffer passed in, don't return back any data.
+  //
+  // If follow pointers are NULL, return back pointers to following data inside
+  // VariableInfo->Buffer, if it's given.
+  //
+  //  VariableInfo->Header.VariableName
+  //  VariableInfo->Header.Data
+  //  VariableInfo->Header.VendorGuid
+  //  VariableInfo->Header.TimeStamp
+  //
+  // Otherwise, suppose they're buffers used to hold a copy of corresponding
+  // data.
+  //
+  //
+
+  //
+  // AuthVariable header
+  //
+  if (VariableInfo->Flags.Auth) {
+    AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableHeader;
+
+    VariableInfo->Header.State          = AuthVariableHeader->State;
+    VariableInfo->Header.Attributes     = AuthVariableHeader->Attributes;
+    VariableInfo->Header.PubKeyIndex    = AuthVariableHeader->PubKeyIndex;
+    VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
+                                            &(AuthVariableHeader->MonotonicCount)
+                                            );
+    if (VariableInfo->Header.TimeStamp != NULL) {
+      CopyMem (
+        VariableInfo->Header.TimeStamp,
+        &AuthVariableHeader->TimeStamp,
+        sizeof (EFI_TIME)
+        );
+    } else if (VariableBuffer != NULL) {
+      AuthVariableHeader             = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer;
+      VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
+    }
+  } else {
+    VariableInfo->Header.State          = VariableHeader->State;
+    VariableInfo->Header.Attributes     = VariableHeader->Attributes;
+    VariableInfo->Header.PubKeyIndex    = 0;
+    VariableInfo->Header.MonotonicCount = 0;
+    VariableInfo->Header.TimeStamp      = NULL;
+  }
+
+  //
+  // VendorGuid
+  //
+  if (VariableInfo->Header.VendorGuid != NULL) {
+    CopyGuid (
+      VariableInfo->Header.VendorGuid,
+      GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
+      );
+  } else if (VariableBuffer != NULL) {
+    VariableInfo->Header.VendorGuid
+      = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
+  }
+
+  //
+  // VariableName
+  //
+  if (  (VariableInfo->Header.VariableName != NULL)
+     && (VariableInfo->Header.NameSize >= NameSize))
+  {
+    GetVariableNameOrData (
+      StoreInfo,
+      (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
+      NameSize,
+      (UINT8 *)VariableInfo->Header.VariableName
+      );
+  } else if (VariableBuffer != NULL) {
+    VariableInfo->Header.VariableName
+      = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
+  } else if (VariableInfo->Header.VariableName != NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  //
+  // Data
+  //
+  if (  (VariableInfo->Header.Data != NULL)
+     && (VariableInfo->Header.DataSize >= DataSize))
+  {
+    GetVariableNameOrData (
+      StoreInfo,
+      GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
+      DataSize,
+      VariableInfo->Header.Data
+      );
+  } else if (VariableBuffer != NULL) {
+    VariableInfo->Header.Data
+      = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo->Flags.Auth);
+  } else if (VariableInfo->Header.Data != NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  //
+  // Update size information about name & data.
+  //
+  VariableInfo->Header.NameSize = NameSize;
+  VariableInfo->Header.DataSize = DataSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Retrieve details about a variable, given by VariableInfo->Buffer or
+  VariableInfo->Index, and pass the details back in VariableInfo->Header.
+
+  This function is used to resolve the variable data structure into
+  VariableInfo->Header, for easier access later without revisiting the variable
+  data in variable store. If pointers in the structure of VariableInfo->Header
+  are not NULL, it's supposed that they are buffers passed in to hold a copy of
+  data of corresponding data fields in variable data structure. Otherwise, this
+  function simply returns pointers pointing to address of those data fields.
+
+  The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
+  If VariableInfo->Index is given, this function finds the corresponding variable
+  first from variable storage according to the Index.
+
+  If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
+  that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
+  requested variable data to be returned.
+
+  @param[in,out] VariableInfo             Pointer to variable information.
+
+  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo->Buffer
+                                 and VariableInfo->Index are NULL (0).
+  @retval EFI_NOT_FOUND          If given Buffer or Index 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_HEADER      *VariablePtr;
+  VARIABLE_HEADER      *VariableHeader;
+  VARIABLE_STORE_TYPE  StoreType;
+  VARIABLE_STORE_INFO  StoreInfo;
+  UINTN                Offset;
+
+  if ((VariableInfo == NULL) ||
+      ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex == VAR_INDEX_INVALID)))
+  {
+    ASSERT (VariableInfo != NULL);
+    ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo->Buffer != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  StoreInfo.VariableStoreHeader = NULL;
+  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+    GetVariableStore (StoreType, &StoreInfo);
+    if (StoreInfo.VariableStoreHeader != NULL) {
+      break;
+    }
+  }
+
+  ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+  //
+  // No StoreIndex? Don't retrieve variable information from store but just from
+  // VariableInfo->Buffer.
+  //
+  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+    VariablePtr    = VariableInfo->Buffer;
+    VariableHeader = VariablePtr;
+
+    return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr, VariableHeader);
+  }
+
+  Offset = (UINTN)VariableInfo->StoreIndex;
+  if (  (StoreInfo.FtwLastWriteData != NULL)
+     && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                    - (UINTN)StoreInfo.VariableStoreHeader)))
+  {
+    Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+               - (UINTN)StoreInfo.VariableStoreHeader);
+    VariablePtr = (VARIABLE_HEADER *)
+                  ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+  } else {
+    VariablePtr = (VARIABLE_HEADER *)
+                  ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+  }
+
+  //
+  // Note that variable might be in unconsecutive space. Always get a copy
+  // of its header in consecutive buffer.
+  //
+  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+    return EFI_NOT_FOUND;
+  }
+
+  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
+
+/**
+
+  Retrieve details of the variable next to given variable within VariableStore.
+
+  If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
+
+  VariableStart and/or VariableEnd can be given optionally for the situation
+  in which the valid storage space is smaller than the VariableStore->Size.
+  This usually happens when PEI variable services make a compact variable
+  cache to save memory, which cannot make use VariableStore->Size to determine
+  the correct variable storage range.
+
+  @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_HEADER      *VariablePtr;
+  VARIABLE_HEADER      *VariableHeader;
+  VARIABLE_STORE_INFO  StoreInfo;
+  VARIABLE_STORE_TYPE  StoreType;
+  UINTN                Offset;
+
+  if (VariableInfo == NULL) {
+    ASSERT (VariableInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  StoreInfo.VariableStoreHeader = NULL;
+  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) {
+    GetVariableStore (StoreType, &StoreInfo);
+    if (StoreInfo.VariableStoreHeader != NULL) {
+      break;
+    }
+  }
+
+  ASSERT (StoreInfo.VariableStoreHeader != NULL);
+
+  //
+  // VariableInfo->StoreIndex is supposed to be the index to variable found
+  // last time. Use it to get the variable next to it in store. If it's invalid,
+  // return the first variable available in store.
+  //
+  VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
+  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
+    VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
+  } else {
+    Offset = (UINTN)VariableInfo->StoreIndex;
+    if (  (StoreInfo.FtwLastWriteData != NULL)
+       && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                      - (UINTN)StoreInfo.VariableStoreHeader)))
+    {
+      Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                 - (UINTN)StoreInfo.VariableStoreHeader);
+      VariablePtr = (VARIABLE_HEADER *)
+                    ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
+    } else {
+      VariablePtr = (VARIABLE_HEADER *)
+                    ((UINTN)StoreInfo.VariableStoreHeader + Offset);
+    }
+
+    //
+    // Note that variable might be in unconsecutive space. Always get a copy
+    // of its header in consecutive buffer.
+    //
+    if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+      return EFI_NOT_FOUND;
+    }
+
+    VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
+  }
+
+  //
+  // Get a copy of variable header in consecutive buffer.
+  //
+  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Use the offset to the start of variable store as index of the variable.
+  //
+  if (  (StoreInfo.FtwLastWriteData == NULL)
+     || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData->TargetAddress))
+  {
+    VariableInfo->StoreIndex
+      = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
+  } else {
+    VariableInfo->StoreIndex
+      = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
+                 - (UINTN)StoreInfo.VariableStoreHeader);
+    VariableInfo->StoreIndex
+      += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData->SpareAddress);
+  }
+
+  if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
+    VariableInfo->Buffer = VariablePtr;
+  }
+
+  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader);
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
new file mode 100644
index 000000000000..75edc3fc5051
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
@@ -0,0 +1,307 @@
+/** @file
+  Implement ReadOnly Variable Services required by PEIM and install
+  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VariableParsing.h"
+#include "VariableStore.h"
+
+/**
+  Get variable store status.
+
+  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
+
+  @retval  EfiRaw      Variable store is raw
+  @retval  EfiValid    Variable store is valid
+  @retval  EfiInvalid  Variable store 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;
+  }
+
+  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;
+  }
+}
+
+/**
+  Reports HOB variable store is available or not.
+
+  @retval EFI_NOT_READY  HOB variable store info not available.
+  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
+  @retval EFI_SUCCESS    HOB variable store is available.
+**/
+EFI_STATUS
+EFIAPI
+IsHobVariableStoreAvailable (
+  VOID
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+  VOID               *VariableStoreInfoHob;
+
+  //
+  // Discover if Variable Store Info Hob has been published by platform driver.
+  // It contains information regards to HOB or NV Variable Store availability
+  //
+  GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
+  if (GuidHob == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  //
+  // Check if HOB Variable Store is available
+  //
+  VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
+  if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // This might be NV Variable Store
+  //
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get HOB variable store.
+
+  @param[out] StoreInfo             Return the store info.
+
+**/
+VOID
+GetHobVariableStore (
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+
+  //
+  // 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 ();
+
+  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+  if (GuidHob != NULL) {
+    StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+    StoreInfo->AuthFlag            = TRUE;
+  } else {
+    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+    if (GuidHob != NULL) {
+      StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+      StoreInfo->AuthFlag            = FALSE;
+    }
+  }
+}
+
+/**
+  Get NV variable store.
+
+  @param[out] StoreInfo             Return the store info.
+  @param[out] VariableFvHeader      Return header of FV containing the store.
+
+**/
+VOID
+GetNvVariableStore (
+  OUT VARIABLE_STORE_INFO         *StoreInfo,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_HOB_GUID_TYPE                     *GuidHob;
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
+  VARIABLE_STORE_HEADER                 *StoreHeader;
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *HobData;
+  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
+  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
+  UINT32                                NvStorageSize;
+  UINT32                                BackUpOffset;
+  UINT64                                NvStorageSize64;
+
+  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);
+
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
+
+  //
+  // Check the FTW last write data hob.
+  //
+  BackUpOffset     = 0;
+  FtwLastWriteData = NULL;
+  HobData          = NULL;
+  GuidHob          = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+
+  if (GuidHob != NULL) {
+    HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
+    if (HobData->TargetAddress == NvStorageBase) {
+      //
+      // Let FvHeader point to spare block.
+      //
+      DEBUG ((
+        EFI_D_INFO,
+        "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
+        (UINTN)HobData->SpareAddress
+        ));
+
+      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData->SpareAddress;
+      HobData  = NULL;
+    } else if ((HobData->TargetAddress > NvStorageBase) &&
+               (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
+    {
+      //
+      // Flash NV storage from the offset is backed up in spare block.
+      //
+      BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
+      DEBUG ((
+        EFI_D_INFO,
+        "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n",
+        BackUpOffset,
+        (UINTN)FtwLastWriteData->SpareAddress
+        ));
+      //
+      // At least one block data in flash NV storage is still valid, so still
+      // leave FvHeader point to NV storage base.
+      //
+    }
+  }
+
+  if (StoreInfo != NULL) {
+    StoreInfo->FtwLastWriteData = HobData;
+  }
+
+  if (VariableFvHeader != NULL) {
+    *VariableFvHeader = FvHeader;
+  }
+
+  //
+  // Check if the Firmware Volume is not corrupted
+  //
+  if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
+      CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
+  {
+    StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+  } else {
+    StoreHeader = NULL;
+    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+  }
+
+  if (StoreInfo != NULL) {
+    StoreInfo->VariableStoreHeader = StoreHeader;
+    if (StoreHeader != NULL) {
+      StoreInfo->AuthFlag = CompareGuid (
+                              &StoreHeader->Signature,
+                              &gEfiAuthenticatedVariableGuid
+                              );
+    }
+  }
+}
+
+/**
+  Return the variable store header and the store info based on the Index.
+
+  @param[in]  Type       The type of the variable store.
+  @param[out] StoreInfo  Return the store info.
+
+  @return  Pointer to the variable store header.
+**/
+VARIABLE_STORE_HEADER *
+GetVariableStore (
+  IN VARIABLE_STORE_TYPE   Type,
+  OUT VARIABLE_STORE_INFO  *StoreInfo
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+
+  StoreInfo->VariableStoreHeader = NULL;
+  StoreInfo->IndexTable          = NULL;
+  StoreInfo->FtwLastWriteData    = NULL;
+  StoreInfo->AuthFlag            = FALSE;
+  switch (Type) {
+    case VariableStoreTypeHob:
+      GetHobVariableStore (StoreInfo);
+      break;
+
+    case VariableStoreTypeNv:
+      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
+        //
+        // Emulated non-volatile variable mode is not enabled.
+        //
+        GetNvVariableStore (StoreInfo, NULL);
+        if (StoreInfo->VariableStoreHeader != NULL) {
+          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+          if (GuidHob != NULL) {
+            StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+          } else {
+            //
+            // If it's the first time to access variable region in flash, create a guid hob to record
+            // VAR_ADDED type variable info.
+            // Note that as the resource of PEI phase is limited, only store the limited number of
+            // VAR_ADDED type variables to reduce access time.
+            //
+            StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+            StoreInfo->IndexTable->Length      = 0;
+            StoreInfo->IndexTable->StartPtr    = GetStartPointer (StoreInfo->VariableStoreHeader);
+            StoreInfo->IndexTable->EndPtr      = GetEndPointer (StoreInfo->VariableStoreHeader);
+            StoreInfo->IndexTable->GoneThrough = 0;
+          }
+        }
+      }
+
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+
+  return StoreInfo->VariableStoreHeader;
+}
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
new file mode 100644
index 000000000000..106c1dfdc5c0
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI."
+
diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
new file mode 100644
index 000000000000..22dd992be908
--- /dev/null
+++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PeiVariable 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
+"Variable Access PEI Module"
+
+
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (6 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-14  7:14   ` Wang, Jian J
  2022-11-06  7:34 ` [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
                   ` (12 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Hao A Wu, Nishant C Mistry

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@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@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


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (7 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Judah Vang
@ 2022-11-06  7:34 ` Judah Vang
  2022-11-22  6:44   ` Wang, Jian J
  2022-11-06  7:35 ` [PATCH v5 10/19] SecurityPkg: Add new GUIDs for Judah Vang
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:34 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Nishant C Mistry

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

V5: Add reference to new Protected Variable libs.

V1: Make reference to new Null ProtectVariableLib.
The null ProtectedVariableLib is used by default.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 MdeModulePkg/MdeModulePkg.dsc              | 20 +++++++++++++++++++-
 MdeModulePkg/Test/MdeModulePkgHostTest.dsc |  8 ++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 659482ab737f..65ec6d1e0918 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -2,7 +2,7 @@
 # EFI/PI Reference Module Package for All Architectures
 #
 # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
-# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -104,6 +104,7 @@ [LibraryClasses]
   VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
   MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
   VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf
+  ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
 
 [LibraryClasses.EBC.PEIM]
   IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
@@ -318,6 +319,7 @@ [Components]
   MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
   MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
   MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+  MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
   MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
   MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
   MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
@@ -397,6 +399,7 @@ [Components]
   MdeModulePkg/Application/VariableInfo/VariableInfo.inf
   MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
   MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
+  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
@@ -461,6 +464,7 @@ [Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
 !if $(TOOL_CHAIN_TAG) != "XCODE5"
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandaloneMm.inf
 !endif
 
 [Components.IA32, Components.X64]
@@ -475,13 +479,27 @@ [Components.IA32, Components.X64]
       NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
       NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
   }
+  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/VarCheckPolicyLib/VarCheckPolicyLib.inf
+      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
+      NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
+  }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
       NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
       NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
   }
+  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
+      NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
+  }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
+  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntimeDxe.inf
   MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
   MdeModulePkg/Library/SmmReportStatusCodeLib/StandaloneMmReportStatusCodeLib.inf
   MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf
diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index c9ec835df65d..c0ca9be71e8c 100644
--- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
+++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -42,6 +42,14 @@ [Components]
       gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|TRUE
   }
 
+  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf {
+    <LibraryClasses>
+      VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
+      VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+    <PcdsFixedAtBuild>
+      gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|TRUE
+  }
+
   MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf {
     <LibraryClasses>
       UefiSortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 10/19] SecurityPkg: Add new GUIDs for
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (8 preceding siblings ...)
  2022-11-06  7:34 ` [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-06  7:35 ` [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines Judah Vang
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

The gEdkiiProtectedVariableGlobalGuid HOB contains the global
configuration data structure which is verified in PEI Phase.
The gEdkiiMetaDataHmacVariableGuid is used for saving the
meta data HMAC variable.
The gEdkiiProtectedVariableContextGuid contains the Protected
Variable context saved in PEI phase to be used later.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
---
 SecurityPkg/SecurityPkg.dec | 43 +++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec
index 7ecf9565d98c..5e20111cceb7 100644
--- a/SecurityPkg/SecurityPkg.dec
+++ b/SecurityPkg/SecurityPkg.dec
@@ -5,7 +5,7 @@
 #  It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
 #  and libraries instances, which are used for those features.
 #
-# Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR>
 # (C) Copyright 2015 Hewlett Packard Enterprise Development LP <BR>
 # Copyright (c) Microsoft Corporation.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -226,6 +226,18 @@ [Guids]
   ## GUID used to specify section with default dbt content
   gDefaultdbtFileGuid                = { 0x36c513ee, 0xa338, 0x4976, { 0xa0, 0xfb, 0x6d, 0xdb, 0xa3, 0xda, 0xfe, 0x87 } }
 
+  ## Include/Guid/ProtectedVariable.h
+  # {8EBF379A-F18E-4728-A410-00CF9A65BE91}
+  gEdkiiProtectedVariableGlobalGuid = { 0x8ebf379a, 0xf18e, 0x4728, { 0xa4, 0x10, 0x0, 0xcf, 0x9a, 0x65, 0xbe, 0x91 } }
+
+  ## Include/Guid/ProtectedVariable.h
+  # {e3e890ad-5b67-466e-904f-94ca7e9376bb}
+  gEdkiiMetaDataHmacVariableGuid = {0xe3e890ad, 0x5b67, 0x466e, {0x90, 0x4f, 0x94, 0xca, 0x7e, 0x93, 0x76, 0xbb}}
+
+  ## Include/Guid/ProtectedVariable.h
+  # {a11a3652-875b-495a-b097-200917580b98}
+  gEdkiiProtectedVariableContextGuid = {0xa11a3652, 0x875b, 0x495a, {0xb0, 0x97, 0x20, 0x09, 0x17, 0x58, 0x0b, 0x98} }
+
 [Ppis]
   ## The PPI GUID for that TPM physical presence should be locked.
   # Include/Ppi/LockPhysicalPresence.h
@@ -251,6 +263,10 @@ [Ppis]
   ## Include/Ppi/Tcg.h
   gEdkiiTcgPpiGuid = {0x57a13b87, 0x133d, 0x4bf3, { 0xbf, 0xf1, 0x1b, 0xca, 0xc7, 0x17, 0x6c, 0xf1 } }
 
+  ## Key Service Ppi
+  # Include/Ppi/KeyServicePpi.h
+  gKeyServicePpiGuid = {0x583592f6, 0xEC34, 0x4CED, {0x8E, 0x81, 0xC8, 0xD1, 0x36, 0x93, 0x04, 0x27}}
+
 #
 # [Error.gEfiSecurityPkgTokenSpaceGuid]
 #   0x80000001 | Invalid value provided.
@@ -334,6 +350,31 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
 
   gEfiSecurityPkgTokenSpaceGuid.PcdCpuRngSupportedAlgorithm|{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}|VOID*|0x00010032
 
+  ## Progress Code for variable integrity check result.<BR><BR>
+  #  DEFAULT: (EFI_PERIPHERAL_FIXED_MEDIA | [EFI_STATUS&0xFF])
+  # @Prompt Status Code for variable integiry check result
+  gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity|0x01070000|UINT32|0x00010033
+
+  ## Null-terminated Unicode string of the Platform Variable Name
+  # @Prompt known unprotected variable name
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName|L""|VOID*|0x00010034
+
+  ## Guid name to identify Platform Variable Guid
+  # @Prompt known unprotected variable guid
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid|{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }|VOID*|0x00010035
+
+  ## Defines Protected Variable Integrity support.
+  #   TRUE  - Enable Protected Variable Integrity.<BR>
+  #   FALSE - Disable Protected Variable Integrity.<BR>
+  # @Prompt Protected Variable Integrity support.
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity|FALSE|BOOLEAN|0x00010036
+
+  ## Defines Protected Variable Confidentiality support.
+  #   TRUE  - Enable Protected Variable Confidentiality.<BR>
+  #   FALSE - Disable Protected Variable Confidentiality.<BR>
+  # @Prompt Protected Variable Integrity support.
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality|FALSE|BOOLEAN|0x00010037
+
 [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   ## Image verification policy for OptionRom. Only following values are valid:<BR><BR>
   #  NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (9 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 10/19] SecurityPkg: Add new GUIDs for Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-22  6:46   ` Wang, Jian J
  2022-11-06  7:35 ` [PATCH v5 12/19] SecurityPkg: Add new variable types and functions Judah Vang
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

V4: revert copyright date change.

V1: Add new KeyService types and defines.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 ++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/SecurityPkg/Include/Ppi/KeyServicePpi.h b/SecurityPkg/Include/Ppi/KeyServicePpi.h
new file mode 100644
index 000000000000..8cfec04f96e5
--- /dev/null
+++ b/SecurityPkg/Include/Ppi/KeyServicePpi.h
@@ -0,0 +1,57 @@
+/** @file
+  Provides Key Services.
+
+Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+@par Specification Reference:
+**/
+
+#ifndef PEI_KEY_SERVICE_PPI_H_
+#define PEI_KEY_SERVICE_PPI_H_
+///
+/// KEY SERVICE PPI GUID
+///
+extern EFI_GUID  gKeyServicePpiGuid;
+
+/**
+  Generate a new key from root key.
+
+  @param[in]   Salt                     Pointer to the salt(non-secret) value.
+  @param[in]   SaltSize                 Salt size in bytes.
+  @param[out]  NewKey                   Pointer to buffer to receive new key.
+  @param[in]   NewKeySize               Size of new key bytes to generate.
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval OTHER                         The function completed with failure.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *KEY_SERVICE_GEN_KEY)(
+  IN   UINT8        *Salt,
+  IN   UINTN        SaltSize,
+  OUT  UINT8        *NewKey,
+  IN   UINTN        NewKeySize
+  );
+
+#define KEY_SERVICE_PPI_REVISION  1
+#define ROOT_KEY_LEN              64
+#define SALT_SIZE_MIN_LEN         64
+#define KEY_SERVICE_KEY_NAME      L"KEY_SERVICE_KEY"
+
+typedef struct {
+  UINT8    RootKey[ROOT_KEY_LEN];
+  UINT8    PreviousRootKey[ROOT_KEY_LEN];
+} KEY_SERVICE_DATA;
+
+typedef struct _KEY_SERVICE_PPI KEY_SERVICE_PPI;
+
+///
+/// KEY SERVICE PPI
+/// The interface functions are for Key Service in PEI Phase
+///
+struct _KEY_SERVICE_PPI {
+  KEY_SERVICE_GEN_KEY    GenerateKey; /// Generate Key
+};
+
+#endif
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 12/19] SecurityPkg: Add new variable types and functions
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (10 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-06  7:35 ` [PATCH v5 13/19] SecurityPkg: Update RPMC APIs with index Judah Vang
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

Add new variable encryption/decryption function prototypes.
Add new variable digest structure. Add new Protected
variable function prototypes. Update RPMC APIs to Add
an index because there is could more than one counter.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Include/Library/RpmcLib.h        | 15 +++++---
 SecurityPkg/Include/Library/VariableKeyLib.h | 37 +++-----------------
 2 files changed, 16 insertions(+), 36 deletions(-)

diff --git a/SecurityPkg/Include/Library/RpmcLib.h b/SecurityPkg/Include/Library/RpmcLib.h
index df4ba34ba8cf..cb71dfcd7e4d 100644
--- a/SecurityPkg/Include/Library/RpmcLib.h
+++ b/SecurityPkg/Include/Library/RpmcLib.h
@@ -1,19 +1,23 @@
 /** @file
   Public definitions for the Replay Protected Monotonic Counter (RPMC) Library.
 
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
-#ifndef _RPMC_LIB_H_
-#define _RPMC_LIB_H_
+#ifndef RPMC_LIB_H_
+#define RPMC_LIB_H_
 
 #include <Uefi/UefiBaseType.h>
 
+#define RPMC_COUNTER_1  0
+#define RPMC_COUNTER_2  1
+
 /**
   Requests the monotonic counter from the designated RPMC counter.
 
+  @param[in]    CounterIndex            The RPMC index
   @param[out]   CounterValue            A pointer to a buffer to store the RPMC value.
 
   @retval       EFI_SUCCESS             The operation completed successfully.
@@ -23,12 +27,15 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 EFI_STATUS
 EFIAPI
 RequestMonotonicCounter (
+  IN  UINT8   CounterIndex,
   OUT UINT32  *CounterValue
   );
 
 /**
   Increments the monotonic counter in the SPI flash device by 1.
 
+  @param[in]    CounterIndex            The RPMC index
+
   @retval       EFI_SUCCESS             The operation completed successfully.
   @retval       EFI_DEVICE_ERROR        A device error occurred while attempting to update the counter.
   @retval       EFI_UNSUPPORTED         The operation is un-supported.
@@ -36,7 +43,7 @@ RequestMonotonicCounter (
 EFI_STATUS
 EFIAPI
 IncrementMonotonicCounter (
-  VOID
+  IN  UINT8  CounterIndex
   );
 
 #endif
diff --git a/SecurityPkg/Include/Library/VariableKeyLib.h b/SecurityPkg/Include/Library/VariableKeyLib.h
index 561ebad09da2..6076c4d4731b 100644
--- a/SecurityPkg/Include/Library/VariableKeyLib.h
+++ b/SecurityPkg/Include/Library/VariableKeyLib.h
@@ -1,13 +1,13 @@
 /** @file
   Public definitions for Variable Key Library.
 
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
-#ifndef _VARIABLE_KEY_LIB_H_
-#define _VARIABLE_KEY_LIB_H_
+#ifndef VARIABLE_KEY_LIB_H_
+#define VARIABLE_KEY_LIB_H_
 
 #include <Uefi/UefiBaseType.h>
 
@@ -25,35 +25,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 EFI_STATUS
 EFIAPI
 GetVariableKey (
-  OUT VOID       **VariableKey,
-  IN  OUT UINTN  *VariableKeySize
-  );
-
-/**
-  Regenerates the variable key.
-
-  @retval       EFI_SUCCESS             The variable key was regenerated successfully.
-  @retval       EFI_DEVICE_ERROR        An error occurred while attempting to regenerate the key.
-  @retval       EFI_ACCESS_DENIED       The function was invoked after locking the key interface.
-  @retval       EFI_UNSUPPORTED         Key regeneration is not supported in the current boot configuration.
-**/
-EFI_STATUS
-EFIAPI
-RegenerateVariableKey (
-  VOID
-  );
-
-/**
-  Locks the regenerate key interface.
-
-  @retval       EFI_SUCCESS             The key interface was locked successfully.
-  @retval       EFI_UNSUPPORTED         Locking the key interface is not supported in the current boot configuration.
-  @retval       Others                  An error occurred while attempting to lock the key interface.
-**/
-EFI_STATUS
-EFIAPI
-LockVariableKeyInterface (
-  VOID
+  OUT VOID   *VariableKey,
+  IN  UINTN  VariableKeySize
   );
 
 #endif
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 13/19] SecurityPkg: Update RPMC APIs with index
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (11 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 12/19] SecurityPkg: Add new variable types and functions Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-06  7:35 ` [PATCH v5 14/19] SecurityPkg: Fix GetVariableKey API Judah Vang
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

Update RPMC APIs with index parameter because sometimes
there are more than 1 RPMC counter on the platform.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
---
 SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c b/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
index 792e48250e5d..557aeb6abf09 100644
--- a/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
+++ b/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
@@ -1,7 +1,7 @@
 /** @file
   NULL RpmcLib instance for build purpose.
 
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -12,6 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 /**
   Requests the monotonic counter from the designated RPMC counter.
 
+  @param[in]    CounterIndex            The RPMC index
   @param[out]   CounterValue            A pointer to a buffer to store the RPMC value.
 
   @retval       EFI_SUCCESS             The operation completed successfully.
@@ -21,6 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 EFI_STATUS
 EFIAPI
 RequestMonotonicCounter (
+  IN  UINT8   CounterIndex,
   OUT UINT32  *CounterValue
   )
 {
@@ -31,6 +33,8 @@ RequestMonotonicCounter (
 /**
   Increments the monotonic counter in the SPI flash device by 1.
 
+  @param[in]    CounterIndex            The RPMC index
+
   @retval       EFI_SUCCESS             The operation completed successfully.
   @retval       EFI_DEVICE_ERROR        A device error occurred while attempting to update the counter.
   @retval       EFI_UNSUPPORTED         The operation is un-supported.
@@ -38,7 +42,7 @@ RequestMonotonicCounter (
 EFI_STATUS
 EFIAPI
 IncrementMonotonicCounter (
-  VOID
+  IN  UINT8  CounterIndex
   )
 {
   ASSERT (FALSE);
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 14/19] SecurityPkg: Fix GetVariableKey API
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (12 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 13/19] SecurityPkg: Update RPMC APIs with index Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-06  7:35 ` [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs Judah Vang
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

V4: Applied code review - function comments need to match
function prototype.

V1: Fix GetVariableKey API to match changes in header files.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c b/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
index a08def767b5f..2cf4b3cbf9f6 100644
--- a/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
+++ b/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
@@ -1,7 +1,7 @@
 /** @file
   Null version of VariableKeyLib for build purpose. Don't use it in real product.
 
-Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -12,7 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
   Retrieves the key for integrity and/or confidentiality of variables.
 
   @param[out]     VariableKey         A pointer to pointer for the variable key buffer.
-  @param[in,out]  VariableKeySize     The size in bytes of the variable key.
+  @param[in]      VariableKeySize     The size in bytes of the variable key.
 
   @retval       EFI_SUCCESS             The variable key was returned.
   @retval       EFI_DEVICE_ERROR        An error occurred while attempting to get the variable key.
@@ -22,8 +22,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 EFI_STATUS
 EFIAPI
 GetVariableKey (
-  OUT VOID       **VariableKey,
-  IN  OUT UINTN  *VariableKeySize
+  OUT VOID   *VariableKey,
+  IN  UINTN  VariableKeySize
   )
 {
   ASSERT (FALSE);
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (13 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 14/19] SecurityPkg: Fix GetVariableKey API Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-22  6:55   ` Wang, Jian J
  2022-11-06  7:35 ` [PATCH v5 16/19] SecurityPkg: Add VariableKey library function Judah Vang
                   ` (5 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

V4: Applied code review - Remove empty Guids section
from .inf file. Update description in *.c. Remove *.uni file
and reference to it.

V1: Provide null ecryption variable libraries.
These will be used by default for platforms that don't
support protected variable encryption.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf | 34 ++++++++
 SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c          | 92 ++++++++++++++++++++
 2 files changed, 126 insertions(+)

diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
new file mode 100644
index 000000000000..185b6f9bedf7
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+#  Provides NULL version of encryption variable services.
+#
+#  Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = EncryptionVariableLibNull
+  FILE_GUID                      = 3972E6FE-74D5-45C3-A9FB-DB9E5E5C9C17
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = EncryptionVariableLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  EncryptionVariable.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
new file mode 100644
index 000000000000..52ee8a7b5aae
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
@@ -0,0 +1,92 @@
+/** @file
+  NULL implementation of EncryptionVariableLib.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/EncryptionVariableLib.h>
+#include <Library/DebugLib.h>
+
+/**
+  Encrypt variable data.
+
+  Null version.
+
+  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
+                                 information about a variable.
+
+  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+EncryptVariable (
+  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Decrypt variable data.
+
+  Null version.
+
+  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
+                                 information about a variable.
+
+  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+DecryptVariable (
+  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Get cipher information.
+
+  Null version.
+
+  @param[in]   VarEncInfo   Pointer to structure containing detailed
+                            information about a variable.
+
+  @retval EFI_UNSUPPORTED         Unsupported interface.
+
+**/
+EFI_STATUS
+EFIAPI
+GetCipherDataInfo (
+  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Set cipher information for a variable.
+
+  Null version.
+
+  @param[in]   VarEncInfo   Pointer to structure containing detailed
+                            information about a variable.
+
+  @retval EFI_UNSUPPORTED         If this method is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCipherDataInfo (
+  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  return EFI_UNSUPPORTED;
+}
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 16/19] SecurityPkg: Add VariableKey library function
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (14 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-06  7:35 ` [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

V5: Applied code review comments. Add PEIM to library class

V1: Provide function that retrieves the key for protected
variables.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf | 36 ++++++++++++
 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c   | 59 ++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
new file mode 100644
index 000000000000..a9f7bb5afefd
--- /dev/null
+++ b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
@@ -0,0 +1,36 @@
+## @file
+#  Provides default implementation of VariableKeyLib.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = VariableKeyLib
+  FILE_GUID                      = 7DF5A0BA-1DBB-4E67-A9F7-9FCCB1F9D250
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = VariableKeyLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 Arm AArch64
+#
+
+[Sources]
+  VariableKeyLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+
+[PpiS]
+  gKeyServicePpiGuid ## CONSUMES
+
diff --git a/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
new file mode 100644
index 000000000000..31b22782cb0c
--- /dev/null
+++ b/SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
@@ -0,0 +1,59 @@
+/** @file
+  VariableKeyLib implementation.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+#include <Library/VariableKeyLib.h>
+
+#include <Ppi/KeyServicePpi.h>
+
+#define VAR_KEY_SALT       L"Key for RPMC Variable"
+#define VAR_KEY_SALT_SIZE  sizeof (VAR_KEY_SALT)
+
+/**
+  Retrieves the key for integrity and/or confidentiality of variables.
+
+  @param[out]     VariableKey         A pointer to pointer for the variable key buffer.
+  @param[in]      VariableKeySize     The size in bytes of the variable key.
+
+  @retval       EFI_SUCCESS             The variable key was returned.
+  @retval       EFI_DEVICE_ERROR        An error occurred while attempting to get the variable key.
+  @retval       EFI_ACCESS_DENIED       The function was invoked after locking the key interface.
+  @retval       EFI_UNSUPPORTED         The variable key is not supported in the current boot configuration.
+**/
+EFI_STATUS
+EFIAPI
+GetVariableKey (
+  OUT VOID   *VariableKey,
+  IN  UINTN  VariableKeySize
+  )
+{
+  EFI_STATUS       Status;
+  KEY_SERVICE_PPI  *KeyService;
+
+  Status = PeiServicesLocatePpi (
+             &gKeyServicePpiGuid,
+             0,
+             NULL,
+             (void **)&KeyService
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Status = KeyService->GenerateKey (
+                         (UINT8 *)VAR_KEY_SALT,
+                         VAR_KEY_SALT_SIZE,
+                         VariableKey,
+                         VariableKeySize
+                         );
+  return Status;
+}
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (15 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 16/19] SecurityPkg: Add VariableKey library function Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-22  7:15   ` Wang, Jian J
  2022-11-06  7:35 ` [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services Judah Vang
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Min Xu, Nishant C Mistry

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

V3: Change AllocateZeroPool() with AllocatePages() and FreePool()
with FreePages(). FreePool() is not supported in PEI phase so this was
causing a memory leak. Reverse the order of the FreePages() call.

V1: Add encryption/decryption of protected variable functionality.
Add functions to get/set cipher data of a protected variable.
This is use for supporting confidentiality for protected
variables.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf |  43 ++
 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h      |  49 ++
 SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c      | 734 ++++++++++++++++++++
 3 files changed, 826 insertions(+)

diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
new file mode 100644
index 000000000000..7ece52f2fb58
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
@@ -0,0 +1,43 @@
+## @file
+#  Provides variable encryption/decryption services.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = EncryptionVariableLib
+  FILE_GUID                      = 459E2CB0-AF4B-4415-B6A1-335E71FD8B85
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = EncryptionVariableLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  EncryptionVariable.c
+  EncryptionVariable.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  BaseCryptLib
+
+[Guids]
+  gEfiVariableGuid
+  gEfiAuthenticatedVariableGuid
diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
new file mode 100644
index 000000000000..f35f9f9e3ad7
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
@@ -0,0 +1,49 @@
+/** @file
+  Definitions used by this library implementation.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef ENCRYPTION_VARIABLE_H_
+#define ENCRYPTION_VARIABLE_H_
+
+#define ENC_KEY_SEP        L":"
+#define ENC_KEY_SEP_SIZE   2
+#define ENC_KEY_NAME       L"VAR_ENC_KEY"
+#define ENC_KEY_NAME_SIZE  22
+
+#define ENC_KEY_SIZE    (256/8)
+#define ENC_BLOCK_SIZE  AES_BLOCK_SIZE
+#define ENC_IVEC_SIZE   ENC_BLOCK_SIZE
+
+#define ENC_PADDING_BYTE  0x0F
+
+//
+// PKCS#5 padding
+//
+// #define AES_CIPHER_DATA_SIZE(PlainDataSize)
+//  (AES_BLOCK_SIZE + (PlainDataSize)) & (~(AES_BLOCK_SIZE - 1))
+//
+#define AES_CIPHER_DATA_SIZE(PlainDataSize)  ALIGN_VALUE (PlainDataSize, AES_BLOCK_SIZE)
+
+#define FREE_POOL(Address)      \
+    if ((Address) != NULL) {    \
+      FreePool (Address);       \
+      (Address) = NULL;         \
+    }
+
+#pragma pack(1)
+
+typedef struct {
+  UINT32    DataType;         // SYM_TYPE_AES
+  UINT32    HeaderSize;       // sizeof(VARIABLE_ENCRYPTION_HEADER)
+  UINT32    PlainDataSize;    // Plain data size
+  UINT32    CipherDataSize;   // Cipher data size
+  UINT8     KeyIvec[ENC_IVEC_SIZE];
+} VARIABLE_ENCRYPTION_HEADER;
+
+#pragma pack()
+
+#endif // _ENCRYPTION_VARIABLE_H_
diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
new file mode 100644
index 000000000000..d128b32f93e0
--- /dev/null
+++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
@@ -0,0 +1,734 @@
+/** @file
+  Implementation of EncryptionVariableLib with AES algorithm support.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/VariableFormat.h>
+#include <Library/EncryptionVariableLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include "EncryptionVariable.h"
+
+/**
+  Derive encryption key for given variable from variable root key.
+
+  The derivation algorithm is depicted below
+
+    HKDF_Expand(SHA256, RootKey, Name||':'||Guid||':'||Attr||"VAR_ENC_KEY")
+
+  @param[in]    VarEncInfo    Pointer to structure containing detailed
+                              information about a variable.
+  @param[in]    EncKeySize    Size of key requested.
+  @param[out]   EncKey        Buffer of key.
+
+  @retval TRUE    The key was derived successfully.
+  @retval FALSE   Failed to generate encryption key.
+
+**/
+STATIC
+BOOLEAN
+EncVarLibGenEncKey (
+  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo,
+  IN UINTN                     EncKeySize,
+  OUT UINT8                    *EncKey
+  )
+{
+  BOOLEAN  Status;
+
+  struct {
+    VOID     *Data;
+    UINTN    Size;
+  }                 InfoGroup[6];
+  UINT8  *Info;
+  UINTN  InfoSize;
+  UINTN  Index;
+  UINT8  Salt[16];
+
+  //
+  // info: Name||':'||Guid||':'||Attr||"VAR_ENC_KEY"
+  //
+  InfoGroup[0].Size = VarEncInfo->Header.NameSize;
+  InfoGroup[0].Data = VarEncInfo->Header.VariableName;
+
+  InfoGroup[1].Size = ENC_KEY_SEP_SIZE;
+  InfoGroup[1].Data = ENC_KEY_SEP;
+
+  InfoGroup[2].Size = sizeof (*VarEncInfo->Header.VendorGuid);
+  InfoGroup[2].Data = VarEncInfo->Header.VendorGuid;
+
+  InfoGroup[3].Size = ENC_KEY_SEP_SIZE;
+  InfoGroup[3].Data = ENC_KEY_SEP;
+
+  InfoGroup[4].Size = sizeof (VarEncInfo->Header.Attributes);
+  InfoGroup[4].Data = &VarEncInfo->Header.Attributes;
+
+  InfoGroup[5].Size = ENC_KEY_NAME_SIZE;
+  InfoGroup[5].Data = ENC_KEY_NAME;
+
+  for (InfoSize = 0, Index = 0; Index < ARRAY_SIZE (InfoGroup); ++Index) {
+    InfoSize += InfoGroup[Index].Size;
+  }
+
+  Info = AllocatePages (EFI_SIZE_TO_PAGES (InfoSize));
+  if (Info == NULL) {
+    ASSERT (Info != NULL);
+    return FALSE;
+  }
+
+  for (InfoSize = 0, Index = 0; Index < ARRAY_SIZE (InfoGroup); ++Index) {
+    CopyMem (Info + InfoSize, InfoGroup[Index].Data, InfoGroup[Index].Size);
+    InfoSize += InfoGroup[Index].Size;
+  }
+
+  Status = HkdfSha256ExtractAndExpand (
+             VarEncInfo->Key,
+             VarEncInfo->KeySize,
+             Salt,
+             0,
+             Info,
+             InfoSize,
+             EncKey,
+             EncKeySize
+             );
+
+  FreePages (Info, EFI_SIZE_TO_PAGES (InfoSize));
+
+  return Status;
+}
+
+/**
+  Generate init-vector for AES encryption.
+
+  @param[out]   InitVector  IVEC buffer.
+  @param[in]    Size        Size of IVEC requested.
+
+  @retval TRUE    IVEC was generated successfully.
+  @retval FALSE   Failed to generate IVEC.
+
+**/
+STATIC
+BOOLEAN
+EncVarLibGenIvec (
+  OUT UINT8  *InitVector,
+  IN  UINTN  Size
+  )
+{
+  return RandomBytes (InitVector, Size);
+}
+
+/**
+  Check if there's valid variable information needed by encrypting or decrypting.
+
+  @param[in]    VarEncInfo    Buffer conveying details about a variable.
+  @param[in]    CheckForEnc   Flag indicating check for encrypting (TRUE) or
+                              decrypting (FALSE).
+
+  @retval TRUE    VarEncInfo is valid.
+  @retval FALSE   VarEncInfo is invalid.
+
+**/
+STATIC
+BOOLEAN
+IsValidVariableInfo (
+  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo,
+  IN BOOLEAN                   CheckForEnc
+  )
+{
+  BOOLEAN  Valid;
+
+  if (CheckForEnc) {
+    Valid = (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+            || (VarEncInfo->PlainData != NULL && VarEncInfo->PlainDataSize > 0);
+    if (!Valid) {
+      ASSERT (
+        (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+             || (VarEncInfo->PlainData != NULL && VarEncInfo->PlainDataSize > 0)
+        );
+    }
+  } else {
+    Valid = (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+            || (VarEncInfo->CipherData != NULL && VarEncInfo->CipherDataSize > 0);
+    if (!Valid) {
+      ASSERT (
+        (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
+             || (VarEncInfo->CipherData != NULL && VarEncInfo->CipherDataSize > 0)
+        );
+    }
+  }
+
+  Valid = Valid
+          && VarEncInfo->Header.VariableName != NULL
+          && VarEncInfo->Header.NameSize > 0
+          && VarEncInfo->Header.VendorGuid != NULL
+          && VarEncInfo->Key != NULL
+          && VarEncInfo->KeySize > 0;
+  if (!Valid) {
+    ASSERT (VarEncInfo->Header.VariableName != NULL);
+    ASSERT (VarEncInfo->Header.NameSize != 0);
+    ASSERT (VarEncInfo->Header.VendorGuid != NULL);
+    ASSERT (VarEncInfo->Key != NULL);
+    ASSERT (VarEncInfo->KeySize > 0);
+  }
+
+  return Valid;
+}
+
+/**
+  Sanity check of encrption header prefixed to encrypted data.
+
+  @param[in]    EncHeader   Pointer to VARIABLE_ENCRYPTION_HEADER.
+  @param[in]    DataSize    Size of variable data payload.
+
+  @retval TRUE    EncHeader is valid.
+  @retval FALSE   EncHeader is invalid.
+
+**/
+STATIC
+BOOLEAN
+IsValidEncrptionHeader (
+  IN VARIABLE_ENCRYPTION_HEADER  *EncHeader,
+  IN UINT32                      DataSize
+  )
+{
+  if (  (DataSize > sizeof (VARIABLE_ENCRYPTION_HEADER))
+     && ((EncHeader->DataType == ENC_TYPE_AES) || (EncHeader->DataType == ENC_TYPE_NULL))
+     && (EncHeader->HeaderSize >= sizeof (VARIABLE_ENCRYPTION_HEADER))
+     && (EncHeader->CipherDataSize > 0)
+     && ((EncHeader->CipherDataSize % ENC_BLOCK_SIZE) == 0)
+     && (EncHeader->PlainDataSize > 0)
+     && (EncHeader->PlainDataSize <= EncHeader->CipherDataSize)
+     && ((EncHeader->CipherDataSize + EncHeader->HeaderSize) <= DataSize))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Encrypt variable data.
+
+  If VarEncInfo->PlainData is not NULL, VarEncInfo->PlainData holds the plain
+  data. Otherwise, VarEncInfo->Headr.Data is supposed to be the plain data.
+
+  If VarEncInfo->CipherData is not NULL, The encrypted data is stored in
+  VarEncInfo->CipherData. Otherwise, the encrypted data is stored directly
+  in variable data buffer, i.e. VarEncInfo->Headr.Data.
+
+  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
+                                 information about a variable.
+
+  @retval EFI_SUCCESS             Variable was encrypted successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_BUFFER_TOO_SMALL    VarEncInfo->CipherData is not NULL but
+                                  VarEncInfo->CipherDataSize is too small.
+  @retval EFI_ABORTED             Uknown error occurred during encrypting.
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+EncryptVariable (
+  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  EFI_STATUS                  Status;
+  VOID                        *AesContext;
+  UINT8                       EncKey[ENC_KEY_SIZE];
+  UINT8                       Ivec[ENC_IVEC_SIZE];
+  UINT8                       *PlainBuffer;
+  UINT8                       *CipherBuffer;
+  UINT8                       *PlainData;
+  UINT32                      PlainDataSize;
+  VARIABLE_ENCRYPTION_HEADER  *CipherData;
+  UINT32                      CipherDataSize;
+  UINT32                      PaddingBytes;
+
+  Status       = EFI_ABORTED;
+  AesContext   = NULL;
+  PlainBuffer  = NULL;
+  CipherBuffer = NULL;
+
+  if (!IsValidVariableInfo (VarEncInfo, TRUE)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VarEncInfo->PlainData != NULL) {
+    PlainData     = VarEncInfo->PlainData;
+    PlainDataSize = VarEncInfo->PlainDataSize;
+  } else {
+    PlainData     = VarEncInfo->Header.Data;
+    PlainDataSize = (UINT32)VarEncInfo->Header.DataSize;
+  }
+
+  CipherDataSize = AES_CIPHER_DATA_SIZE (PlainDataSize);
+  if (VarEncInfo->CipherData != NULL) {
+    if (VarEncInfo->CipherDataSize
+        < (CipherDataSize + sizeof (VARIABLE_ENCRYPTION_HEADER)))
+    {
+      VarEncInfo->CipherDataSize = CipherDataSize
+                                   + sizeof (VARIABLE_ENCRYPTION_HEADER);
+      return EFI_BUFFER_TOO_SMALL;
+    }
+
+    CipherData = VarEncInfo->CipherData;
+  } else {
+    CipherData = VarEncInfo->Header.Data;
+  }
+
+  //
+  // Prepare buffer for encrypted data.
+  //
+  if ((UINTN)CipherData == (UINTN)PlainData) {
+    //
+    // Need buffer to store the encrypted data temporarily.
+    //
+    CipherBuffer = (UINT8 *)AllocateZeroPool (
+                              CipherDataSize
+                              + sizeof (VARIABLE_ENCRYPTION_HEADER)
+                              );
+    if (CipherBuffer == NULL) {
+      ASSERT (CipherBuffer != NULL);
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    CipherBuffer = (UINT8 *)CipherData;
+  }
+
+  //
+  // Plain variable data must also be multiple of ENC_BLOCK_SIZE.
+  //
+  PaddingBytes = ALIGN_VALUE (PlainDataSize, ENC_BLOCK_SIZE) - PlainDataSize;
+  if (PaddingBytes != 0) {
+    //
+    // Since the plain data size will be saved in the VARIABLE_ENCRYPTION_HEADER,
+    // there's no need to do PKCS way of padding. To save space, just padding
+    // the plain data to be of the nearest n*ENC_BLOCK_SIZE.
+    //
+    PlainBuffer = AllocateZeroPool (PlainDataSize + PaddingBytes);
+    if (PlainBuffer == NULL) {
+      ASSERT (PlainBuffer != NULL);
+      goto Done;
+    }
+
+    CopyMem (PlainBuffer, PlainData, PlainDataSize);
+    SetMem (PlainBuffer + PlainDataSize, PaddingBytes, ENC_PADDING_BYTE);
+  } else {
+    PlainBuffer = PlainData;
+  }
+
+  //
+  // Skip EFI_VARIABLE_APPEND_WRITE bit in generating encryption key.
+  //
+  VarEncInfo->Header.Attributes &= (~EFI_VARIABLE_APPEND_WRITE);
+  if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;
+  }
+
+  if (!EncVarLibGenIvec (Ivec, ENC_IVEC_SIZE)) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;
+  }
+
+  AesContext = AllocateZeroPool (AesGetContextSize ());
+  if (AesContext == NULL) {
+    ASSERT (AesContext != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) {
+    ASSERT (FALSE);
+    goto Done;
+  }
+
+  if (AesCbcEncrypt (
+        AesContext,
+        PlainBuffer,
+        PlainDataSize + PaddingBytes,
+        Ivec,
+        CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER)
+        ))
+  {
+    //
+    // Keep the IV for decryption.
+    //
+    CopyMem (CipherData->KeyIvec, Ivec, ENC_BLOCK_SIZE);
+
+    if ((UINTN)CipherBuffer != (UINTN)CipherData) {
+      CopyMem (
+        CipherData + 1,
+        CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER),
+        CipherDataSize
+        );
+    }
+
+    CipherData->CipherDataSize = CipherDataSize;
+    CipherData->PlainDataSize  = PlainDataSize;
+    CipherData->DataType       = ENC_TYPE_AES;
+    CipherData->HeaderSize     = sizeof (VARIABLE_ENCRYPTION_HEADER);
+
+    VarEncInfo->CipherData       = CipherData;
+    VarEncInfo->CipherDataSize   = CipherDataSize + sizeof (VARIABLE_ENCRYPTION_HEADER);
+    VarEncInfo->CipherHeaderSize = sizeof (VARIABLE_ENCRYPTION_HEADER);
+    VarEncInfo->CipherDataType   = ENC_TYPE_AES;
+
+    Status = EFI_SUCCESS;
+  } else {
+    VarEncInfo->CipherData       = NULL;
+    VarEncInfo->CipherDataSize   = 0;
+    VarEncInfo->CipherHeaderSize = 0;
+    VarEncInfo->CipherDataType   = ENC_TYPE_NULL;
+
+    ASSERT (FALSE);
+  }
+
+Done:
+  FREE_POOL (AesContext);
+  if (PlainBuffer != PlainData) {
+    FREE_POOL (PlainBuffer);
+  }
+
+  if (CipherBuffer != (UINT8 *)CipherData) {
+    FREE_POOL (CipherBuffer);
+  }
+
+  return Status;
+}
+
+/**
+  Decrypt variable data.
+
+  If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
+  decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
+  VarEncInfo->Header.Data.
+
+  If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
+  back in the same buffer as cipher buffer got above, after encryption header,
+  which helps to identify later if the data in buffer is decrypted or not. This
+  can avoid repeat decryption when accessing the same variable more than once.
+
+  If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
+  passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
+  with its size.
+
+  Note the VarEncInfo->PlainData is always pointing to the buffer address with
+  decrypted data without encryption header, and VarEncInfo->PlainDataSize is
+  always the size of original variable data, if this function returned
+  successfully.
+
+  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
+                                 information about a variable.
+
+  @retval EFI_SUCCESS             Variable was decrypted successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_BUFFER_TOO_SMALL    VarEncInfo->PlainData is not NULL but
+                                  VarEncInfo->PlainDataSize is too small.
+  @retval EFI_ABORTED             Uknown error occurred during decrypting.
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate enough resource.
+  @retval EFI_COMPROMISED_DATA    The cipher header is not valid.
+  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
+
+**/
+EFI_STATUS
+EFIAPI
+DecryptVariable (
+  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  VOID                        *AesContext;
+  UINT8                       EncKey[ENC_KEY_SIZE];
+  UINT8                       *PlainBuffer;
+  UINT8                       *PlainData;
+  VARIABLE_ENCRYPTION_HEADER  *CipherData;
+  UINT32                      CipherDataSize;
+  EFI_STATUS                  Status;
+
+  Status      = EFI_ABORTED;
+  AesContext  = NULL;
+  PlainBuffer = NULL;
+
+  if (!IsValidVariableInfo (VarEncInfo, FALSE)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (VarEncInfo->CipherData != NULL) {
+    CipherData     = VarEncInfo->CipherData;
+    CipherDataSize = VarEncInfo->CipherDataSize;
+  } else {
+    CipherData     = VarEncInfo->Header.Data;
+    CipherDataSize = (UINT32)VarEncInfo->Header.DataSize;
+  }
+
+  //
+  // Sanity check of cipher header.
+  //
+  if (!IsValidEncrptionHeader (CipherData, CipherDataSize)) {
+    return EFI_COMPROMISED_DATA;
+  }
+
+  if (  (VarEncInfo->PlainData != NULL)
+     && (VarEncInfo->PlainDataSize < CipherData->PlainDataSize))
+  {
+    VarEncInfo->PlainDataSize = CipherData->PlainDataSize;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (CipherData->DataType == ENC_TYPE_AES) {
+    if (VarEncInfo->Flags.DecryptInPlace) {
+      //
+      // Reusing cipher data buffer needs to keep the encryption header.
+      //
+      PlainData = (UINT8 *)CipherData + CipherData->HeaderSize;
+    } else {
+      PlainData = VarEncInfo->PlainData;
+    }
+
+    if (PlainData == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Always need buffer to store the decrypted data temporarily, due to
+    // padding bytes or buffer reuse. Then the buffer must be larger than
+    // CipherData->PlainDataSize.
+    //
+    PlainBuffer = AllocatePages (EFI_SIZE_TO_PAGES (CipherDataSize));
+    if (PlainBuffer == NULL) {
+      ASSERT (PlainBuffer != NULL);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) {
+      ASSERT (FALSE);
+      goto Done;
+    }
+
+    AesContext = AllocatePages (EFI_SIZE_TO_PAGES (AesGetContextSize ()));
+    if (AesContext == NULL) {
+      ASSERT (AesContext != NULL);
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+
+    if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) {
+      ASSERT (FALSE);
+      goto Done;
+    }
+
+    if (AesCbcDecrypt (
+          AesContext,
+          (UINT8 *)CipherData + CipherData->HeaderSize,
+          CipherDataSize - CipherData->HeaderSize,
+          CipherData->KeyIvec,
+          PlainBuffer
+          ))
+    {
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_COMPROMISED_DATA;
+    }
+  } else {
+    //
+    // The data has been decrypted already.
+    //
+    PlainBuffer = (UINT8 *)CipherData + CipherData->HeaderSize;
+
+    if (VarEncInfo->PlainData != NULL) {
+      PlainData = VarEncInfo->PlainData;
+    } else {
+      PlainData = PlainBuffer;
+    }
+
+    Status = EFI_SUCCESS;
+  }
+
+  if (!EFI_ERROR (Status)) {
+    if (PlainBuffer != PlainData) {
+      CopyMem (PlainData, PlainBuffer, CipherData->PlainDataSize);
+    }
+
+    if (VarEncInfo->PlainData != NULL) {
+      if (VarEncInfo->PlainData != PlainBuffer) {
+        CopyMem (VarEncInfo->PlainData, PlainBuffer, CipherData->PlainDataSize);
+      }
+    } else {
+      VarEncInfo->PlainData = PlainData;
+    }
+
+    VarEncInfo->PlainDataSize    = CipherData->PlainDataSize;
+    VarEncInfo->CipherHeaderSize = CipherData->HeaderSize;
+    VarEncInfo->CipherDataType   = CipherData->DataType;
+
+    if (VarEncInfo->Flags.DecryptInPlace) {
+      CipherData->DataType = ENC_TYPE_NULL;
+    }
+  }
+
+Done:
+  if (AesContext != NULL) {
+    FreePages (AesContext, EFI_SIZE_TO_PAGES (AesGetContextSize ()));
+  }
+
+  if (PlainBuffer != NULL) {
+    FreePages (PlainBuffer, EFI_SIZE_TO_PAGES ((CipherDataSize)));
+  }
+
+  return Status;
+}
+
+/**
+  Get cipher information about a variable, including plaindata size,
+  cipher algorithm type, etc.
+
+  For data passed in with VarEncInfo,
+
+    VarEncInfo->Header.Data
+      - The variable data in normal variable structure.
+    VarEncInfo->Header.DataSize
+      - The size of variable data.
+
+  For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
+
+    VarEncInfo->CipherDataType
+      - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
+      - ENC_TYPE_AES, if the variable is encrypted.
+    VarEncInfo->CipherHeaderSize
+      - Size of cipher header put before encrypted or decrypted data.
+    VarEncInfo->PlainData
+      - NULL, if the variable is encrypted; Or
+      - pointer to original variable data, if the variable has been decrypted.
+    VarEncInfo->PlainDataSize
+      - The size of original variable data
+    VarEncInfo->CipherData
+      - NULL, if the variable is decrypted; Or
+      - pointer to start of encrypted variable data, including encryption header;
+    VarEncInfo->CipherDataSize
+      - The size of encrypted variable data, including encryption header.
+
+  @param[in]   VarEncInfo   Pointer to structure containing detailed
+                            information about a variable.
+
+  @retval EFI_SUCCESS             The information was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_NOT_FOUND           No cipher information recognized.
+  @retval EFI_UNSUPPORTED         Unsupported interface.
+
+**/
+EFI_STATUS
+EFIAPI
+GetCipherDataInfo (
+  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  VARIABLE_ENCRYPTION_HEADER  *EncHeader;
+
+  if ((VarEncInfo->Header.Data == NULL) || (VarEncInfo->Header.DataSize == 0)) {
+    ASSERT (VarEncInfo->Header.Data != NULL);
+    ASSERT (VarEncInfo->Header.DataSize != 0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Validate encryption header.
+  //
+  EncHeader = (VARIABLE_ENCRYPTION_HEADER *)VarEncInfo->Header.Data;
+  if (!IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo->Header.DataSize)) {
+    //
+    // Not an encrypted variable.
+    //
+    return EFI_NOT_FOUND;
+  }
+
+  if (EncHeader->DataType == ENC_TYPE_NULL) {
+    //
+    // The data must have been decrypted.
+    //
+    VarEncInfo->PlainData            = (UINT8 *)VarEncInfo->Header.Data + EncHeader->HeaderSize;
+    VarEncInfo->CipherData           = NULL;
+    VarEncInfo->Flags.DecryptInPlace = TRUE;
+  } else {
+    //
+    // The data is encrypted.
+    //
+    VarEncInfo->CipherData           = VarEncInfo->Header.Data;
+    VarEncInfo->PlainData            = NULL;
+    VarEncInfo->Flags.DecryptInPlace = FALSE;
+  }
+
+  VarEncInfo->PlainDataSize    = EncHeader->PlainDataSize;
+  VarEncInfo->CipherDataSize   = EncHeader->CipherDataSize + EncHeader->HeaderSize;
+  VarEncInfo->CipherDataType   = EncHeader->DataType;
+  VarEncInfo->CipherHeaderSize = EncHeader->HeaderSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Force set cipher information for a variable, like plaindata size,
+  cipher algorithm type, cipher data etc.
+
+  The destination buffer must be passed via VarEncInfo->Header.Data.
+
+  This method is only used to update and/or change plain data information.
+
+  @param[in]   VarEncInfo   Pointer to structure containing detailed
+                            information about a variable.
+
+  @retval EFI_SUCCESS             The information was updated successfully.
+  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is invalid.
+  @retval EFI_UNSUPPORTED         If this method is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCipherDataInfo (
+  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
+  )
+{
+  VARIABLE_ENCRYPTION_HEADER  *EncHeader;
+  UINT8                       *Data;
+
+  if (  (VarEncInfo->Header.Data == NULL)
+     || (VarEncInfo->Header.DataSize < sizeof (VARIABLE_ENCRYPTION_HEADER))
+     || (VarEncInfo->CipherDataType != ENC_TYPE_NULL))
+  {
+    ASSERT (VarEncInfo->Header.Data != NULL);
+    ASSERT (VarEncInfo->Header.DataSize >= sizeof (VARIABLE_ENCRYPTION_HEADER));
+    ASSERT (VarEncInfo->CipherDataType == ENC_TYPE_NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data      = VarEncInfo->Header.Data;
+  EncHeader = (VARIABLE_ENCRYPTION_HEADER *)Data;
+
+  if (  !IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo->Header.DataSize)
+     || (VarEncInfo->PlainDataSize > EncHeader->CipherDataSize))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((VarEncInfo->PlainData != NULL) && (VarEncInfo->PlainDataSize > 0)) {
+    CopyMem (
+      Data + EncHeader->HeaderSize,
+      VarEncInfo->PlainData,
+      VarEncInfo->PlainDataSize
+      );
+  }
+
+  EncHeader->DataType = VarEncInfo->CipherDataType;
+  if (VarEncInfo->PlainDataSize != 0) {
+    EncHeader->PlainDataSize = VarEncInfo->PlainDataSize;
+  }
+
+  return EFI_SUCCESS;
+}
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (16 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-22  7:59   ` Wang, Jian J
  2022-11-06  7:35 ` [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files Judah Vang
                   ` (2 subsequent siblings)
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Min Xu, Nishant C Mistry

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

V5: Applied code review comments. Remove unused API.
V3: Change placement of buffer used for confidentiality crypto
operation to fix an issue when enabling confidentiality. Remove
un-needed increment of monotonic counter.

V1: Add Protected Variable Services across the different UEFI phases.
Functions includes creating variable digest, performing integrity
check, initializing protected variables, updating protected
variables, and verifying the MetaDataHmacVar variable.
This module prevents UEFI variable tampering.  It provides
variable integrity and confidentiality.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf        |   64 +
 SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf        |   68 +
 SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf        |   67 +
 SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf |   62 +
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h        |  589 ++++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c          | 2103 ++++++++++++++++++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c             |  163 ++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c             | 1327 ++++++++++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c             |  209 ++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c    |  967 +++++++++
 SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c      |  233 +++
 11 files changed, 5852 insertions(+)

diff --git a/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
new file mode 100644
index 000000000000..74a0285af7ef
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
@@ -0,0 +1,64 @@
+## @file
+#  Provides protected variable services for EmulatorPkg.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = DxeProtectedVariableLib
+  MODULE_UNI_FILE                = ProtectedVariableLib.uni
+  FILE_GUID                      = 6F424E10-0F75-4716-9F97-58C2E1C643AD
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 0.1
+  LIBRARY_CLASS                  = ProtectedVariableLib|DXE_RUNTIME_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  ProtectedVariableDxe.c
+  ProtectedVariableCommon.c
+  ProtectedVariableSmmDxeCommon.c
+  ProtectedVariableInternal.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  HobLib
+  BaseCryptLib
+  EncryptionVariableLib
+  RpmcLib
+  HashApiLib
+  SortLib
+
+[Protocols]
+  gEfiVariableWriteArchProtocolGuid
+
+[Guids]
+  gEdkiiMetaDataHmacVariableGuid
+  gEdkiiProtectedVariableGlobalGuid
+  gEdkiiVarErrorFlagGuid
+  gEdkiiProtectedVariableContextGuid
+
+[Pcd]
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
diff --git a/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
new file mode 100644
index 000000000000..44c959a94ca3
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
@@ -0,0 +1,68 @@
+## @file
+#  Provides protected variable services.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = PeiProtectedVariableLib
+  MODULE_UNI_FILE                = ProtectedVariableLib.uni
+  FILE_GUID                      = 76FBFBCE-ACBB-4084-A348-8FCC97AAEB9D
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 0.1
+  LIBRARY_CLASS                  = ProtectedVariableLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 AARCH64
+#
+
+[Sources]
+  ProtectedVariablePei.c
+  ProtectedVariableCommon.c
+  ProtectedVariableInternal.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  HobLib
+  BaseCryptLib
+  RpmcLib
+  VariableKeyLib
+  EncryptionVariableLib
+  ReportStatusCodeLib
+  PeiServicesLib
+  HashApiLib
+  SortLib
+
+[Guids]
+  gEdkiiMetaDataHmacVariableGuid
+  gEdkiiProtectedVariableGlobalGuid
+  gEdkiiVarErrorFlagGuid
+  gEdkiiProtectedVariableContextGuid
+
+[Ppis]
+  gEfiPeiMemoryDiscoveredPpiGuid
+  gEfiPeiVariableStoreDiscoveredPpiGuid
+
+[Pcd]
+  gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
diff --git a/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
new file mode 100644
index 000000000000..ecf0b1a43d30
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
@@ -0,0 +1,67 @@
+## @file
+#  Provides protected variable services.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = SmmProtectedVariableLib
+  MODULE_UNI_FILE                = ProtectedVariableLib.uni
+  FILE_GUID                      = 2BEE71E5-259B-4057-A2C1-2115DF43C76A
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 0.1
+  LIBRARY_CLASS                  = ProtectedVariableLib|DXE_SMM_DRIVER MM_STANDALONE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  ProtectedVariableSmm.c
+  ProtectedVariableCommon.c
+  ProtectedVariableSmmDxeCommon.c
+  ProtectedVariableInternal.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  HobLib
+  BaseCryptLib
+  EncryptionVariableLib
+  RpmcLib
+  VariableKeyLib
+  HashApiLib
+  SortLib
+
+[Protocols]
+  gEfiMmEndOfDxeProtocolGuid
+
+[Guids]
+  gSmmVariableWriteGuid
+  gEdkiiMetaDataHmacVariableGuid
+  gEdkiiProtectedVariableGlobalGuid
+  gEdkiiVarErrorFlagGuid
+  gEdkiiProtectedVariableContextGuid
+
+[Pcd]
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
+
diff --git a/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
new file mode 100644
index 000000000000..011ccdce2db8
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
@@ -0,0 +1,62 @@
+## @file
+#  Provides protected variable services.
+#
+#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010029
+  BASE_NAME                      = SmmRuntimeProtectedVariableLib
+  MODULE_UNI_FILE                = ProtectedVariableLib.uni
+  FILE_GUID                      = 99A623DE-1AD3-4AB3-909D-E3AADD7845EF
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 0.1
+  LIBRARY_CLASS                  = ProtectedVariableLib|DXE_DRIVER DXE_RUNTIME_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  ProtectedVariableSmmRuntime.c
+  ProtectedVariableCommon.c
+  ProtectedVariableInternal.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  HobLib
+  BaseCryptLib
+  EncryptionVariableLib
+  RpmcLib
+  HashApiLib
+  SortLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
+  gEdkiiMetaDataHmacVariableGuid
+  gEdkiiProtectedVariableGlobalGuid
+  gEdkiiVarErrorFlagGuid
+  gEdkiiProtectedVariableContextGuid
+
+[Pcd]
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
+  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
+  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
+
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
new file mode 100644
index 000000000000..7948649b21bd
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
@@ -0,0 +1,589 @@
+/** @file
+  Definitions shared among different implementation of ProtectedVariableLib.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROTECTED_VARIABLE_INTERNAL_H_
+#define PROTECTED_VARIABLE_INTERNAL_H_
+
+#include <Guid/VariableFormat.h>
+#include <Guid/ProtectedVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/RpmcLib.h>
+#include <Library/VariableKeyLib.h>
+#include <Library/EncryptionVariableLib.h>
+#include <Library/ProtectedVariableLib.h>
+#include <Library/HashApiLib.h>
+
+#define VARIABLE_KEY_SIZE  (256/8)
+
+#define METADATA_HMAC_SIZE           (256/8)
+#define METADATA_HMAC_KEY_NAME       L"HMAC_KEY"
+#define METADATA_HMAC_KEY_NAME_SIZE  0x10
+
+#define METADATA_HMAC_SEP       L":"
+#define METADATA_HMAC_SEP_SIZE  2
+
+#define METADATA_HMAC_VARIABLE_NAME       L"MetaDataHmacVar"
+#define METADATA_HMAC_VARIABLE_NAME_SIZE  sizeof (METADATA_HMAC_VARIABLE_NAME)
+#define METADATA_HMAC_VARIABLE_GUID       gEdkiiMetaDataHmacVariableGuid
+#define METADATA_HMAC_VARIABLE_ATTR       VARIABLE_ATTRIBUTE_NV_BS_RT
+
+#define DIGEST_CONTEXT_SIZE  (HashApiGetContextSize())
+
+#define MAX_VARIABLE_SIZE                                                       \
+  MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),  \
+       PcdGet32 (PcdMaxHardwareErrorVariableSize))
+
+#define IS_VARIABLE(Var, Name, Guid)          \
+  (StrCmp ((Var)->VariableName, (Name)) == 0  \
+   && CompareGuid ((CONST EFI_GUID *)(Var)->VendorGuid, (CONST EFI_GUID *)(Guid)))
+
+#define VARIABLE_SIZE(VarInfo)                                  \
+  (((UINTN)(VarInfo)->Header.Data - (UINTN)(VarInfo)->Buffer)   \
+   + (VarInfo)->Header.DataSize                                 \
+   + GET_PAD_SIZE ((VarInfo)->Header.DataSize))
+
+#define VARIABLE_HEADER_SIZE(AuthFlag)                    \
+  ((AuthFlag) ? sizeof (AUTHENTICATED_VARIABLE_HEADER)    \
+              : sizeof (VARIABLE_HEADER))
+
+#define VARIABLE_NAME(Var, AuthFlag)                    \
+  ((CHAR16 *)((UINTN)(Var) + VARIABLE_HEADER_SIZE(AuthFlag)))
+
+#define VARIABLE_START(VarStore)  \
+   ((VARIABLE_HEADER *)HEADER_ALIGN ((VARIABLE_STORE_HEADER *)(VarStore) + 1))
+
+#define VARIABLE_END(VarStore)                         \
+   ((VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)(VarStore) \
+     + ((VARIABLE_STORE_HEADER *)(VarStore))->Size))
+
+#define SET_VARIABLE_DATA_SIZE(VarInfo, Size)                                 \
+  if ((VarInfo)->Flags.Auth) {                                                \
+    ((AUTHENTICATED_VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize = Size;  \
+    (VarInfo)->Header.DataSize = Size;                                        \
+  } else {                                                                    \
+    ((VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize = Size;                \
+      (VarInfo)->Header.DataSize = Size;                                      \
+  }
+
+#define IS_KNOWN_UNPROTECTED_VARIABLE(Global, VarInfo)  \
+  (CheckKnownUnprotectedVariable ((Global), (VarInfo)) < UnprotectedVarIndexMax)
+
+#define GET_CNTX(Global)   ((PROTECTED_VARIABLE_CONTEXT_IN *)(UINTN)((Global)->ContextIn))
+#define GET_BUFR(Address)  ((VOID *)(UINTN)(Address))
+#define GET_ADRS(Buffer)   ((EFI_PHYSICAL_ADDRESS)(UINTN)(Buffer))
+
+typedef struct _VARIABLE_IDENTIFIER {
+  CHAR16      *VariableName;
+  EFI_GUID    *VendorGuid;
+  UINT8       State;
+} VARIABLE_IDENTIFIER;
+
+typedef enum {
+  IndexHmacInDel = 0,     /// MetaDataHmacVar with state VAR_IN_DELETED_TRANSITION
+  IndexHmacAdded,         /// MetaDataHmacVar with state VAR_ADDED
+  IndexErrorFlag,         /// VarErrorFlag
+  IndexPlatformVar,       /// Platform Variable
+  UnprotectedVarIndexMax
+} UNPROTECTED_VARIABLE_INDEX;
+
+#pragma pack(1)
+
+#define PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION  0x02
+
+typedef struct _PROTECTED_VARIABLE_FLAG {
+  BOOLEAN    Auth;          // Authenticated variable format
+  BOOLEAN    WriteInit;     // Write-init-done
+  BOOLEAN    WriteReady;    // Ready-to-write
+  BOOLEAN    RecoveryMode;  // Variable storage recovery or provisioning
+  BOOLEAN    CacheReady;    // Indicates Cache is available
+  BOOLEAN    Reserved;      // reserved
+} PROTECTED_VARIABLE_FLAG;
+
+typedef struct _PROTECTED_VARIABLE_GLOBAL {
+  UINT32                     StructVersion;
+  UINT32                     StructSize;
+
+  ///
+  /// Variable root key used to derive Encryption key and HMAC key.
+  ///
+  UINT8                      RootKey[VARIABLE_KEY_SIZE];
+  ///
+  /// HMAC key derived from RootKey.
+  ///
+  UINT8                      MetaDataHmacKey[VARIABLE_KEY_SIZE];
+  ///
+  /// Number of variables in linked list pointed by VariableDigests.
+  ///
+  UINT32                     VariableNumber;
+  ///
+  /// Size of memory reserved by VariableCache.
+  ///
+  UINT32                     VariableCacheSize;
+  ///
+  /// Memory reserved to temporarily hold data of one variable, for integrity
+  /// validation purpose.
+  ///
+  EFI_PHYSICAL_ADDRESS       VariableCache;
+  ///
+  /// Pointer to linked list, in which each node holds the digest value of each
+  /// variable.
+  ///
+  EFI_PHYSICAL_ADDRESS       VariableDigests;
+  ///
+  /// Memory reserved for Context used in hash API to avoid repeat alloc/free.
+  ///
+  EFI_PHYSICAL_ADDRESS       DigestContext;
+  ///
+  /// Pointer to one of node in linked list pointed by VariableDigests, which
+  /// has been just accessed. This is mainly used to facilitate the two calls
+  /// use case of GetVariable().
+  ///
+  EFI_PHYSICAL_ADDRESS       LastAccessedVariable;
+  ///
+  /// Cached copy of pointers to nodes of unprotected variables in the linked
+  /// list pointed by VariableDigests.
+  ///
+  EFI_PHYSICAL_ADDRESS       Unprotected[UnprotectedVarIndexMax];
+  ///
+  /// Pointer to data structure holding helper functions passed by user of
+  /// ProtectedVariableLib, most of which are used to complete operations on
+  /// variable storage.
+  ///
+  EFI_PHYSICAL_ADDRESS       ContextIn;
+
+  ///
+  /// Pointer to Global data structure. This is to hold pre-mem address value.
+  /// Later to be used to identify pre-mem to post-mem transition.
+  ///
+  EFI_PHYSICAL_ADDRESS       GlobalSelf;
+
+  PROTECTED_VARIABLE_FLAG    Flags;
+} PROTECTED_VARIABLE_GLOBAL;
+
+#pragma pack()
+
+/* Sort method function pointer taking two parameters */
+typedef
+INTN
+(*SORT_METHOD) (
+  IN VARIABLE_DIGEST  *Variable1,
+  IN VARIABLE_DIGEST  *Variable2
+  );
+
+/* Update variable digest data function pointer */
+typedef
+BOOLEAN
+(*DIGEST_UPDATE) (
+  IN OUT  VOID   *Context,
+  IN      VOID   *Data,
+  IN      UINTN  DataSize
+  );
+
+/**
+
+  Print variable information
+
+  @param[in]   Data8      Pointer to data
+  @param[out]  DataSize   Size of data
+
+**/
+VOID
+PrintVariableData (
+  IN UINT8  *Data8,
+  IN UINTN  DataSize
+  );
+
+/**
+
+  Derive HMAC key from given variable root key.
+
+  @param[in]  RootKey       Pointer to root key to derive from.
+  @param[in]  RootKeySize   Size of root key.
+  @param[out] HmacKey       Pointer to generated HMAC key.
+  @param[in]  HmacKeySize   Size of HMAC key.
+
+  @retval TRUE      The HMAC key is derived successfully.
+  @retval FALSE     Failed to generate HMAC key from given root key.
+
+**/
+BOOLEAN
+EFIAPI
+GenerateMetaDataHmacKey (
+  IN   CONST UINT8  *RootKey,
+  IN   UINTN        RootKeySize,
+  OUT  UINT8        *HmacKey,
+  IN   UINTN        HmacKeySize
+  );
+
+/**
+
+  Digests the given variable data and updates HMAC context.
+
+  @param[in,out]  Context   Pointer to initialized HMAC context.
+  @param[in]      VarInfo   Pointer to variable data.
+
+  @retval TRUE    HMAC context was updated successfully.
+  @retval FALSE   Failed to update HMAC context.
+
+**/
+BOOLEAN
+UpdateVariableMetadataHmac (
+  IN  VOID                     *Context,
+  IN  PROTECTED_VARIABLE_INFO  *VarInfo
+  );
+
+/**
+
+  Re-calculate HMAC based on new variable data and re-generate MetaDataHmacVar.
+
+  @param[in]      Global          Pointer to global configuration data.
+  @param[in]      NewVarInfo      Pointer to buffer of new variable data.
+  @param[in,out]  NewHmacVarInfo  Pointer to buffer of new MetaDataHmacVar.
+
+  @return EFI_SUCCESS           The HMAC value was updated successfully.
+  @return EFI_ABORTED           Failed to calculate the HMAC value.
+  @return EFI_OUT_OF_RESOURCES  Not enough resource to calculate HMC value.
+  @return EFI_NOT_FOUND         The MetaDataHmacVar was not found in storage.
+
+**/
+EFI_STATUS
+RefreshVariableMetadataHmac (
+  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN      PROTECTED_VARIABLE_INFO    *NewVarInfo,
+  IN  OUT PROTECTED_VARIABLE_INFO    *NewHmacVarInfo
+  );
+
+/**
+
+  Retrieve the context and global configuration data structure from HOB.
+
+  Once protected NV variable storage is cached and verified in PEI phase,
+  all related information are stored in a HOB which can be used by PEI variable
+  service itself and passed to SMM along with the boot flow, which can avoid
+  many duplicate works, like generating HMAC key, verifying NV variable storage,
+  etc.
+
+  The HOB can be identified by gEdkiiProtectedVariableGlobalGuid.
+
+  @param[out]   Global      Pointer to global configuration data from PEI phase.
+
+  @retval EFI_SUCCESS     The HOB was found, and Context and Global are retrieved.
+  @retval EFI_NOT_FOUND   The HOB was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobalFromHob (
+  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
+  );
+
+/**
+
+  Get context and/or global data structure used to process protected variable.
+
+  @param[out]   Global      Pointer to global configuration data.
+
+  @retval EFI_SUCCESS         Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
+  );
+
+/**
+
+  Get context data structure used to process protected variable.
+
+  @param[out]   ContextIn   Pointer to context provided by variable runtime services.
+
+  @retval EFI_SUCCESS         Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableContext (
+  PROTECTED_VARIABLE_CONTEXT_IN  **ContextIn  OPTIONAL
+  );
+
+/**
+
+  Check if a given variable is unprotected variable specified in advance
+  and return its index ID.
+
+  @param[in] Global     Pointer to global configuration data.
+  @param[in] VarInfo    Pointer to variable information data.
+
+  @retval IndexHmacInDel    Variable is MetaDataHmacVar in delete-transition state.
+  @retval IndexHmacAdded    Variable is MetaDataHmacVar in valid state.
+  @retval IndexErrorFlag    Variable is VarErrorLog.
+  @retval Others            Variable is not any known unprotected variables.
+
+**/
+UNPROTECTED_VARIABLE_INDEX
+CheckKnownUnprotectedVariable (
+  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  PROTECTED_VARIABLE_INFO    *VarInfo
+  );
+
+/**
+
+  Return the size of variable MetaDataHmacVar.
+
+  @param[in] AuthFlag         Auth-variable indicator.
+
+  @retval size of variable MetaDataHmacVar.
+
+**/
+UINTN
+GetMetaDataHmacVarSize (
+  IN      BOOLEAN  AuthFlag
+  );
+
+/**
+
+  Fix state of MetaDataHmacVar on NV variable storage, if there's failure at
+  last boot during updating variable.
+
+  This must be done before the first writing of variable in current boot,
+  including storage reclaim.
+
+  @retval EFI_UNSUPPORTED        Updating NV variable storage is not supported.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to complete the operation.
+  @retval EFI_SUCCESS            Variable store was successfully updated.
+
+**/
+EFI_STATUS
+FixupHmacVariable (
+  VOID
+  );
+
+/**
+
+  Verify the variable digest.
+
+  @param[in]  Global      Pointer to global configuration data.
+  @param[in]  VarInfo     Pointer to verified copy of protected variables.
+  @param[in]  VarDig      Pointer to variable digest data.
+
+  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
+  @retval EFI_ABORTED            An error was encountered.
+  @retval EFI_COMPROMISED_DATA   The data was compromised.
+  @retval EFI_SUCCESS            Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+VerifyVariableDigest (
+  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  PROTECTED_VARIABLE_INFO    *VarInfo,
+  IN  VARIABLE_DIGEST            *VarDig
+  );
+
+/**
+
+  Get the variable digest.
+
+  @param[in]      Global        Pointer to global configuration data.
+  @param[in]      VarInfo       Pointer to verified copy of protected variables.
+  @param[in,out]  DigestValue   Pointer to variable digest value.
+
+  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
+  @retval EFI_ABORTED            An error was encountered.
+  @retval EFI_COMPROMISED_DATA   The data was compromised.
+  @retval EFI_SUCCESS            Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+GetVariableDigest (
+  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN      PROTECTED_VARIABLE_INFO    *VarInfo,
+  IN  OUT UINT8                      *DigestValue
+  );
+
+/**
+
+  Compare variable name and Guid
+
+  @param[in]  Name1      Name of first variable.
+  @param[in]  Name1Size  Size of first variable.
+  @param[in]  Name2      Name of second variable.
+  @param[in]  Name2Size  Size of second variable.
+  @param[in]  Guid1      Guid for first variable.
+  @param[in]  Guid2      Guid for second variable.
+
+  @retval 0         First name is identical to Second name.
+  @return others    First name is not identical to Second name.
+
+**/
+INTN
+CompareVariableNameAndGuid (
+  IN CONST CHAR16  *Name1,
+  IN UINTN         Name1Size,
+  IN CONST CHAR16  *Name2,
+  IN UINTN         Name2Size,
+  IN EFI_GUID      *Guid1,
+  IN EFI_GUID      *Guid2
+  );
+
+/**
+
+  Compare variable digest.
+
+  @param[in]  Variable1     Pointer to first variable digest.
+  @param[in]  Variable2     Pointer to second variable digest.
+
+  @retval 0         Variables are identical.
+  @return others    Variables are not identical.
+
+**/
+INTN
+CompareVariableDigestInfo (
+  IN  VARIABLE_DIGEST  *Variable1,
+  IN  VARIABLE_DIGEST  *Variable2
+  );
+
+/**
+
+  Move a node backward in the order controlled by SortMethod.
+
+  @param[in]  Node          Pointer to node to be moved.
+  @param[in]  SortMethod    Method used to compare node in list.
+
+**/
+VOID
+MoveNodeBackward (
+  IN  OUT VARIABLE_DIGEST  *Node,
+  IN  SORT_METHOD          SortMethod
+  );
+
+/**
+
+  Remove variable digest node.
+
+  @param[in,out]  Global        Pointer to global configuration data.
+  @param[in,out]  VarDig        Pointer to variable digest value.
+  @param[in]      FreeResource  Flag to indicate whether to free resource.
+
+**/
+VOID
+RemoveVariableDigestNode (
+  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  OUT VARIABLE_DIGEST            *VarDig,
+  IN      BOOLEAN                    FreeResource
+  );
+
+/**
+
+  Insert variable digest node.
+
+  @param[in,out]  Global        Pointer to global configuration data.
+  @param[in]      VarDig        Pointer to variable digest value.
+  @param[in]      SortMethod    Method for sorting.
+
+**/
+VOID
+InsertVariableDigestNode (
+  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN      VARIABLE_DIGEST            *VarDig,
+  IN      SORT_METHOD                SortMethod
+  );
+
+/**
+
+  Create variable digest node.
+
+  @param[in]  VariableName      Name of variable.
+  @param[in]  VendorGuid        Guid of variable.
+  @param[in]  NameSize          Size of variable name.
+  @param[in]  DataSize          Size of variable data.
+  @param[in]  AuthVar           Authenticated variable flag.
+  @param[in]  Global            Pointer to global configuration data.
+
+  @retval Ptr   Pointer to variable digest
+
+**/
+VARIABLE_DIGEST *
+CreateVariableDigestNode (
+  IN CHAR16                     *VariableName,
+  IN EFI_GUID                   *VendorGuid,
+  IN UINT16                     NameSize,
+  IN UINT32                     DataSize,
+  IN BOOLEAN                    AuthVar,
+  IN PROTECTED_VARIABLE_GLOBAL  *Global
+  );
+
+/**
+
+  Find the specified variable digest
+
+  @param[in]  Global        Pointer to global configuration data.
+  @param[in]  VarInfo       Pointer to variable data.
+  @param[in]  FindNext      Flag to continue looking for variable.
+
+**/
+VARIABLE_DIGEST *
+FindVariableInternal (
+  IN PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN PROTECTED_VARIABLE_INFO    *VarInfo,
+  IN BOOLEAN                    FindNext
+  );
+
+/**
+
+  Synchronize the RPMC counters
+
+  @param[in]  Global      Pointer to global configuration data.
+  @param[in]  VarInfo     Pointer to variable data.
+  @param[in]  FindNext    Flag to continue looking for variable.
+
+  @retval EFI_SUCCESS     Successfully sync RPMC counters.
+  @return others          Failed to sync RPMC counters.
+
+**/
+EFI_STATUS
+SyncRpmcCounter (
+  VOID
+  );
+
+/**
+
+  Perform for protected variable integrity check.
+
+  If this initialization failed upon any error, the whole variable services
+  should not be used.  A system reset might be needed to re-construct NV
+  variable storage to be the default state.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected variables.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+PerformVariableIntegrityCheck (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  );
+
+extern EFI_TIME                       mDefaultTimeStamp;
+extern VARIABLE_IDENTIFIER            mUnprotectedVariables[UnprotectedVarIndexMax];
+extern PROTECTED_VARIABLE_CONTEXT_IN  mVariableContextIn;
+extern PROTECTED_VARIABLE_GLOBAL      mProtectedVariableGlobal;
+
+#endif
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
new file mode 100644
index 000000000000..456c871a4561
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
@@ -0,0 +1,2103 @@
+/** @file
+  The common protected variable operation routines.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <PiPei.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/VarErrorFlag.h>
+
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HashApiLib.h>
+#include <Library/SortLib.h>
+
+#include "ProtectedVariableInternal.h"
+
+EFI_TIME             mDefaultTimeStamp       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+VARIABLE_IDENTIFIER  mUnprotectedVariables[] = {
+  {
+    METADATA_HMAC_VARIABLE_NAME,
+    &METADATA_HMAC_VARIABLE_GUID,
+    VAR_ADDED & VAR_IN_DELETED_TRANSITION
+  },
+  {
+    METADATA_HMAC_VARIABLE_NAME,
+    &METADATA_HMAC_VARIABLE_GUID,
+    VAR_ADDED
+  },
+  {
+    VAR_ERROR_FLAG_NAME,
+    &gEdkiiVarErrorFlagGuid,
+    VAR_ADDED
+  },
+  {
+    (CHAR16 *)PcdGetPtr (PcdPlatformVariableName),
+    (EFI_GUID *)PcdGetPtr (PcdPlatformVariableGuid),
+    VAR_ADDED
+  }
+};
+
+/**
+  Print variable information.
+
+  @param[in]   Data8      Pointer to data.
+  @param[in]   DataSize   Size of data.
+
+**/
+VOID
+PrintVariableData (
+  IN UINT8  *Data8,
+  IN UINTN  DataSize
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < DataSize; Index++) {
+    if (Index % 0x10 == 0) {
+      DEBUG ((DEBUG_INFO, "\n%08X:", Index));
+    }
+
+    DEBUG ((DEBUG_INFO, " %02X", *Data8++));
+  }
+
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+
+  Retrieve the context and global configuration data structure from HOB.
+
+  Once protected NV variable storage is cached and verified in PEI phase,
+  all related information are stored in a HOB which can be used by PEI variable
+  service itself and passed to SMM along with the boot flow, which can avoid
+  many duplicate works, like generating HMAC key, verifying NV variable storage,
+  etc.
+
+  The HOB can be identified by gEdkiiProtectedVariableGlobalGuid.
+
+  @param[out]   Global      Pointer to global configuration data from PEI phase.
+
+  @retval EFI_SUCCESS     The HOB was found, and Context and Global are retrieved.
+  @retval EFI_NOT_FOUND   The HOB was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobalFromHob (
+  OUT PROTECTED_VARIABLE_GLOBAL  **Global
+  )
+{
+  VOID                           *Data;
+  EFI_PEI_HOB_POINTERS           Hob;
+  EFI_HOB_MEMORY_ALLOCATION      *MemoryAllocationHob;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  EFI_PHYSICAL_ADDRESS           OldStart;
+  VARIABLE_DIGEST                *VarDig;
+  EFI_HOB_GUID_TYPE              *GuidHob;
+  UINTN                          Index;
+
+  Hob.Raw = GetFirstGuidHob (&gEdkiiProtectedVariableGlobalGuid);
+  if (Hob.Raw != NULL) {
+    Data = GET_GUID_HOB_DATA (Hob);
+  } else {
+    //
+    // Search the global from allocated memory blob.
+    //
+    Data                = NULL;
+    MemoryAllocationHob = NULL;
+
+    Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+    while (Hob.Raw != NULL) {
+      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
+      if (CompareGuid (
+            &MemoryAllocationHob->AllocDescriptor.Name,
+            &gEdkiiProtectedVariableGlobalGuid
+            ))
+      {
+        Data = (VOID *)(UINTN)
+               MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress;
+        break;
+      }
+
+      Hob.Raw = GET_NEXT_HOB (Hob);
+      Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+    }
+  }
+
+  if (Data == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  if (Global != NULL) {
+    GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
+    if (GuidHob != NULL) {
+      ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA (GuidHob);
+    } else {
+      ASSERT (GuidHob == NULL);
+    }
+
+    *Global = (PROTECTED_VARIABLE_GLOBAL *)((UINT8 *)Data);
+    //
+    // Fix pointers in the HOB (due to physical memory readiness)
+    //
+    if ((*Global)->GlobalSelf != (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global)) {
+      OldStart             = (*Global)->GlobalSelf;
+      (*Global)->ContextIn = GET_ADRS (ContextIn);
+
+      //
+      // Mark Memory caching is available
+      //
+      (*Global)->Flags.CacheReady = TRUE;
+
+      //
+      // Re-allocate new minimum cache
+      //
+      (*Global)->VariableCache = GET_ADRS (Data)
+                                 + ((*Global)->VariableCache - OldStart);
+
+      (*Global)->DigestContext = GET_ADRS (((*Global) + 1));
+      for (Index = 0; Index < UnprotectedVarIndexMax; Index++) {
+        if ((*Global)->Unprotected[Index] != VAR_INDEX_INVALID) {
+          (*Global)->Unprotected[Index] = GET_ADRS (Data)
+                                          + ((*Global)->Unprotected[Index] - OldStart);
+        }
+      }
+
+      (*Global)->LastAccessedVariable = GET_ADRS (Data)
+                                        + ((*Global)->LastAccessedVariable - OldStart);
+
+      //
+      // Fix all linked-list pointers inside VARIABLE_SIGNATURE.
+      //
+      (*Global)->VariableDigests = GET_ADRS (Data)
+                                   + ((*Global)->VariableDigests - OldStart);
+      VarDig = VAR_DIG_PTR ((*Global)->VariableDigests);
+      while (VarDig != NULL) {
+        if (VarDig->Prev != 0) {
+          VarDig->Prev = GET_ADRS (Data) + (VarDig->Prev - OldStart);
+        }
+
+        if (VarDig->Next != 0) {
+          VarDig->Next = GET_ADRS (Data) + (VarDig->Next - OldStart);
+        }
+
+        VarDig = VAR_DIG_NEXT (VarDig);
+      }
+
+      (*Global)->GlobalSelf = (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Derive HMAC key from given variable root key.
+
+  @param[in]  RootKey       Pointer to root key to derive from.
+  @param[in]  RootKeySize   Size of root key.
+  @param[out] HmacKey       Pointer to generated HMAC key.
+  @param[in]  HmacKeySize   Size of HMAC key.
+
+  @retval TRUE      The HMAC key is derived successfully.
+  @retval FALSE     Failed to generate HMAC key from given root key.
+
+**/
+BOOLEAN
+EFIAPI
+GenerateMetaDataHmacKey (
+  IN   CONST UINT8  *RootKey,
+  IN   UINTN        RootKeySize,
+  OUT  UINT8        *HmacKey,
+  IN   UINTN        HmacKeySize
+  )
+{
+  UINT8  Salt[AES_BLOCK_SIZE];
+
+  return HkdfSha256ExtractAndExpand (
+           RootKey,
+           RootKeySize,
+           Salt,
+           0,
+           (UINT8 *)METADATA_HMAC_KEY_NAME,
+           METADATA_HMAC_KEY_NAME_SIZE,
+           HmacKey,
+           HmacKeySize
+           );
+}
+
+/**
+
+  Return the size of variable MetaDataHmacVar.
+
+  @param[in] AuthFlag         Auth-variable indicator.
+
+  @retval size of variable MetaDataHmacVar.
+
+**/
+UINTN
+GetMetaDataHmacVarSize (
+  IN      BOOLEAN  AuthFlag
+  )
+{
+  UINTN  Size;
+
+  if (AuthFlag) {
+    Size = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+  } else {
+    Size = sizeof (VARIABLE_HEADER);
+  }
+
+  Size += METADATA_HMAC_VARIABLE_NAME_SIZE;
+  Size += GET_PAD_SIZE (Size);
+  Size += METADATA_HMAC_SIZE;
+  Size += GET_PAD_SIZE (Size);
+
+  return Size;
+}
+
+/**
+
+  Digests the given variable data and updates HMAC context.
+
+  @param[in]      Context        Pointer to initialized HMAC context.
+  @param[in]      VarInfo        Pointer to variable data.
+  @param[in]      UpdateMethod   Function to run when updating variable digest.
+
+  @retval TRUE    HMAC context was updated successfully.
+  @retval FALSE   Failed to update HMAC context.
+
+**/
+STATIC
+BOOLEAN
+UpdateVariableDigestData (
+  IN  VOID                     *Context,
+  IN  PROTECTED_VARIABLE_INFO  *VarInfo,
+  IN  DIGEST_UPDATE            UpdateMethod
+  )
+{
+  VOID     *Buffer[12];
+  UINT32   BufferSize[12];
+  UINTN    Index;
+  BOOLEAN  Status;
+
+  //
+  // Empty variable is legal here (e.g. variable deletion case or write-init case).
+  //
+  if ((VarInfo == NULL) ||
+      (VarInfo->CipherData == NULL) ||
+      (VarInfo->CipherDataSize == 0))
+  {
+    return TRUE;
+  }
+
+  //
+  // HMAC (":" || VariableName)
+  //
+  Buffer[0]     = METADATA_HMAC_SEP;
+  BufferSize[0] = METADATA_HMAC_SEP_SIZE;
+
+  Buffer[1]     = VarInfo->Header.VariableName;
+  BufferSize[1] = (UINT32)VarInfo->Header.NameSize;
+
+  //
+  // HMAC (":" || VendorGuid || Attributes || DataSize)
+  //
+  Buffer[2]     = METADATA_HMAC_SEP;
+  BufferSize[2] = METADATA_HMAC_SEP_SIZE;
+
+  Buffer[3]     = VarInfo->Header.VendorGuid;
+  BufferSize[3] = sizeof (EFI_GUID);
+
+  Buffer[4]     = &VarInfo->Header.Attributes;
+  BufferSize[4] = sizeof (VarInfo->Header.Attributes);
+
+  Buffer[5]     = &VarInfo->CipherDataSize;
+  BufferSize[5] = sizeof (VarInfo->CipherDataSize);
+
+  //
+  // HMAC (":" || CipherData)
+  //
+  Buffer[6]     = METADATA_HMAC_SEP;
+  BufferSize[6] = METADATA_HMAC_SEP_SIZE;
+
+  Buffer[7]     = VarInfo->CipherData;
+  BufferSize[7] = VarInfo->CipherDataSize;
+
+  //
+  // HMAC (":" || PubKeyIndex || AuthMonotonicCount || TimeStamp)
+  //
+  Buffer[8]     = METADATA_HMAC_SEP;
+  BufferSize[8] = METADATA_HMAC_SEP_SIZE;
+
+  Buffer[9]     = &VarInfo->Header.PubKeyIndex;
+  BufferSize[9] = sizeof (VarInfo->Header.PubKeyIndex);
+
+  Buffer[10]     = &VarInfo->Header.MonotonicCount;
+  BufferSize[10] = sizeof (VarInfo->Header.MonotonicCount);
+
+  Buffer[11] = (VarInfo->Header.TimeStamp != NULL) ?
+               VarInfo->Header.TimeStamp : &mDefaultTimeStamp;
+  BufferSize[11] = sizeof (EFI_TIME);
+
+  for (Index = 0; Index < ARRAY_SIZE (Buffer); ++Index) {
+    Status = UpdateMethod (Context, Buffer[Index], BufferSize[Index]);
+    if (!Status) {
+      ASSERT (FALSE);
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+
+  Digests the given variable data and updates HMAC context.
+
+  @param[in]      Context   Pointer to initialized HMAC context.
+  @param[in]      VarInfo   Pointer to variable data.
+
+  @retval TRUE    HMAC context was updated successfully.
+  @retval FALSE   Failed to update HMAC context.
+
+**/
+BOOLEAN
+UpdateVariableMetadataHmac (
+  IN  VOID                     *Context,
+  IN  PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  return UpdateVariableDigestData (Context, VarInfo, (DIGEST_UPDATE)HmacSha256Update);
+}
+
+/**
+
+  Get the variable digest.
+
+  @param[in]      Global        Pointer to global configuration data.
+  @param[in]      VarInfo       Pointer to verified copy of protected variables.
+  @param[in,out]  DigestValue   Pointer to variable digest value.
+
+  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
+  @retval EFI_ABORTED            An error was encountered.
+  @retval EFI_COMPROMISED_DATA   The data was compromised.
+  @retval EFI_SUCCESS            Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+GetVariableDigest (
+  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN      PROTECTED_VARIABLE_INFO    *VarInfo,
+  IN  OUT UINT8                      *DigestValue
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Context;
+
+  if ((Global == NULL) || (VarInfo == NULL) || (DigestValue == NULL)) {
+    ASSERT (Global != NULL);
+    ASSERT (VarInfo != NULL);
+    ASSERT (DigestValue != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Context = GET_BUFR (Global->DigestContext);
+  if (!HashApiInit (Context)) {
+    ASSERT (Context != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (VarInfo->CipherData == NULL) {
+    VarInfo->CipherData     = VarInfo->Header.Data;
+    VarInfo->CipherDataSize = (UINT32)VarInfo->Header.DataSize;
+  }
+
+  if (  !UpdateVariableDigestData (Context, VarInfo, (DIGEST_UPDATE)HashApiUpdate)
+     || !HashApiFinal (Context, DigestValue))
+  {
+    ASSERT (FALSE);
+    Status = EFI_ABORTED;
+  } else {
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+
+  Verify the variable digest.
+
+  @param[in]  Global      Pointer to global configuration data.
+  @param[in]  VarInfo     Pointer to verified copy of protected variables.
+  @param[in]  VarDig      Pointer to variable digest data.
+
+  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
+  @retval EFI_ABORTED            An error was encountered.
+  @retval EFI_COMPROMISED_DATA   The data was compromised.
+  @retval EFI_SUCCESS            Variable digest was successfully verified.
+
+**/
+EFI_STATUS
+VerifyVariableDigest (
+  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  PROTECTED_VARIABLE_INFO    *VarInfo,
+  IN  VARIABLE_DIGEST            *VarDig
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       NewDigest[METADATA_HMAC_SIZE];
+
+  if (Global->Flags.RecoveryMode || !VarDig->Flags.Protected) {
+    return EFI_SUCCESS;
+  }
+
+  ASSERT (VarDig->DigestSize == sizeof (NewDigest));
+
+  Status = GetVariableDigest (Global, VarInfo, NewDigest);
+  if (!EFI_ERROR (Status)) {
+    if (CompareMem (VAR_DIG_VALUE (VarDig), NewDigest, VarDig->DigestSize) != 0) {
+      Status = EFI_COMPROMISED_DATA;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Initialize variable MetaDataHmacVar.
+
+  @param[in,out]  Variable      Pointer to buffer of MetaDataHmacVar.
+  @param[in]      AuthFlag      Variable format flag.
+
+**/
+VOID
+InitMetadataHmacVariable (
+  IN  OUT VARIABLE_HEADER  *Variable,
+  IN      BOOLEAN          AuthFlag
+  )
+{
+  UINT8                          *NamePtr;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+
+  Variable->StartId    = VARIABLE_DATA;
+  Variable->State      = VAR_ADDED;
+  Variable->Reserved   = 0;
+  Variable->Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT;
+
+  if (AuthFlag) {
+    AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+    AuthVariable->NameSize       = METADATA_HMAC_VARIABLE_NAME_SIZE;
+    AuthVariable->DataSize       = METADATA_HMAC_SIZE;
+    AuthVariable->PubKeyIndex    = 0;
+    AuthVariable->MonotonicCount = 0;
+
+    ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
+    CopyMem (&AuthVariable->VendorGuid, &METADATA_HMAC_VARIABLE_GUID, sizeof (EFI_GUID));
+
+    NamePtr = (UINT8 *)AuthVariable + sizeof (AUTHENTICATED_VARIABLE_HEADER);
+  } else {
+    Variable->NameSize = METADATA_HMAC_VARIABLE_NAME_SIZE;
+    Variable->DataSize = METADATA_HMAC_SIZE;
+
+    CopyMem (&Variable->VendorGuid, &METADATA_HMAC_VARIABLE_GUID, sizeof (EFI_GUID));
+
+    NamePtr = (UINT8 *)Variable + sizeof (VARIABLE_HEADER);
+  }
+
+  CopyMem (NamePtr, METADATA_HMAC_VARIABLE_NAME, METADATA_HMAC_VARIABLE_NAME_SIZE);
+}
+
+/**
+  Re-calculate HMAC based on new variable data and re-generate MetaDataHmacVar.
+
+  @param[in]      Global          Pointer to global configuration data.
+  @param[in]      NewVarInfo      Pointer to buffer of new variable data.
+  @param[in,out]  NewHmacVarInfo  Pointer to buffer of new MetaDataHmacVar.
+
+  @return EFI_SUCCESS           The HMAC value was updated successfully.
+  @return EFI_ABORTED           Failed to calculate the HMAC value.
+  @return EFI_OUT_OF_RESOURCES  Not enough resource to calculate HMC value.
+  @return EFI_NOT_FOUND         The MetaDataHmacVar was not found in storage.
+
+**/
+EFI_STATUS
+RefreshVariableMetadataHmac (
+  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN      PROTECTED_VARIABLE_INFO    *NewVarInfo,
+  IN  OUT PROTECTED_VARIABLE_INFO    *NewHmacVarInfo
+  )
+{
+  EFI_STATUS                     Status;
+  VOID                           *Context;
+  UINT32                         Counter;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+  PROTECTED_VARIABLE_INFO        CurrHmacVarInfo;
+  UINT8                          *HmacValue;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  VARIABLE_DIGEST                *VarDig;
+  VARIABLE_DIGEST                *HmacVarDig;
+
+  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+  ZeroMem ((VOID *)&CurrHmacVarInfo, sizeof (CurrHmacVarInfo));
+
+  Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Counter  += 1;
+  ContextIn = GET_CNTX (Global);
+
+  //
+  // Delete current MetaDataHmacVariable first, if any.
+  //
+  if (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID) {
+    HmacVarDig = VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded]);
+
+    CurrHmacVarInfo.Header.NameSize     = HmacVarDig->NameSize;
+    CurrHmacVarInfo.Header.VariableName = VAR_DIG_NAME (HmacVarDig);
+    CurrHmacVarInfo.Header.VendorGuid   = VAR_DIG_GUID (HmacVarDig);
+
+    CurrHmacVarInfo.Buffer     = VAR_HDR_PTR (HmacVarDig->CacheIndex);
+    CurrHmacVarInfo.StoreIndex = HmacVarDig->StoreIndex;
+    CurrHmacVarInfo.Flags.Auth = HmacVarDig->Flags.Auth;
+    //
+    // Force marking current MetaDataHmacVariable as VAR_IN_DELETED_TRANSITION.
+    //
+    CurrHmacVarInfo.Buffer->State &= VAR_IN_DELETED_TRANSITION;
+    HmacVarDig->State             &= VAR_IN_DELETED_TRANSITION;
+    Status                         = ContextIn->UpdateVariableStore (
+                                                  &CurrHmacVarInfo,
+                                                  OFFSET_OF (VARIABLE_HEADER, State),
+                                                  sizeof (CurrHmacVarInfo.Buffer->State),
+                                                  &CurrHmacVarInfo.Buffer->State
+                                                  );
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+  } else if (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID) {
+    HmacVarDig = VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel]);
+  } else {
+    //
+    // No MetaDataHmacVar. Allocate space to cache its value.
+    //
+    HmacVarDig = CreateVariableDigestNode (
+                   METADATA_HMAC_VARIABLE_NAME,
+                   &METADATA_HMAC_VARIABLE_GUID,
+                   METADATA_HMAC_VARIABLE_NAME_SIZE,
+                   METADATA_HMAC_SIZE,
+                   Global->Flags.Auth,
+                   Global
+                   );
+    if (HmacVarDig == NULL) {
+      ASSERT (HmacVarDig != NULL);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    HmacVarDig->Flags.Protected = FALSE;
+  }
+
+  if (HmacVarDig->CacheIndex == VAR_INDEX_INVALID) {
+    HmacVarDig->CacheIndex = (GET_ADRS (Global)) + (Global->StructSize - GetMetaDataHmacVarSize (Global->Flags.Auth));
+  }
+
+  //
+  // Construct new MetaDataHmacVar.
+  //
+  if (NewHmacVarInfo == NULL) {
+    NewHmacVarInfo         = &VarInfo;
+    NewHmacVarInfo->Buffer = GET_BUFR (HmacVarDig->CacheIndex);
+  }
+
+  InitMetadataHmacVariable (NewHmacVarInfo->Buffer, Global->Flags.Auth);
+
+  NewHmacVarInfo->StoreIndex = VAR_INDEX_INVALID;     // Skip calculating offset
+  NewHmacVarInfo->Flags.Auth = Global->Flags.Auth;
+  Status                     = ContextIn->GetVariableInfo (NewHmacVarInfo);
+  ASSERT_EFI_ERROR (Status);
+  HmacValue = NewHmacVarInfo->Header.Data;
+
+  //
+  // Re-calculate HMAC for all valid variables
+  //
+  Context = HmacSha256New ();
+  if (Context == NULL) {
+    ASSERT (Context != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = EFI_ABORTED;
+  if (!HmacSha256SetKey (
+         Context,
+         Global->MetaDataHmacKey,
+         sizeof (Global->MetaDataHmacKey)
+         ))
+  {
+    ASSERT (FALSE);
+    goto Done;
+  }
+
+  //
+  // HMAC (|| hash(Var1) || hash(Var2) || ... || hash(VarN))
+  //
+  VarDig = VAR_DIG_PTR (Global->VariableDigests);
+  while (VarDig != NULL) {
+    if (VarDig->Flags.Valid && VarDig->Flags.Protected) {
+      HmacSha256Update (Context, VAR_DIG_VALUE (VarDig), VarDig->DigestSize);
+    }
+
+    VarDig = VAR_DIG_NEXT (VarDig);
+  }
+
+  //
+  // HMAC (RpmcMonotonicCounter)
+  //
+  if (!HmacSha256Update (Context, &Counter, sizeof (Counter))) {
+    ASSERT (FALSE);
+    goto Done;
+  }
+
+  if (!HmacSha256Final (Context, HmacValue)) {
+    ASSERT (FALSE);
+    goto Done;
+  }
+
+  //
+  // Update HMAC value in cache.
+  //
+  CopyMem (VAR_DIG_VALUE (HmacVarDig), HmacValue, HmacVarDig->DataSize);
+  if ((HmacVarDig->Prev == 0) && (HmacVarDig->Next == 0)) {
+    InsertVariableDigestNode (Global, HmacVarDig, NULL);
+  }
+
+  //
+  // Just one MetaDataHmacVar is needed for normal operation.
+  //
+  Global->Unprotected[IndexHmacAdded] = VAR_DIG_ADR (HmacVarDig);
+  Global->Unprotected[IndexHmacInDel] = VAR_INDEX_INVALID;
+
+  Status = EFI_SUCCESS;
+
+Done:
+  if (Context != NULL) {
+    HmacSha256Free (Context);
+  }
+
+  return Status;
+}
+
+/**
+
+  Check if a given variable is unprotected variable specified in advance
+  and return its index ID.
+
+  @param[in] Global     Pointer to global configuration data.
+  @param[in] VarInfo    Pointer to variable information data.
+
+  @retval IndexHmacInDel    Variable is MetaDataHmacVar in delete-transition state.
+  @retval IndexHmacAdded    Variable is MetaDataHmacVar in valid state.
+  @retval IndexErrorFlag    Variable is VarErrorLog.
+  @retval Others            Variable is not any known unprotected variables.
+
+**/
+UNPROTECTED_VARIABLE_INDEX
+CheckKnownUnprotectedVariable (
+  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  PROTECTED_VARIABLE_INFO    *VarInfo
+  )
+{
+  UNPROTECTED_VARIABLE_INDEX  Index;
+
+  if ((VarInfo == NULL) || (  (VarInfo->StoreIndex == VAR_INDEX_INVALID)
+                           && (  (VarInfo->Header.VariableName == NULL)
+                              || (VarInfo->Header.VendorGuid == NULL))))
+  {
+    ASSERT (VarInfo != NULL);
+    ASSERT (VarInfo->StoreIndex != VAR_INDEX_INVALID);
+    ASSERT (VarInfo->Header.VariableName != NULL);
+    ASSERT (VarInfo->Header.VendorGuid != NULL);
+    return UnprotectedVarIndexMax;
+  }
+
+  for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
+    if (  (Global->Unprotected[Index] != VAR_INDEX_INVALID)
+       && (VarInfo->StoreIndex != VAR_INDEX_INVALID))
+    {
+      if (VarInfo->StoreIndex == VAR_DIG_PTR (Global->Unprotected[Index])->StoreIndex) {
+        break;
+      }
+    } else if (IS_VARIABLE (
+                 &VarInfo->Header,
+                 mUnprotectedVariables[Index].VariableName,
+                 mUnprotectedVariables[Index].VendorGuid
+                 ) && (VarInfo->Header.State == mUnprotectedVariables[Index].State))
+    {
+      break;
+    }
+  }
+
+  return Index;
+}
+
+/**
+
+  Compare variable name and Guid
+
+  @param[in]  Name1      Name of first variable.
+  @param[in]  Name1Size  Size of first variable.
+  @param[in]  Name2      Name of second variable.
+  @param[in]  Name2Size  Size of second variable.
+  @param[in]  Guid1      Guid for first variable.
+  @param[in]  Guid2      Guid for second variable.
+
+  @retval 0         First name is identical to Second name.
+  @return others    First name is not identical to Second name.
+
+**/
+INTN
+CompareVariableNameAndGuid (
+  IN CONST CHAR16  *Name1,
+  IN UINTN         Name1Size,
+  IN CONST CHAR16  *Name2,
+  IN UINTN         Name2Size,
+  IN EFI_GUID      *Guid1,
+  IN EFI_GUID      *Guid2
+  )
+{
+  INTN  Result;
+
+  Result = StrnCmp (
+             Name1,
+             Name2,
+             MIN (Name1Size, Name2Size) / sizeof (CHAR16)
+             );
+  if (Result == 0) {
+    if (Name1Size != Name2Size) {
+      //
+      // Longer name is 'bigger' than shorter one.
+      //
+      Result = (INTN)Name1Size - (INTN)Name2Size;
+    } else {
+      //
+      // The variable name is the same. Compare the GUID.
+      //
+      Result = CompareMem ((VOID *)Guid1, (VOID *)Guid2, sizeof (EFI_GUID));
+    }
+  }
+
+  return Result;
+}
+
+/**
+
+  Compare variable digest.
+
+  @param[in]  Variable1     Pointer to first variable digest.
+  @param[in]  Variable2     Pointer to second variable digest.
+
+  @retval 0         Variables are identical.
+  @return others    Variables are not identical.
+
+**/
+INTN
+CompareVariableDigestInfo (
+  IN  VARIABLE_DIGEST  *Variable1,
+  IN  VARIABLE_DIGEST  *Variable2
+  )
+{
+  return CompareVariableNameAndGuid (
+           VAR_DIG_NAME (Variable1),
+           Variable1->NameSize,
+           VAR_DIG_NAME (Variable2),
+           Variable2->NameSize,
+           &Variable1->VendorGuid,
+           &Variable2->VendorGuid
+           );
+}
+
+/**
+
+  Move a node backward in the order controlled by SortMethod.
+
+  @param[in,out]  Node          Pointer to node to be moved.
+  @param[in]      SortMethod    Method used to compare node in list.
+
+**/
+VOID
+MoveNodeBackward (
+  IN  OUT VARIABLE_DIGEST  *Node,
+  IN      SORT_METHOD      SortMethod
+  )
+{
+  VARIABLE_DIGEST  *Curr;
+  VARIABLE_DIGEST  *Prev;
+  INTN             Result;
+
+  Curr = Node;
+  while (Curr != NULL) {
+    Prev = VAR_DIG_PREV (Curr);
+    if (Prev == NULL) {
+      Result = -1;
+    } else {
+      Result = SortMethod (Prev, Node);
+    }
+
+    //
+    // 'Result > 0' means the 'Prev' is 'bigger' than 'Node'. Continue to check
+    // previous node til a node 'smaller' than 'Node' found.
+    //
+    if (Result > 0) {
+      Curr = Prev;
+      continue;
+    }
+
+    if (Curr != Node) {
+      //
+      // Remove Node first
+      //
+      if (VAR_DIG_PREV (Node) != NULL) {
+        VAR_DIG_PREV (Node)->Next = Node->Next;
+      }
+
+      if (VAR_DIG_NEXT (Node) != NULL) {
+        VAR_DIG_NEXT (Node)->Prev = Node->Prev;
+      }
+
+      //
+      // Insert Node before Curr.
+      //
+      Node->Prev = Curr->Prev;
+      Node->Next = VAR_DIG_ADR (Curr);
+
+      if (Curr->Prev != 0) {
+        VAR_DIG_PREV (Curr)->Next = VAR_DIG_ADR (Node);
+      }
+
+      Curr->Prev = VAR_DIG_ADR (Node);
+    }
+
+    //
+    // If there're two identical variables in storage, one of them must be
+    // "in-delete-transition" state. Mark it as "deleted" anyway.
+    //
+    if (Result == 0) {
+      if (Curr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
+        Curr->State &= VAR_DELETED;
+      }
+
+      if (Prev->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
+        Prev->State &= VAR_DELETED;
+      }
+    }
+
+    break;
+  }
+}
+
+/**
+
+  Create variable digest node.
+
+  @param[in]  VariableName      Name of variable.
+  @param[in]  VendorGuid        Guid of variable.
+  @param[in]  NameSize          Size of variable name.
+  @param[in]  DataSize          Size of variable data.
+  @param[in]  AuthVar           Authenticated variable flag.
+  @param[in]  Global            Pointer to global configuration data.
+
+  @retval Ptr   Pointer to variable digest
+
+**/
+VARIABLE_DIGEST *
+CreateVariableDigestNode (
+  IN CHAR16                     *VariableName,
+  IN EFI_GUID                   *VendorGuid,
+  IN UINT16                     NameSize,
+  IN UINT32                     DataSize,
+  IN BOOLEAN                    AuthVar,
+  IN PROTECTED_VARIABLE_GLOBAL  *Global
+  )
+{
+  VARIABLE_DIGEST  *VarDig;
+  VOID             *Buffer;
+  UINTN            VarSize;
+
+  VarDig = (VARIABLE_DIGEST *)AllocateZeroPool (
+                                sizeof (VARIABLE_DIGEST) + NameSize + METADATA_HMAC_SIZE
+                                );
+  if ((VarDig == NULL) || (Global == NULL)) {
+    ASSERT (VarDig != NULL);
+    ASSERT (Global != NULL);
+    return NULL;
+  }
+
+  VarDig->DataSize        = DataSize;
+  VarDig->NameSize        = NameSize;
+  VarDig->DigestSize      = METADATA_HMAC_SIZE;
+  VarDig->State           = VAR_ADDED;
+  VarDig->Attributes      = VARIABLE_ATTRIBUTE_NV_BS_RT;
+  VarDig->Flags.Auth      = AuthVar;
+  VarDig->Flags.Valid     = TRUE;
+  VarDig->Flags.Freeable  = TRUE;
+  VarDig->Flags.Protected = PcdGetBool (PcdProtectedVariableIntegrity);
+  VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
+  VarDig->StoreIndex      = VAR_INDEX_INVALID;
+  VarDig->CacheIndex      = VAR_INDEX_INVALID;
+
+  if (Global->Flags.CacheReady == TRUE) {
+    VarSize  =  VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
+    VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+    VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+    VarSize  = HEADER_ALIGN (VarSize);
+
+    Buffer = AllocateZeroPool (VarSize);
+    if (Buffer != NULL) {
+      VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+    }
+  }
+
+  CopyMem (VAR_DIG_NAME (VarDig), VariableName, NameSize);
+  CopyMem (VAR_DIG_GUID (VarDig), VendorGuid, sizeof (EFI_GUID));
+
+  return VarDig;
+}
+
+/**
+
+  Remove variable digest node.
+
+  @param[in,out]  Global        Pointer to global configuration data.
+  @param[in,out]  VarDig        Pointer to variable digest value.
+  @param[in]      FreeResource  Flag to indicate whether to free resource.
+
+**/
+VOID
+RemoveVariableDigestNode (
+  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  OUT VARIABLE_DIGEST            *VarDig,
+  IN      BOOLEAN                    FreeResource
+  )
+{
+  VARIABLE_DIGEST  *Prev;
+  VARIABLE_DIGEST  *Next;
+
+  Prev = VAR_DIG_PREV (VarDig);
+  Next = VAR_DIG_NEXT (VarDig);
+
+  if (Global->VariableDigests == VAR_DIG_ADR (VarDig)) {
+    Global->VariableDigests = VAR_DIG_ADR (Next);
+  }
+
+  if (Prev != NULL) {
+    Prev->Next = VAR_DIG_ADR (Next);
+  }
+
+  if (Next != NULL) {
+    Next->Prev = VAR_DIG_ADR (Prev);
+  }
+
+  VarDig->Prev        = 0;
+  VarDig->Next        = 0;
+  VarDig->Flags.Valid = FALSE;
+
+  if (FreeResource && VarDig->Flags.Freeable) {
+    if ((VarDig->CacheIndex != 0) && (VarDig->CacheIndex != VAR_INDEX_INVALID)) {
+      VarDig->CacheIndex = VAR_INDEX_INVALID;
+    }
+  }
+}
+
+/**
+
+  Insert variable digest node.
+
+  @param[in,out]  Global        Pointer to global configuration data.
+  @param[in]      VarDig        Pointer to variable digest value.
+  @param[in]      SortMethod    Method for sorting.
+
+**/
+VOID
+InsertVariableDigestNode (
+  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN      VARIABLE_DIGEST            *VarDig,
+  IN      SORT_METHOD                SortMethod
+  )
+{
+  VARIABLE_DIGEST  *Curr;
+  VARIABLE_DIGEST  *Prev;
+  BOOLEAN          DoReplace;
+  INTN             Result;
+
+  if (SortMethod == NULL) {
+    SortMethod = CompareVariableDigestInfo;
+  }
+
+  DoReplace = FALSE;
+  Curr      = VAR_DIG_PTR (Global->VariableDigests);
+  if (Curr == NULL) {
+    //
+    // First one.
+    //
+    VarDig->Prev            = 0;
+    VarDig->Next            = 0;
+    Global->VariableDigests = VAR_DIG_ADR (VarDig);
+    return;
+  }
+
+  while (Curr != NULL && Curr != VarDig) {
+    Result = SortMethod (VarDig, Curr);
+
+    if (Result <= 0) {
+      ASSERT (VarDig->StoreIndex != Curr->StoreIndex);
+
+      //
+      // The same variable already in list?
+      //
+      if (Result == 0) {
+        //
+        // Keep only the same new one, unless states are different. In such
+        // situation, the one with no VAR_ADDED will be deleted.
+        //
+        if (VarDig->State >= Curr->State) {
+          DoReplace         = TRUE;
+          Curr->Flags.Valid = FALSE;    // to-be-deleted
+        } else {
+          DoReplace           = FALSE;
+          VarDig->Flags.Valid = FALSE;  // to-be-deleted
+        }
+      }
+
+      //
+      // Put VarDig before Curr
+      //
+      VarDig->Next = VAR_DIG_ADR (Curr);
+      VarDig->Prev = Curr->Prev;
+
+      if (VAR_DIG_PREV (Curr) != NULL) {
+        VAR_DIG_PREV (Curr)->Next = VAR_DIG_ADR (VarDig);
+      }
+
+      Curr->Prev = VAR_DIG_ADR (VarDig);
+
+      if (DoReplace) {
+        RemoveVariableDigestNode (Global, Curr, TRUE);
+      }
+
+      break;
+    }
+
+    Prev = Curr;
+    Curr = VAR_DIG_NEXT (Curr);
+    if (Curr == NULL) {
+      Prev->Next = VAR_DIG_ADR (VarDig);
+
+      VarDig->Prev = VAR_DIG_ADR (Prev);
+      VarDig->Next = 0;
+    }
+  }
+
+  //
+  // Update the head node if necessary.
+  //
+  if (VAR_DIG_PTR (VarDig->Prev) == NULL) {
+    Global->VariableDigests = VAR_DIG_ADR (VarDig);
+  }
+}
+
+/**
+
+  Find the specified variable digest
+
+  @param[in]  Global        Pointer to global configuration data.
+  @param[in]  VarInfo       Pointer to variable data.
+  @param[in]  FindNext      Flag to continue looking for variable.
+
+**/
+VARIABLE_DIGEST *
+FindVariableInternal (
+  IN PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN PROTECTED_VARIABLE_INFO    *VarInfo,
+  IN BOOLEAN                    FindNext
+  )
+{
+  VARIABLE_DIGEST  *VarDig;
+  VARIABLE_DIGEST  *Found;
+  VARIABLE_DIGEST  *FirstStoreIndexVar;
+  BOOLEAN          ByIndex;
+  INTN             FwdOrBwd;
+
+  //
+  // If VarInfo->StoreIndex is valid, use it to find the variable. Otherwise,
+  // use the variable name and guid instead, if given. If no clue at all, return
+  // the variable with lowest StoreIndex.
+  //
+  if (  (VarInfo->StoreIndex != VAR_INDEX_INVALID)
+     || (VarInfo->Header.VariableName == NULL)
+     || (VarInfo->Header.VendorGuid == NULL))
+  {
+    ByIndex = TRUE;
+  } else {
+    ByIndex = FALSE;
+  }
+
+  Found              = NULL;
+  VarDig             = VAR_DIG_PTR (Global->VariableDigests);
+  FirstStoreIndexVar = VarDig;
+  FwdOrBwd           = 1;
+
+  //
+  // Discover variable with first/smallest store index
+  //
+  while (VarDig != NULL) {
+    if (VarDig->StoreIndex < FirstStoreIndexVar->StoreIndex) {
+      FirstStoreIndexVar = VAR_DIG_PTR (VarDig);
+    }
+
+    VarDig = VAR_DIG_NEXT (VarDig);
+  }
+
+  //
+  // Input variable is NULL than return first variable
+  // with smallest store index from the variable digest list.
+  //
+  if (((VarInfo->Header.VariableName == NULL) ||
+       (VarInfo->Header.VendorGuid == NULL)) &&
+      (ByIndex == FALSE))
+  {
+    return FirstStoreIndexVar;
+  }
+
+  //
+  // Start with first entry
+  //
+  VarDig = VAR_DIG_PTR (Global->VariableDigests);
+  while (VarDig != NULL) {
+    if (ByIndex) {
+      if (FindNext) {
+        if (VarDig->StoreIndex == VarInfo->StoreIndex) {
+          Found = VarDig = VAR_DIG_NEXT (VarDig);
+          break;
+        }
+      } else if (VarDig->StoreIndex == VarInfo->StoreIndex) {
+        Found = VarDig;
+        break;
+      }
+    } else {
+      //
+      // Match given variable name and vendor guid.
+      //
+      if (IS_VARIABLE (&VarInfo->Header, VAR_DIG_NAME (VarDig), VAR_DIG_GUID (VarDig))) {
+        Found = (FindNext) ? VAR_DIG_NEXT (VarDig) : VarDig;
+        break;
+      }
+    }
+
+    VarDig = (FwdOrBwd > 0) ? VAR_DIG_NEXT (VarDig) : VAR_DIG_PREV (VarDig);
+    if (VarDig == NULL) {
+    }
+  }
+
+  return Found;
+}
+
+/**
+
+  Synchronize the RPMC counters
+
+  @param[in]  Global      Pointer to global configuration data.
+  @param[in]  VarInfo     Pointer to variable data.
+  @param[in]  FindNext    Flag to continue looking for variable.
+
+  @retval EFI_SUCCESS     Successfully sync RPMC counters.
+  @return others          Failed to sync RPMC counters.
+
+**/
+EFI_STATUS
+SyncRpmcCounter (
+  VOID
+  )
+{
+  UINT32      Counter1;
+  UINT32      Counter2;
+  EFI_STATUS  Status;
+
+  //
+  // Sync RPMC1 & RPMC2.
+  //
+  Status = RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  while (Counter1 < Counter2) {
+    Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+
+    ++Counter1;
+  }
+
+  while (Counter2 < Counter1) {
+    Status = IncrementMonotonicCounter (RPMC_COUNTER_2);
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+
+    ++Counter2;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  An alternative version of ProtectedVariableLibGetData to get plain data from
+  given variable, if encrypted.
+
+  @param[in]          Global        Pointer to global configuration data.
+  @param[in,out]      VarInfo       Pointer to structure containing variable
+                                    information. VarInfo->Header.Data must point
+                                    to the original variable data.
+
+  @retval EFI_SUCCESS               Found the specified variable.
+  @retval EFI_INVALID_PARAMETER     VarInfo is NULL or both VarInfo->Buffer and
+                                    VarInfo->Offset are invalid.
+  @retval EFI_NOT_FOUND             The specified variable could not be found.
+
+**/
+STATIC
+EFI_STATUS
+ProtectedVariableLibGetDataInternal (
+  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  OUT PROTECTED_VARIABLE_INFO    *VarInfo
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  VOID                           *Buffer;
+  UINTN                          BufferSize;
+
+  if ((Global == NULL) || (VarInfo == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ContextIn = GET_CNTX (Global);
+
+  //
+  // Check if the data has been decrypted or not.
+  //
+  BufferSize              = VarInfo->PlainDataSize;
+  VarInfo->CipherData     = NULL;
+  VarInfo->CipherDataSize = 0;
+  VarInfo->PlainData      = NULL;
+  VarInfo->PlainDataSize  = 0;
+  Status                  = GetCipherDataInfo (VarInfo);
+
+  if ((Status == EFI_UNSUPPORTED) || (Status == EFI_NOT_FOUND)) {
+    VarInfo->Flags.DecryptInPlace = TRUE;
+    VarInfo->PlainDataSize        = (UINT32)VarInfo->Header.DataSize;
+    VarInfo->PlainData            = VarInfo->Header.Data;
+    VarInfo->CipherDataType       = 0;
+    VarInfo->CipherHeaderSize     = 0;
+    Status                        = EFI_SUCCESS;
+  } else if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // Don't do decryption if the caller provided buffer is too small
+  // Simply return the real Plain Data Size via VarInfo->PlainDataSize
+  //
+  if (BufferSize < VarInfo->PlainDataSize) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  //
+  // If the variable data is cipher data, decrypt it inplace if possible.
+  //
+  if ((VarInfo->PlainData == NULL) && (VarInfo->CipherData != NULL)) {
+    VarInfo->Key     = Global->RootKey;
+    VarInfo->KeySize = sizeof (Global->RootKey);
+
+    switch (ContextIn->VariableServiceUser) {
+      case FromPeiModule:
+        VarInfo->Flags.DecryptInPlace = FALSE;
+        //
+        // In PEI VariableCache holds Cipher header + Cipher data
+        // Do not override Cipher header data during decrypt operation
+        //
+        VarInfo->PlainData = GET_BUFR (Global->VariableCache + VarInfo->CipherHeaderSize);
+
+        Status = DecryptVariable (VarInfo);
+        if (Status == EFI_UNSUPPORTED) {
+          VarInfo->PlainData        = VarInfo->Header.Data;
+          VarInfo->PlainDataSize    = (UINT32)VarInfo->Header.DataSize;
+          VarInfo->CipherDataType   = 0;
+          VarInfo->CipherHeaderSize = 0;
+
+          Status = EFI_SUCCESS;
+        }
+
+        break;
+
+      case FromSmmModule:
+        VarInfo->Flags.DecryptInPlace = FALSE;
+        VarInfo->PlainData            = GET_BUFR (Global->VariableCache);
+
+        Status = DecryptVariable (VarInfo);
+        if (Status == EFI_UNSUPPORTED) {
+          VarInfo->PlainData        = VarInfo->Header.Data;
+          VarInfo->PlainDataSize    = (UINT32)VarInfo->Header.DataSize;
+          VarInfo->CipherDataType   = 0;
+          VarInfo->CipherHeaderSize = 0;
+
+          Status = EFI_SUCCESS;
+        }
+
+        break;
+
+      case FromBootServiceModule:
+      case FromRuntimeModule:
+        //
+        // The SMM passes back only decrypted data. We re-use the original cipher
+        // data buffer to keep the plain data along with the cipher header.
+        //
+        VarInfo->Flags.DecryptInPlace = TRUE;
+        Buffer                        = (VOID *)((UINTN)VarInfo->CipherData + VarInfo->CipherHeaderSize);
+        BufferSize                    = VarInfo->PlainDataSize;
+        Status                        = ContextIn->FindVariableSmm (
+                                                     VarInfo->Header.VariableName,
+                                                     VarInfo->Header.VendorGuid,
+                                                     &VarInfo->Header.Attributes,
+                                                     &BufferSize,
+                                                     Buffer
+                                                     );
+        if (!EFI_ERROR (Status)) {
+          //
+          // Flag the payload as plain data to avoid re-decrypting.
+          //
+          VarInfo->CipherDataType = ENC_TYPE_NULL;
+          VarInfo->PlainDataSize  = (UINT32)BufferSize;
+          VarInfo->PlainData      = Buffer;
+
+          Status = SetCipherDataInfo (VarInfo);
+          if (Status == EFI_UNSUPPORTED) {
+            Status = EFI_SUCCESS;
+          }
+        }
+
+        break;
+
+      default:
+        Status = EFI_UNSUPPORTED;
+        break;
+    }
+
+    VarInfo->CipherData     = NULL;
+    VarInfo->CipherDataSize = 0;
+  }
+
+  return Status;
+}
+
+/**
+
+  An alternative version of ProtectedVariableLibGetData to get plain data, if
+  encrypted, from given variable, for different use cases.
+
+  @param[in,out]      VarInfo     Pointer to structure containing variable information.
+
+  @retval EFI_SUCCESS               Found the specified variable.
+  @retval EFI_INVALID_PARAMETER     VarInfo is NULL or both VarInfo->Buffer and
+                                    VarInfo->Offset are invalid.
+  @retval EFI_NOT_FOUND             The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByInfo (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  EFI_STATUS                 Status;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VOID                       **Buffer;
+  UINT32                     BufferSize;
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // Save the output data buffer because below call
+  // call will use this struct field internally.
+  //
+  Buffer     = VarInfo->PlainData;
+  BufferSize = VarInfo->PlainDataSize;
+
+  Status = ProtectedVariableLibGetDataInternal (Global, VarInfo);
+  if (EFI_ERROR (Status) || ((BufferSize) < VarInfo->PlainDataSize)) {
+    //
+    // Return with caller provided buffer with zero DataSize
+    //
+    VarInfo->PlainData = Buffer;
+    return Status;
+  }
+
+  //
+  // Copy Plain data to ouput data buffer
+  //
+  CopyMem (Buffer, VarInfo->PlainData, VarInfo->PlainDataSize);
+  VarInfo->PlainData = Buffer;
+
+  return Status;
+}
+
+/**
+
+  Retrieve plain data, if encrypted, of given variable.
+
+  If variable encryption is employed, this function will initiate a SMM request
+  to get the plain data. Due to security consideration, the decryption can only
+  be done in SMM environment.
+
+  @param[in]      Variable           Pointer to header of a Variable.
+  @param[in,out]  Data               Pointer to plain data of the given variable.
+  @param[in,out]  DataSize           Size of data returned or data buffer needed.
+  @param[in]      AuthFlag           Auth-variable indicator.
+
+  @retval EFI_SUCCESS                Found the specified variable.
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.
+  @retval EFI_NOT_FOUND              The specified variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL       If *DataSize is smaller than needed.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByBuffer (
+  IN      VARIABLE_HEADER  *Variable,
+  IN  OUT VOID             *Data,
+  IN  OUT UINT32           *DataSize,
+  IN      BOOLEAN          AuthFlag
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
+  VOID                           *Buffer;
+
+  if ((Variable == NULL) || (DataSize == NULL)) {
+    ASSERT (Variable != NULL);
+    ASSERT (DataSize != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+
+  VarInfo.Buffer        = Variable;
+  VarInfo.Flags.Auth    = AuthFlag;
+  VarInfo.PlainDataSize = *DataSize;
+
+  if (VarInfo.Flags.Auth == TRUE) {
+    AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
+
+    VarInfo.Header.VariableName = (CHAR16 *)((UINTN)Variable + sizeof (AUTHENTICATED_VARIABLE_HEADER));
+    VarInfo.Header.NameSize     = AuthVariable->NameSize;
+    VarInfo.Header.VendorGuid   = &AuthVariable->VendorGuid;
+    VarInfo.Header.Attributes   = AuthVariable->Attributes;
+    VarInfo.Header.DataSize     = AuthVariable->DataSize;
+  } else {
+    VarInfo.Header.VariableName = (CHAR16 *)((UINTN)Variable + sizeof (VARIABLE_HEADER));
+    VarInfo.Header.NameSize     = Variable->NameSize;
+    VarInfo.Header.VendorGuid   = &Variable->VendorGuid;
+    VarInfo.Header.Attributes   = Variable->Attributes;
+    VarInfo.Header.DataSize     = Variable->DataSize;
+  }
+
+  Buffer              = VARIABLE_NAME (VarInfo.Buffer, VarInfo.Flags.Auth);
+  Buffer              = GET_BUFR (GET_ADRS (Buffer) + VarInfo.Header.NameSize);
+  Buffer              = GET_BUFR (GET_ADRS (Buffer) + GET_PAD_SIZE (VarInfo.Header.NameSize));
+  VarInfo.Header.Data = Buffer;
+
+  Status    = ProtectedVariableLibGetDataInternal (Global, &VarInfo);
+  *DataSize = VarInfo.PlainDataSize;
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize);
+
+  return Status;
+}
+
+/**
+  This service retrieves a variable's value using its name and GUID.
+
+  Read the specified variable from the UEFI variable store. If the Data
+  buffer is too small to hold the contents of the variable, the error
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+  size to obtain the data.
+
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
+                                VariableGuid and VariableName must be unique.
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
+                                On return, points to the size of the data returned in Data.
+  @param  Data                  Points to the buffer which will hold the returned variable value.
+                                May be NULL with a zero DataSize in order to determine the size of the buffer needed.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable was be found.
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
+                                DataSize is updated with the size required for
+                                the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetByName (
+  IN      CONST  CHAR16    *VariableName,
+  IN      CONST  EFI_GUID  *VariableGuid,
+  OUT UINT32               *Attributes,
+  IN  OUT UINTN            *DataSize,
+  OUT VOID                 *Data OPTIONAL
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  VARIABLE_DIGEST                *VarDig;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+  EFI_TIME                       TimeStamp;
+  VOID                           *DataBuffer;
+
+  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
+    ASSERT (VariableName != NULL);
+    ASSERT (VariableGuid != NULL);
+    ASSERT (DataSize != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetProtectedVariableGlobal (&Global);
+
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  ContextIn = GET_CNTX (Global);
+
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+  VarInfo.StoreIndex          = VAR_INDEX_INVALID;
+  VarInfo.Header.VariableName = (CHAR16 *)VariableName;
+  VarInfo.Header.NameSize     = StrSize (VariableName);
+  VarInfo.Header.VendorGuid   = (EFI_GUID *)VariableGuid;
+
+  VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+  if (VarDig == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  if (Attributes != NULL) {
+    *Attributes = VarDig->Attributes;
+  }
+
+  if ((Data == NULL) || (*DataSize < VarDig->PlainDataSize)) {
+    *DataSize = VarDig->PlainDataSize;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  VarInfo.Flags.Auth      = VarDig->Flags.Auth;
+  VarInfo.Flags.Protected = VarDig->Flags.Protected;
+
+  //
+  // Verify digest before copy the data back, if the variable is not in cache.
+  //
+  if (VarDig->CacheIndex != VAR_INDEX_INVALID) {
+    VarInfo.Header.VariableName = NULL;
+    VarInfo.Header.VendorGuid   = NULL;
+    VarInfo.Buffer              = GET_BUFR (VarDig->CacheIndex);
+
+    Status = ContextIn->GetVariableInfo (&VarInfo);
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    //
+    // A buffer for at least one variable data (<=PcdMax(Auth)VariableSize)
+    // must be reserved in advance.
+    //
+    ASSERT (
+      Global->VariableCache != 0
+           && Global->VariableCacheSize >= VarDig->DataSize
+      );
+    DataBuffer = GET_BUFR (Global->VariableCache);
+    //
+    // Note name and GUID are already there.
+    //
+    VarInfo.StoreIndex = VarDig->StoreIndex;
+
+    VarInfo.Header.VariableName = NULL; // Prevent name from being retrieved again.
+    VarInfo.Header.NameSize     = 0;
+    VarInfo.Header.VendorGuid   = NULL; // Prevent guid from being retrieved again.
+    VarInfo.Header.TimeStamp    = &TimeStamp;
+    VarInfo.Header.Data         = DataBuffer;
+    VarInfo.Header.DataSize     = VarDig->DataSize;
+
+    //
+    // Get detailed information about the variable.
+    //
+    Status = ContextIn->GetVariableInfo (&VarInfo);
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // The variable must be validated its digest value to avoid TOCTOU, if it's
+    // not been cached yet.
+    //
+    VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+    VarInfo.Header.NameSize     = VarDig->NameSize;
+    VarInfo.Header.VendorGuid   = &VarDig->VendorGuid;
+    Status                      = VerifyVariableDigest (Global, &VarInfo, VarDig);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  VarInfo.PlainDataSize = (UINT32)*DataSize;
+
+  //
+  // Decrypt the data, if necessary.
+  //
+  Status    = ProtectedVariableLibGetDataInternal (Global, &VarInfo);
+  *DataSize = VarInfo.PlainDataSize;
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: %d Exit(). VariableName = %s, VariableGuid = 0x%g, DataSize = 0x%X, Data Buffer = 0x%lX, Status = %r\n",
+      __FUNCTION__,
+      __LINE__,
+      VariableName,
+      VariableGuid,
+      *DataSize,
+      Data,
+      Status
+      ));
+    return Status;
+  }
+
+  CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize);
+
+  return Status;
+}
+
+/**
+
+  This function is used to enumerate the variables managed by current
+  ProtectedVariableLib.
+
+  If the VarInfo->StoreIndex is invalid (VAR_INDEX_INVALID), the first variable
+  with the smallest StoreIndex will be returned. Otherwise, the variable with
+  StoreIndex just after than the VarInfo->StoreIndex will be returned.
+
+  @param[in,out]      VarInfo     Pointer to structure containing variable information.
+
+  @retval EFI_SUCCESS               Found the specified variable.
+  @retval EFI_INVALID_PARAMETER     VarInfo is NULL.
+  @retval EFI_NOT_FOUND             The specified variable could not be found.
+
+**/
+STATIC
+EFI_STATUS
+GetNextVariableInternal (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  EFI_STATUS                 Status;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VARIABLE_DIGEST            *Found;
+
+  if (VarInfo == NULL) {
+    ASSERT (VarInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Found = FindVariableInternal (Global, VarInfo, TRUE);
+  if (Found == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Return all cached data.
+  //
+  VarInfo->Header.VariableName = VAR_DIG_NAME (Found);
+  VarInfo->Header.VendorGuid   = VAR_DIG_GUID (Found);
+  VarInfo->Header.NameSize     = Found->NameSize;
+  VarInfo->Header.DataSize     = Found->DataSize;
+  VarInfo->Header.Attributes   = Found->Attributes;
+
+  VarInfo->PlainDataSize = Found->PlainDataSize;
+  VarInfo->StoreIndex    = Found->StoreIndex;
+  if (Found->CacheIndex != VAR_INDEX_INVALID) {
+    VarInfo->Buffer = GET_BUFR (Found->CacheIndex);
+  }
+
+  VarInfo->Flags.Auth = Found->Flags.Auth;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Find the request variable.
+
+  @param[in, out]  VarInfo      Pointer to variable data.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_INVALID_PARAMETER Variable info is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFind (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  EFI_STATUS                 Status;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VARIABLE_DIGEST            *Found;
+
+  if (VarInfo == NULL) {
+    ASSERT (VarInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Found = FindVariableInternal (Global, VarInfo, FALSE);
+  if (Found == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Return all cached data.
+  //
+  VarInfo->Header.VariableName = VAR_DIG_NAME (Found);
+  VarInfo->Header.VendorGuid   = VAR_DIG_GUID (Found);
+  VarInfo->Header.NameSize     = Found->NameSize;
+  VarInfo->Header.DataSize     = Found->DataSize;
+  VarInfo->Header.Attributes   = Found->Attributes;
+
+  VarInfo->PlainDataSize = Found->PlainDataSize;
+  VarInfo->StoreIndex    = Found->StoreIndex;
+  if (Found->CacheIndex != VAR_INDEX_INVALID) {
+    VarInfo->Buffer = GET_BUFR (Found->CacheIndex);
+  }
+
+  VarInfo->Flags.Auth = Found->Flags.Auth;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Return the next variable name and GUID.
+
+  This function is called multiple times to retrieve the VariableName
+  and VariableGuid of all variables currently available in the system.
+  On each call, the previous results are passed into the interface,
+  and, on return, the interface returns the data for the next
+  interface. When the entire variable list has been returned,
+  EFI_NOT_FOUND is returned.
+
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
+                            On return, the size of the variable name buffer.
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
+                            On return, points to the next variable's null-terminated name string.
+  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID.
+                            On return, a pointer to the next variable's GUID.
+
+  @retval EFI_SUCCESS           The variable was read successfully.
+  @retval EFI_NOT_FOUND         The variable could not be found.
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
+                                data. VariableNameSize is updated with the size
+                                required for the specified variable.
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+                                VariableNameSize is NULL.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNext (
+  IN OUT UINTN     *VariableNameSize,
+  IN OUT CHAR16    *VariableName,
+  IN OUT EFI_GUID  *VariableGuid
+  )
+{
+  EFI_STATUS                 Status;
+  PROTECTED_VARIABLE_INFO    VarInfo;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VARIABLE_DIGEST            *VarDig;
+  UINTN                      Size;
+
+  if ((VariableNameSize == NULL) || (VariableName == NULL) || (VariableGuid == NULL)) {
+    ASSERT (VariableNameSize != NULL);
+    ASSERT (VariableName != NULL);
+    ASSERT (VariableGuid != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SetMem (&VarInfo, sizeof (VarInfo), 0);
+  Size = StrSize (VariableName);
+
+  if (Size <= 2) {
+    VarDig = VAR_DIG_PTR (Global->VariableDigests);
+  } else {
+    VarInfo.Header.VariableName = VariableName;
+    VarInfo.Header.NameSize     = Size;
+    VarInfo.Header.VendorGuid   = VariableGuid;
+
+    VarInfo.StoreIndex = VAR_INDEX_INVALID;
+
+    VarDig = FindVariableInternal (Global, &VarInfo, TRUE);
+  }
+
+  if (VarDig == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  if (VarDig->NameSize > *VariableNameSize) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  CopyMem (VariableName, VAR_DIG_NAME (VarDig), VarDig->NameSize);
+  CopyGuid (VariableGuid, &VarDig->VendorGuid);
+  *VariableNameSize = VarInfo.Header.NameSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Return the next variable name and GUID.
+
+  @param[in, out]  VarInfo        Pointer to variable data.
+
+  @retval EFI_SUCCESS             The variable was read successfully.
+  @retval EFI_INVALID_PARAMETER   VarInfo is NULL.
+  @retval EFI_NOT_FOUND           The specified variable could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibFindNextEx (
+  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
+  )
+{
+  return GetNextVariableInternal (VarInfo);
+}
+
+/**
+
+  Return the max count of a variable.
+
+  @return   max count of a variable.
+
+**/
+UINTN
+ProtectedVariableLibGetMaxVariablesCount (
+  VOID
+  )
+{
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  PROTECTED_VARIABLE_INFO    VarInfo;
+  VARIABLE_DIGEST            *VarDig;
+  EFI_STATUS                 Status;
+  UINTN                      Count;
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return 0;
+  }
+
+  Count = 0;
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+
+  //
+  // Start with first entry
+  //
+  VarDig                      = VAR_DIG_PTR (Global->VariableDigests);
+  VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+  VarInfo.Header.VendorGuid   = VAR_DIG_GUID (VarDig);
+  VarInfo.StoreIndex          = VarDig->StoreIndex;
+
+  do {
+    VarInfo.Buffer = NULL;
+    Status         = ProtectedVariableLibFindNextEx (&VarInfo);
+    if (EFI_ERROR (Status)) {
+      return Count;
+    }
+
+    Count++;
+  } while (TRUE);
+}
+
+/**
+  The function is called by PerformQuickSort to sort.
+
+  @param[in] Left            The pointer to first buffer.
+  @param[in] Right           The pointer to second buffer.
+
+  @retval 0                  Buffer1 equal to Buffer2.
+  @return < 0                Buffer1 is less than Buffer2.
+  @return > 0                Buffer1 is greater than Buffer2.
+
+**/
+INTN
+EFIAPI
+CompareStoreIndex (
+  IN CONST VOID  *Left,
+  IN CONST VOID  *Right
+  )
+{
+  EFI_PHYSICAL_ADDRESS  StoreIndex1;
+  EFI_PHYSICAL_ADDRESS  StoreIndex2;
+
+  StoreIndex1 = (*(EFI_PHYSICAL_ADDRESS *)Left);
+  StoreIndex2 = (*(EFI_PHYSICAL_ADDRESS *)Right);
+
+  if (StoreIndex1 == StoreIndex2) {
+    return (0);
+  }
+
+  if (StoreIndex1 < StoreIndex2) {
+    return (-1);
+  }
+
+  return (1);
+}
+
+/**
+  Refresh variable information changed by variable service.
+
+  @param Buffer           Pointer to a pointer of buffer.
+  @param NumElements      Pointer to number of elements in list.
+
+
+  @return EFI_SUCCESS     Successfully retrieved sorted list.
+  @return others          Unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibGetSortedList (
+  IN  OUT  EFI_PHYSICAL_ADDRESS  **Buffer,
+  IN  OUT  UINTN                 *NumElements
+  )
+{
+  EFI_STATUS                 Status;
+  UINTN                      Count;
+  UINTN                      StoreIndexTableSize;
+  EFI_PHYSICAL_ADDRESS       *StoreIndexTable;
+  PROTECTED_VARIABLE_INFO    VarInfo;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VARIABLE_DIGEST            *VarDig;
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Count = 0;
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+  StoreIndexTableSize = ProtectedVariableLibGetMaxVariablesCount ();
+  StoreIndexTable     = AllocateZeroPool (sizeof (EFI_PHYSICAL_ADDRESS) * StoreIndexTableSize);
+
+  //
+  // Start with first entry
+  //
+  VarDig                      = VAR_DIG_PTR (Global->VariableDigests);
+  VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+  VarInfo.Header.VendorGuid   = VAR_DIG_GUID (VarDig);
+  VarInfo.StoreIndex          = VarDig->StoreIndex;
+  StoreIndexTable[Count]      = VarInfo.StoreIndex;
+  Count++;
+
+  //
+  // Populate the un-sorted table
+  //
+  do {
+    VarInfo.Buffer = NULL;
+    Status         = ProtectedVariableLibFindNextEx (&VarInfo);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    StoreIndexTable[Count] = VarInfo.StoreIndex;
+    Count++;
+  } while (TRUE);
+
+  PerformQuickSort (
+    StoreIndexTable,
+    Count,
+    sizeof (EFI_PHYSICAL_ADDRESS),
+    (SORT_COMPARE)CompareStoreIndex
+    );
+
+  *Buffer      = StoreIndexTable;
+  *NumElements = Count;
+
+  return EFI_SUCCESS;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
new file mode 100644
index 000000000000..94df21eacf25
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
@@ -0,0 +1,163 @@
+/** @file
+  Implemention of ProtectedVariableLib for SMM variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Library/UefiBootServicesTableLib.h"
+#include "Library/MemoryAllocationLib.h"
+
+#include "ProtectedVariableInternal.h"
+
+PROTECTED_VARIABLE_CONTEXT_IN  mVariableContextIn = {
+  PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
+  sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
+  0,
+  FromSmmModule,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+PROTECTED_VARIABLE_GLOBAL  mProtectedVariableGlobal = {
+  PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
+  sizeof (PROTECTED_VARIABLE_GLOBAL),
+  { 0 },
+  { 0 },
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  { 0,                                          0,  0 },
+  0,
+  0,
+  { 0,                                          0,  0, 0, 0, 0}
+};
+
+/**
+  Fix incorrect state of MetaDataHmacVariable before any variable update.
+
+  @param[in]   Event    The event that occurred
+  @param[in]   Context  For EFI compatibility.  Not used.
+
+**/
+VOID
+EFIAPI
+VariableWriteProtocolCallback (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Fix incorrect state of MetaDataHmacVariable before any variable update.
+  // This has to be done here due to the fact that this operation needs to
+  // update NV storage but the FVB and FTW protocol might not be ready during
+  // ProtectedVariableLibInitialize().
+  //
+  Status = FixupHmacVariable ();
+  ASSERT_EFI_ERROR (Status);
+
+  Status = ProtectedVariableLibWriteInit ();
+  ASSERT_EFI_ERROR (Status);
+
+  gBS->CloseEvent (Event);
+}
+
+/**
+
+  Initialization for protected variable services.
+
+  If this initialization failed upon any error, the whole variable services
+  should not be used.  A system reset might be needed to re-construct NV
+  variable storage to be the default state.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected variables.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ProtectedVarContext;
+  PROTECTED_VARIABLE_GLOBAL      *OldGlobal;
+  PROTECTED_VARIABLE_GLOBAL      *NewGlobal;
+  VOID                           *VarWriteReg;
+
+  if (  (ContextIn == NULL)
+     || (ContextIn->StructVersion != PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
+     || (ContextIn->StructSize != sizeof (PROTECTED_VARIABLE_CONTEXT_IN))
+     || (ContextIn->GetVariableInfo == NULL)
+     || (ContextIn->GetNextVariableInfo == NULL)
+     || (ContextIn->UpdateVariableStore == NULL)
+     || (ContextIn->UpdateVariable == NULL))
+  {
+    ASSERT (ContextIn != NULL);
+    ASSERT (ContextIn->StructVersion == PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION);
+    ASSERT (ContextIn->StructSize == sizeof (PROTECTED_VARIABLE_CONTEXT_IN));
+    ASSERT (ContextIn->GetVariableInfo != NULL);
+    ASSERT (ContextIn->GetNextVariableInfo != NULL);
+    ASSERT (ContextIn->UpdateVariableStore != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  GetProtectedVariableGlobal (&NewGlobal);
+  ProtectedVarContext = GET_CNTX (NewGlobal);
+  CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn));
+  ProtectedVarContext->VariableServiceUser = FromSmmModule;
+
+  //
+  // Get root key and HMAC key from HOB created by PEI variable driver.
+  //
+  Status = GetProtectedVariableGlobalFromHob (&OldGlobal);
+  ASSERT_EFI_ERROR (Status);
+
+  CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof (*OldGlobal));
+
+  //
+  // The keys must not be available outside SMM.
+  //
+  if (ProtectedVarContext->VariableServiceUser == FromSmmModule) {
+    ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey));
+    ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal->MetaDataHmacKey));
+  }
+
+  //
+  // Register variable write protocol notify function used to fix any
+  // inconsistency in MetaDataHmacVariable before the first variable write
+  // operation.
+  //
+  NewGlobal->Flags.WriteInit  = FALSE;
+  NewGlobal->Flags.WriteReady = FALSE;
+
+  EfiCreateProtocolNotifyEvent (
+    &gEfiVariableWriteArchProtocolGuid,
+    TPL_CALLBACK,
+    VariableWriteProtocolCallback,
+    NULL,
+    &VarWriteReg
+    );
+
+  return EFI_SUCCESS;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
new file mode 100644
index 000000000000..8b5ccb83e32d
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
@@ -0,0 +1,1327 @@
+/** @file
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <PiPei.h>
+
+#include <Guid/VariableFormat.h>
+#include <Ppi/MemoryDiscovered.h>
+
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include "ProtectedVariableInternal.h"
+
+/**
+  Function allocates a global buffer.
+
+  This function allocates a buffer with the specified size.
+
+  @param[in] Size           Size of buffer to allocate.
+  @param[in] AllocatePage   Whether to allocate pages.
+
+  @retval Buffer             Pointer to the Buffer allocated.
+  @retval NULL               if no Buffer was found.
+
+**/
+VOID *
+AllocateGlobalBuffer (
+  IN UINT32   Size,
+  IN BOOLEAN  AllocatePage
+  )
+{
+  VOID                       *Buffer;
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;
+  EFI_PEI_HOB_POINTERS       Hob;
+
+  Buffer = NULL;
+  if (!AllocatePage) {
+    Buffer = BuildGuidHob (&gEdkiiProtectedVariableGlobalGuid, Size);
+  }
+
+  if (Buffer == NULL) {
+    //
+    // Use the AllocatePages() to get over size limit of general GUID-ed HOB.
+    //
+    Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));
+    if (Buffer == NULL) {
+      ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
+      return NULL;
+    }
+
+    //
+    // Mark the HOB holding the pages just allocated so that it can be
+    // identified later.
+    //
+    MemoryAllocationHob = NULL;
+    Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
+    while (Hob.Raw != NULL) {
+      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
+      if ((UINTN)Buffer == (UINTN)MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
+        CopyGuid (
+          &MemoryAllocationHob->AllocDescriptor.Name,
+          &gEdkiiProtectedVariableGlobalGuid
+          );
+        break;
+      }
+
+      Hob.Raw = GET_NEXT_HOB (Hob);
+      Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
+    }
+  }
+
+  return Buffer;
+}
+
+/**
+  Callback use to re-verify all variables and cache them in memory.
+
+  @param[in] PeiServices          General purpose services available to every PEIM.
+  @param[in] NotifyDescriptor     The notification structure this PEIM registered on install.
+  @param[in] Ppi                  The memory discovered PPI.  Not used.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval others                  There's error in MP initialization.
+**/
+EFI_STATUS
+EFIAPI
+MemoryDiscoveredPpiNotifyCallback (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  VARIABLE_DIGEST                *VarDig;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+  VOID                           *Buffer;
+  UINT32                         VarSize;
+  INTN                           Result;
+
+  Status = GetProtectedVariableGlobal (&Global);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  ContextIn = GET_CNTX (Global);
+
+  //
+  // Allocate last Var buffer for confidentiality crypto operation
+  //
+  VarSize = (Global->VariableNumber + 1) * MAX_VARIABLE_SIZE;
+  Buffer  = AllocateGlobalBuffer (VarSize, TRUE);
+
+  //
+  // Traverse all valid variables.
+  //
+  VarDig = VAR_DIG_PTR (Global->VariableDigests);
+  while (VarDig != NULL) {
+    if (VarDig->CacheIndex == VAR_INDEX_INVALID) {
+      ASSERT (VarDig->StoreIndex != VAR_INDEX_INVALID);
+
+      VarSize  =  VARIABLE_HEADER_SIZE (Global->Flags.Auth);
+      VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+      VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+      VarSize  = HEADER_ALIGN (VarSize);
+
+      //
+      // Note the variable might be in unconsecutive space.
+      //
+      ZeroMem (&VarInfo, sizeof (VarInfo));
+      VarInfo.StoreIndex = VarDig->StoreIndex;
+      VarInfo.Buffer     = Buffer;
+      VarInfo.Flags.Auth = VarDig->Flags.Auth;
+
+      Status = ContextIn->GetVariableInfo (&VarInfo);
+      ASSERT_EFI_ERROR (Status);
+      //
+      // VerifyVariableDigest() refers to CipherData for raw data.
+      //
+      VarInfo.CipherData     = VarInfo.Header.Data;
+      VarInfo.CipherDataSize = (UINT32)VarInfo.Header.DataSize;
+
+      //
+      // Make sure that the cached copy is not compromised.
+      //
+      Status = VerifyVariableDigest (Global, &VarInfo, VarDig);
+      if (EFI_ERROR (Status)) {
+        REPORT_STATUS_CODE (
+          EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
+          (PcdGet32 (PcdStatusCodeVariableIntegrity) | (Status & 0xFF))
+          );
+        ASSERT_EFI_ERROR (Status);
+        CpuDeadLoop ();
+      }
+
+      //
+      // Simply use the cache address as CacheIndex of the variable.
+      //
+      VarDig->CacheIndex = GET_ADRS (Buffer);
+      Buffer             = (UINT8 *)Buffer + MAX_VARIABLE_SIZE;
+    } else {
+      Result = StrnCmp (
+                 VAR_DIG_NAME (VarDig),
+                 METADATA_HMAC_VARIABLE_NAME,
+                 METADATA_HMAC_VARIABLE_NAME_SIZE
+                 );
+      if (Result == 0) {
+        CopyMem (
+          Buffer,
+          GET_BUFR (Global->GlobalSelf + (Global->StructSize - GetMetaDataHmacVarSize (Global->Flags.Auth))),
+          GetMetaDataHmacVarSize (Global->Flags.Auth)
+          );
+
+        //
+        // Simply use the cache address as CacheIndex of the variable.
+        //
+        VarDig->CacheIndex = GET_ADRS (Buffer);
+        Buffer             = (UINT8 *)Buffer + MAX_VARIABLE_SIZE;
+      }
+    }
+
+    VarDig = VAR_DIG_NEXT (VarDig);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Callback use to perform variable integrity check.
+
+  @param[in] PeiServices          General purpose services available to every PEIM.
+  @param[in] NotifyDescriptor     The notification structure this PEIM registered on install.
+  @param[in] Ppi                  The memory discovered PPI.  Not used.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval others                  There's error in MP initialization.
+**/
+EFI_STATUS
+EFIAPI
+VariableStoreDiscoveredPpiNotifyCallback (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_HOB_GUID_TYPE              *GuidHob;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+
+  GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
+  if (GuidHob != NULL) {
+    ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA (GuidHob);
+  } else {
+    ASSERT (GuidHob == NULL);
+  }
+
+  Status = ContextIn->IsHobVariableStoreAvailable ();
+
+  if (Status == EFI_NOT_READY) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Status = PerformVariableIntegrityCheck (ContextIn);
+
+  return Status;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR  mPostMemNotifyList[] = {
+  {
+    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gEfiPeiMemoryDiscoveredPpiGuid,
+    MemoryDiscoveredPpiNotifyCallback
+  }
+};
+
+EFI_PEI_NOTIFY_DESCRIPTOR  mVariableStoreNotifyList[] = {
+  {
+    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gEfiPeiVariableStoreDiscoveredPpiGuid,
+    VariableStoreDiscoveredPpiNotifyCallback
+  }
+};
+
+/**
+
+  Get global data structure used to process protected variable.
+
+  @param[out]   Global      Pointer to global configuration data.
+
+  @retval EFI_SUCCESS         Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
+  )
+{
+  return GetProtectedVariableGlobalFromHob (Global);
+}
+
+/**
+
+  Get context data structure used to process protected variable.
+
+  @param[out]   ContextIn   Pointer to context provided by variable runtime services.
+
+  @retval EFI_SUCCESS         Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableContext (
+  PROTECTED_VARIABLE_CONTEXT_IN  **ContextIn  OPTIONAL
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+
+  GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
+  if (GuidHob != NULL) {
+    *ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA (GuidHob);
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Verify the HMAC value stored in MetaDataHmacVar against all valid and
+  protected variables in storage.
+
+  @param[in,out]  Global          Pointer to global configuration data.
+
+  @retval   EFI_SUCCESS           The HMAC value matches.
+  @retval   EFI_ABORTED           Error in HMAC value calculation.
+  @retval   EFI_VOLUME_CORRUPTED  Inconsistency found in NV variable storage.
+  @retval   EFI_COMPROMISED_DATA  The HMAC value doesn't match.
+
+**/
+EFI_STATUS
+VerifyMetaDataHmac (
+  IN OUT  PROTECTED_VARIABLE_GLOBAL  *Global
+  )
+{
+  EFI_STATUS       Status;
+  VARIABLE_DIGEST  *VariableDig;
+  UINT32           Counter1;
+  UINT32           Counter2;
+  VOID             *Hmac1;
+  VOID             *Hmac2;
+  UINT8            HmacVal1[METADATA_HMAC_SIZE];
+  UINT8            HmacVal2[METADATA_HMAC_SIZE];
+
+  Hmac1 = NULL;
+  Hmac2 = HmacSha256New ();
+  if (Hmac2 == NULL) {
+    ASSERT (Hmac2 != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (!HmacSha256SetKey (Hmac2, Global->MetaDataHmacKey, sizeof (Global->MetaDataHmacKey))) {
+    ASSERT (FALSE);
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+
+  //
+  // Retrieve the RPMC counter value.
+  //
+  Status = RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    goto Done;
+  }
+
+  Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    goto Done;
+  }
+
+  //
+  // Counter1 must be either equal to Counter2 or just one step ahead of Counter2.
+  //
+  if ((Counter1 > Counter2) && ((Counter1 - Counter2) > 1)) {
+    Status = EFI_COMPROMISED_DATA;
+    goto Done;
+  }
+
+  VariableDig = VAR_DIG_PTR (Global->VariableDigests);
+  while (VariableDig != NULL) {
+    //
+    // Only take valid protected variables into account.
+    //
+    if (VariableDig->Flags.Protected && VariableDig->Flags.Valid) {
+      if (!HmacSha256Update (
+             Hmac2,
+             VAR_DIG_VALUE (VariableDig),
+             VariableDig->DigestSize
+             ))
+      {
+        ASSERT (FALSE);
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+    }
+
+    VariableDig = VAR_DIG_NEXT (VariableDig);
+  }
+
+  //
+  // If two MetaDataHmacVariable were found, check which one is valid. We might
+  // need two HMAC values to check against: one for Counter1, one for Counter2.
+  //
+  if (  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+     && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID)
+     && (Counter1 != Counter2))
+  {
+    //
+    // Might need to check Counter1. There must be something wrong in last boot.
+    //
+    Hmac1 = HmacSha256New ();
+    if ((Hmac1 == NULL) || !HmacSha256Duplicate (Hmac2, Hmac1)) {
+      ASSERT (FALSE);
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+
+    if (  !HmacSha256Update (Hmac1, &Counter1, sizeof (Counter1))
+       || !HmacSha256Final (Hmac1, HmacVal1))
+    {
+      ASSERT (FALSE);
+      Status = EFI_ABORTED;
+      goto Done;
+    }
+  }
+
+  //
+  // Always check Counter2.
+  //
+  if (  !HmacSha256Update (Hmac2, &Counter2, sizeof (Counter2))
+     || !HmacSha256Final (Hmac2, HmacVal2))
+  {
+    ASSERT (FALSE);
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+
+  //
+  //  When writing (update or add) a variable, there must be following steps
+  //  performed:
+  //
+  //    A - Increment Counter1
+  //    B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+  //    C - Calculate new HMAC value against Counter2+1,
+  //        and force-add a new MetaDataHmacVar with state of VAR_ADDED
+  //    D - Write the new protected variable
+  //    E - Increment Counter2
+  //    F - Mark old MetaDataHmacVar as VAR_DELETED
+  //
+  Status = EFI_COMPROMISED_DATA;
+  if (  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+     && (Global->Unprotected[IndexHmacInDel] == VAR_INDEX_INVALID))
+  {
+    if (CompareMem (
+          VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])),
+          HmacVal2,
+          METADATA_HMAC_SIZE
+          ) == 0)
+    {
+      //
+      //
+      // + A - Increment Counter1
+      //   B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+      //   C - Calculate new HMAC value against Counter2+1,
+      //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
+      //   D - Write the new protected variable
+      //   E - Increment Counter2
+      //   F - Mark old MetaDataHmacVar as VAR_DELETED
+      //
+      // or,
+      //
+      // + A - Increment Counter1
+      // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+      // + C - Calculate new HMAC value against Counter2+1,
+      //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
+      // + D - Write the new protected variable
+      // + E - Increment Counter2
+      // + F - Mark old MetaDataHmacVar as VAR_DELETED
+      //
+      Status = EFI_SUCCESS;
+
+      VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = TRUE;
+    }
+  } else if (  (Global->Unprotected[IndexHmacAdded] == VAR_INDEX_INVALID)
+            && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID))
+  {
+    if (CompareMem (
+          VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])),
+          HmacVal2,
+          METADATA_HMAC_SIZE
+          ) == 0)
+    {
+      //
+      // + A - Increment Counter1
+      // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+      //   C - Calculate new HMAC value against Counter2+1,
+      //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
+      //   D - Write the new protected variable
+      //   E - Increment Counter2
+      //   F - Mark old MetaDataHmacVar as VAR_DELETED
+      //
+      Status = EFI_SUCCESS;
+
+      VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = TRUE;
+    }
+  } else if (  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+            && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID))
+  {
+    if (Counter1 > Counter2) {
+      if (CompareMem (
+            VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])),
+            HmacVal2,
+            METADATA_HMAC_SIZE
+            ) == 0)
+      {
+        //
+        // + A - Increment Counter1
+        // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+        // + C - Calculate new HMAC value against Counter2+1,
+        //       and force-add a new MetaDataHmacVar with state VAR_ADDED
+        //   D - Write the new protected variable
+        //   E - Increment Counter2
+        //   F - Mark old MetaDataHmacVar as VAR_DELETED
+        //
+        Status = EFI_SUCCESS;
+
+        VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = FALSE;
+        VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = TRUE;
+      } else if (CompareMem (
+                   VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])),
+                   HmacVal1,
+                   METADATA_HMAC_SIZE
+                   ) == 0)
+      {
+        //
+        // + A - Increment Counter1
+        // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+        // + C - Calculate new HMAC value against Counter2+1,
+        //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
+        // + D - Write the new protected variable
+        //   E - Increment Counter2
+        //   F - Mark old MetaDataHmacVar as VAR_DELETED
+        //
+        Status = EFI_SUCCESS;
+
+        VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = TRUE;
+        VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = FALSE;
+      }
+    } else {
+      if (CompareMem (
+            VAR_DIG_VALUE (VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])),
+            HmacVal2,
+            METADATA_HMAC_SIZE
+            ) == 0)
+      {
+        //
+        // + A - Increment Counter1
+        // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
+        // + C - Calculate new HMAC value against Counter2+1,
+        //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
+        // + D - Write the new protected variable
+        // + E - Increment Counter2
+        //   F - Mark old MetaDataHmacVar as VAR_DELETED
+        //
+        Status = EFI_SUCCESS;
+
+        VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = TRUE;
+        VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = FALSE;
+      }
+    }
+  } else {
+    //
+    // There must be logic error or variable written to storage skipped
+    // the protected variable service, if code reaches here.
+    //
+    ASSERT (FALSE);
+  }
+
+Done:
+  if (Hmac1 != NULL) {
+    HmacSha256Free (Hmac1);
+  }
+
+  if (Hmac2 != NULL) {
+    HmacSha256Free (Hmac2);
+  }
+
+  return Status;
+}
+
+/**
+  Collect variable digest information.
+
+  This information is collected to be used to for integrity check.
+
+  @param[in]       Global             Pointer to global configuration data.
+  @param[in]       ContextIn          Pointer to variable service context needed by
+                                      protected variable.
+  @param[in, out]  DigestBuffer       Base address of digest of each variable.
+  @param[out]      DigestBufferSize   Digest size of one variable if DigestBuffer is NULL.
+                                      Size of DigestBuffer if DigestBuffer is NOT NULL.
+  @param[out]      VariableNumber     Number of valid variables.
+
+  @retval   EFI_SUCCESS             Successfully retreived variable digest.
+  @retval   EFI_INVALID_PARAMETER   One ore more parameters are invalid.
+  @retval   EFI_OUT_OF_RESOURCES    Unable to allocate memory.
+  @retval   EFI_BUFFER_TOO_SMALL    The DigestBufferSize pass in is too small.
+
+**/
+EFI_STATUS
+CollectVariableDigestInfo (
+  IN      PROTECTED_VARIABLE_GLOBAL      *Global,
+  IN      PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn,
+  IN  OUT VOID                           *DigestBuffer OPTIONAL,
+  OUT UINT32                             *DigestBufferSize OPTIONAL,
+  OUT UINT32                             *VariableNumber OPTIONAL
+  )
+{
+  EFI_STATUS                  Status;
+  PROTECTED_VARIABLE_INFO     VarInfo;
+  UINT32                      VarNum;
+  UINT32                      DigSize;
+  VARIABLE_DIGEST             *VarDig;
+  EFI_TIME                    TimeStamp;
+  UNPROTECTED_VARIABLE_INDEX  VarIndex;
+
+  //
+  // This function might be called before Global is initialized. In that case,
+  // Global must be NULL but not ContextIn.
+  //
+  if ((Global == NULL) && (ContextIn == NULL)) {
+    ASSERT (Global != NULL || ContextIn != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Global == NULL) && (DigestBuffer != NULL)) {
+    ASSERT (Global != NULL && DigestBuffer != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (  (DigestBuffer != NULL)
+     && ((DigestBufferSize == NULL) || (*DigestBufferSize == 0)))
+  {
+    ASSERT (
+      DigestBuffer != NULL
+           && DigestBufferSize != NULL && *DigestBufferSize > 0
+      );
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Global != NULL) && (ContextIn == NULL)) {
+    ContextIn = GET_CNTX (Global);
+  }
+
+  DigSize = 0;
+  VarNum  = 0;
+  VarDig  = NULL;
+
+  ZeroMem (&VarInfo, sizeof (VarInfo));
+  VarInfo.StoreIndex = VAR_INDEX_INVALID; // To get the first variable.
+
+  if ((Global != NULL) &&
+      (Global->VariableCache != 0) &&
+      (Global->VariableCacheSize > 0))
+  {
+    //
+    // Use the variable cache to hold a copy of one variable.
+    //
+    VarInfo.Buffer = GET_BUFR (Global->VariableCache);
+  } else {
+    //
+    // Allocate a buffer to hold a copy of one variable
+    //
+    VarInfo.Buffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
+    if (VarInfo.Buffer == NULL) {
+      ASSERT (VarInfo.Buffer != NULL);
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  if ((DigestBuffer != NULL) && (*DigestBufferSize > 0)) {
+    VarDig = DigestBuffer;
+  }
+
+  while (TRUE) {
+    if (VarDig != NULL) {
+      if (DigSize >= (*DigestBufferSize)) {
+        //
+        // Out of buffer.
+        //
+        break;
+      }
+
+      VarInfo.Header.VendorGuid   = &VarDig->VendorGuid;
+      VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
+      VarInfo.Header.NameSize     = (UINTN)DigestBuffer + (UINTN)*DigestBufferSize
+                                    - (UINTN)VarInfo.Header.VariableName;
+      VarInfo.Header.TimeStamp = &TimeStamp;
+      VarInfo.Header.Data      = NULL;
+    } else {
+      ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header));
+    }
+
+    Status = ContextIn->GetNextVariableInfo (&VarInfo);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    //
+    // Skip deleted variables.
+    //
+    if (  (VarInfo.Header.State != VAR_ADDED)
+       && (VarInfo.Header.State != (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
+    {
+      continue;
+    }
+
+    if (Global != NULL) {
+      Global->Flags.Auth &= VarInfo.Flags.Auth;
+    }
+
+    VarNum  += 1;
+    DigSize += (UINT32)(sizeof (VARIABLE_DIGEST)
+                        + VarInfo.Header.NameSize
+                        + METADATA_HMAC_SIZE);
+    if ((DigestBuffer != NULL) && (DigSize > *DigestBufferSize)) {
+      ASSERT (DigSize <= *DigestBufferSize);
+      return EFI_BUFFER_TOO_SMALL;
+    }
+
+    if (VarDig != NULL) {
+      VarDig->Prev       = 0;
+      VarDig->Next       = 0;
+      VarDig->State      = VarInfo.Header.State;
+      VarDig->Attributes = VarInfo.Header.Attributes;
+      VarDig->DataSize   = (UINT32)VarInfo.Header.DataSize;
+      VarDig->NameSize   = (UINT16)VarInfo.Header.NameSize;
+      VarDig->DigestSize = METADATA_HMAC_SIZE;
+      VarDig->StoreIndex = VarInfo.StoreIndex;
+
+      if ((VarInfo.Buffer != NULL) && ((UINTN)VarInfo.Buffer != Global->VariableCache)) {
+        VarDig->CacheIndex = GET_ADRS (VarInfo.Buffer);
+      } else {
+        VarDig->CacheIndex = VAR_INDEX_INVALID;
+      }
+
+      VarDig->Flags.Auth  = VarInfo.Flags.Auth;
+      VarDig->Flags.Valid = TRUE;
+
+      VarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+      if (VarIndex >= UnprotectedVarIndexMax) {
+        //
+        // Check information relating to encryption, if enabled.
+        //
+        VarDig->Flags.Encrypted = FALSE;
+        if ((VarInfo.Header.Data != NULL) && (VarInfo.Header.DataSize > 0)) {
+          VarInfo.CipherData     = NULL;
+          VarInfo.CipherDataSize = 0;
+          VarInfo.PlainData      = NULL;
+          VarInfo.PlainDataSize  = 0;
+          Status                 = GetCipherDataInfo (&VarInfo);
+          if (!EFI_ERROR (Status)) {
+            //
+            // Discovered encrypted variable mark variable to be
+            // encrypted on the next SetVariable() operation
+            //
+            VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
+          } else {
+            VarInfo.PlainData        = VarInfo.Header.Data;
+            VarInfo.PlainDataSize    = (UINT32)VarInfo.Header.DataSize;
+            VarInfo.CipherDataType   = 0;
+            VarInfo.CipherHeaderSize = 0;
+            if (Status == EFI_NOT_FOUND) {
+              //
+              // Found variable that is not encrypted mark variable to be
+              // encrypted on the next SetVariable() operation
+              //
+              VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
+            }
+          }
+        }
+
+        //
+        // Variable is protected
+        //
+        VarDig->Flags.Protected = PcdGetBool (PcdProtectedVariableIntegrity);
+        VarDig->PlainDataSize   = VarInfo.PlainDataSize;
+
+        //
+        // Calculate digest only for protected variable.
+        //
+        Status = GetVariableDigest (Global, &VarInfo, VAR_DIG_VALUE (VarDig));
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+
+        //
+        // Keep the VarDig in an ordered list.
+        //
+        InsertVariableDigestNode (Global, VarDig, CompareVariableDigestInfo);
+      } else {
+        VarDig->Flags.Protected = FALSE;
+        VarDig->Flags.Encrypted = FALSE;
+        VarDig->PlainDataSize   = VarDig->DataSize;
+
+        //
+        // Make use of VARIABLE_DIGEST->DigestValue to cache HMAC value from
+        // MetaDataHmacVar, which doesn't need a digest value (only protected
+        // variables need it for integrity check).
+        //
+        if ((VarIndex == IndexHmacInDel) || (VarIndex == IndexHmacAdded)) {
+          if (VarDig->State == VAR_ADDED) {
+            VarIndex = IndexHmacAdded;
+          } else {
+            VarIndex = IndexHmacInDel;
+          }
+        }
+
+        Global->Unprotected[VarIndex] = VAR_DIG_ADR (VarDig);
+
+        if ((VarInfo.Header.Data != NULL) && (VarDig->DataSize <= VarDig->DigestSize)) {
+          CopyMem (VAR_DIG_VALUE (VarDig), VarInfo.Header.Data, VarDig->DataSize);
+        }
+
+        //
+        // Don't add the VarDig for MetaDataHmacVar into the linked list now.
+        // Do it after the HMAC has been validated.
+        //
+        if ((VarIndex != IndexHmacInDel) || (VarIndex != IndexHmacAdded)) {
+          InsertVariableDigestNode (Global, VarDig, CompareVariableDigestInfo);
+        }
+      }
+
+      VarDig = (VARIABLE_DIGEST *)((UINTN)VarDig + VAR_DIG_END (VarDig));
+    }
+  }
+
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+    return Status;
+  }
+
+  if (DigestBufferSize != NULL) {
+    *DigestBufferSize = DigSize;
+  }
+
+  if (VariableNumber != NULL) {
+    *VariableNumber = VarNum;
+  }
+
+  if ((Global == NULL) && (VarInfo.Buffer != NULL)) {
+    //
+    // Free Buffer
+    //
+    FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Perform for protected variable integrity check.
+
+  If this initialization failed upon any error, the whole variable services
+  should not be used.  A system reset might be needed to re-construct NV
+  variable storage to be the default state.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected variables.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+PerformVariableIntegrityCheck (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     HobDataSize;
+  UINT32                     VarNumber;
+  VOID                       *Buffer;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VARIABLE_DIGEST            *DigBuffer;
+  UINT32                     DigBufferSize;
+  UINT32                     HmacMetaDataSize;
+  UINTN                      Index;
+  BOOLEAN                    PreviousKey;
+  EFI_HOB_GUID_TYPE          *GuidHob;
+
+  if ((ContextIn == NULL) || (ContextIn->GetNextVariableInfo == NULL)) {
+    ASSERT (ContextIn != NULL);
+    ASSERT (ContextIn->GetNextVariableInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ContextIn->StructSize = (ContextIn->StructSize == 0) ? sizeof (*ContextIn)
+                                                       : ContextIn->StructSize;
+
+  //
+  // Enumerate all variables first to collect info for resource allocation.
+  //
+  DigBufferSize = 0;
+  Status        = CollectVariableDigestInfo (
+                    NULL,
+                    ContextIn,
+                    NULL,
+                    &DigBufferSize,
+                    &VarNumber
+                    );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  //
+  // Allocate buffer for Global. Memory layout:
+  //
+  //      Global
+  //      Digest context
+  //      Variable Digest List
+  //      HmacMetaData
+  //
+  // To save precious NEM space of processor, variable cache will not be
+  // allocated at this point until physical memory is ready for use.
+  //
+  HmacMetaDataSize = (UINT32)GetMetaDataHmacVarSize (TRUE);
+  HobDataSize      = sizeof (PROTECTED_VARIABLE_GLOBAL)
+                     + (UINT32)DIGEST_CONTEXT_SIZE
+                     + DigBufferSize
+                     + HmacMetaDataSize;
+  Buffer = AllocateGlobalBuffer (HobDataSize, FALSE);
+  if (Buffer == NULL) {
+    ASSERT (Buffer != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Global                = (PROTECTED_VARIABLE_GLOBAL *)((UINTN)Buffer);
+  Global->DigestContext = GET_ADRS (Global + 1);
+
+  if (DigBufferSize > 0) {
+    DigBuffer = (VARIABLE_DIGEST *)(UINTN)(Global->DigestContext + DIGEST_CONTEXT_SIZE);
+    ZeroMem (DigBuffer, DigBufferSize);
+  } else {
+    DigBuffer = NULL;
+  }
+
+  //
+  // Keep a copy of ContextIn in HOB for later uses.
+  //
+  Global->GlobalSelf = GET_ADRS (Global);
+  Global->ContextIn  = GET_ADRS (ContextIn);
+
+  Global->StructVersion = PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION;
+  Global->StructSize    = HobDataSize;
+
+  Global->VariableNumber  = VarNumber;
+  Global->VariableDigests = 0;
+
+  Global->Flags.Auth       = TRUE;
+  Global->Flags.WriteInit  = FALSE;
+  Global->Flags.WriteReady = FALSE;
+
+  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+  if (GuidHob == NULL) {
+    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+    if (GuidHob != NULL) {
+      Global->Flags.Auth = FALSE;
+    }
+  }
+
+  Global->Flags.RecoveryMode = (GuidHob != NULL);
+
+  //
+  // Before physical memory is ready, we cannot cache all variables in the very
+  // limited NEM space. But we still need to reserve buffer to hold data of
+  // one variable as well as context for integrity check (HMAC calculation).
+  //
+  Global->VariableCacheSize = MAX_VARIABLE_SIZE;
+  Buffer                    = AllocatePages (EFI_SIZE_TO_PAGES (Global->VariableCacheSize));
+  if (Buffer == NULL) {
+    ASSERT (Buffer != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Global->VariableCache        = GET_ADRS (Buffer);
+  Global->LastAccessedVariable = VAR_INDEX_INVALID;
+
+  for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
+    Global->Unprotected[Index] = VAR_INDEX_INVALID;
+  }
+
+  //
+  // Re-enumerate all NV variables and build digest list.
+  //
+  Status = CollectVariableDigestInfo (
+             Global,
+             ContextIn,
+             DigBuffer,
+             &DigBufferSize,
+             &VarNumber
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  ASSERT (Global->VariableNumber == VarNumber);
+
+  //
+  // Fix-up number of valid protected variables (i.e. exclude unprotected ones)
+  //
+  for (Index = 0; VarNumber != 0 && Index < UnprotectedVarIndexMax; ++Index) {
+    if (Global->Unprotected[Index] != VAR_INDEX_INVALID) {
+      --VarNumber;
+    }
+  }
+
+  //
+  // Get root key and generate HMAC key.
+  //
+  PreviousKey = FALSE;
+  Status      = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
+  if (EFI_ERROR (Status)) {
+    ASSERT (FALSE);
+    Status = EFI_COMPROMISED_DATA;
+  }
+
+  //
+  // Derive the MetaDataHmacKey from root key
+  //
+  if (!GenerateMetaDataHmacKey (
+         Global->RootKey,
+         sizeof (Global->RootKey),
+         Global->MetaDataHmacKey,
+         sizeof (Global->MetaDataHmacKey)
+         ))
+  {
+    ASSERT (FALSE);
+    Status = EFI_COMPROMISED_DATA;
+  }
+
+  //
+  // Check the integrity of all NV variables, if any.
+  //
+  if ((  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
+      || (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID)))
+  {
+    //
+    // Validate the HMAC stored in variable MetaDataHmacVar.
+    //
+    Status = VerifyMetaDataHmac (Global);
+    if (EFI_ERROR (Status)) {
+      //
+      // Try again with the previous root key if the latest key failed the HMAC validation.
+      //
+      Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
+      if (!EFI_ERROR (Status)) {
+        //
+        // Derive the MetaDataHmacKey from previous root key
+        //
+        if (GenerateMetaDataHmacKey (
+              Global->RootKey,
+              sizeof (Global->RootKey),
+              Global->MetaDataHmacKey,
+              sizeof (Global->MetaDataHmacKey)
+              ) == TRUE)
+        {
+          //
+          // Validate the HMAC stored in variable MetaDataHmacVar.
+          //
+          Status = VerifyMetaDataHmac (Global);
+          if (!EFI_ERROR (Status)) {
+            Status = EFI_COMPROMISED_DATA;
+          }
+        } else {
+          Status = EFI_COMPROMISED_DATA;
+        }
+      }
+    }
+  } else if (Global->Flags.RecoveryMode) {
+    //
+    // Generate the first version of MetaDataHmacVar.
+    //
+    Status = SyncRpmcCounter ();
+    if (!EFI_ERROR (Status)) {
+      Status = RefreshVariableMetadataHmac (Global, NULL, NULL);
+      if (!EFI_ERROR (Status)) {
+        //
+        // MetaDataHmacVar is always calculated against Counter2+1. Updating
+        // RPMCs to match it.
+        //
+        (VOID)IncrementMonotonicCounter (RPMC_COUNTER_1);
+        (VOID)IncrementMonotonicCounter (RPMC_COUNTER_2);
+      }
+    }
+  } else if ((VarNumber > 0) && !Global->Flags.RecoveryMode) {
+    //
+    // There's no MetaDataHmacVar found for protected variables. Suppose
+    // the variable storage is compromised.
+    //
+    Status = EFI_COMPROMISED_DATA;
+  }
+
+  if (EFI_ERROR (Status)) {
+    //
+    // The integrity of variables have been compromised. The platform has to do
+    // something to recover the variable store. But the boot should not go on
+    // anyway this time.
+    //
+    DEBUG ((DEBUG_ERROR, "%a: %d Integrity check Status = %r\n", __FUNCTION__, __LINE__, Status));
+    REPORT_STATUS_CODE (
+      EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
+      (PcdGet32 (PcdStatusCodeVariableIntegrity) | EFI_SW_PEI_PC_RECOVERY_BEGIN)
+      );
+ #if defined (EDKII_UNIT_TEST_FRAMEWORK_ENABLED) // Avoid test malfunctioning.
+    return Status;
+ #else
+    ASSERT_EFI_ERROR (Status);
+    CpuDeadLoop ();
+ #endif
+  }
+
+  //
+  // Everything's OK.
+  //
+  REPORT_STATUS_CODE (
+    EFI_PROGRESS_CODE,
+    PcdGet32 (PcdStatusCodeVariableIntegrity)
+    );
+
+  if (GET_BUFR (Global->VariableCacheSize) != NULL) {
+    //
+    // Free Buffer
+    //
+    FreePages (Buffer, EFI_SIZE_TO_PAGES (Global->VariableCacheSize));
+  }
+
+  //
+  // Keep the valid MetaDataHmacVar in the list.
+  //
+  for (Index = 0; Index < IndexPlatformVar; ++Index) {
+    if (  (Global->Unprotected[Index] != VAR_INDEX_INVALID)
+       && VAR_DIG_PTR (Global->Unprotected[Index])->Flags.Valid)
+    {
+      InsertVariableDigestNode (
+        Global,
+        VAR_DIG_PTR (Global->Unprotected[Index]),
+        NULL
+        );
+    }
+  }
+
+  //
+  // Restore the key to the latest one.
+  //
+  if (PreviousKey) {
+    Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // Derive the MetaDataHmacKey from root key
+    //
+    if (!GenerateMetaDataHmacKey (
+           Global->RootKey,
+           sizeof (Global->RootKey),
+           Global->MetaDataHmacKey,
+           sizeof (Global->MetaDataHmacKey)
+           ))
+    {
+      ASSERT (FALSE);
+    }
+  }
+
+  //
+  // Make sure that the RPMC counter is in-sync.
+  //
+  Status = SyncRpmcCounter ();
+
+  //
+  // Setup a hook to migrate data in Global once physical memory is ready.
+  //
+  Status = PeiServicesNotifyPpi (mPostMemNotifyList);
+
+  return Status;
+}
+
+/**
+
+  Initialization for protected variable services.
+
+  If the variable store is available than perform integrity check.
+  Otherwise, defer integrity check until variable store is available.
+
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected variables.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  )
+{
+  EFI_STATUS               Status;
+  VOID                     *ContextInHob;
+  PROTECTED_VARIABLE_INFO  VarInfo;
+
+  if ((ContextIn == NULL) || (ContextIn->GetNextVariableInfo == NULL)) {
+    ASSERT (ContextIn != NULL);
+    ASSERT (ContextIn->GetNextVariableInfo != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Keep a copy of ContextIn in HOB for later uses.
+  //
+  ContextIn->StructSize = (ContextIn->StructSize == 0) ? sizeof (*ContextIn)
+                                                       : ContextIn->StructSize;
+  ContextInHob = BuildGuidHob (&gEdkiiProtectedVariableContextGuid, ContextIn->StructSize);
+  CopyMem (ContextInHob, ContextIn, ContextIn->StructSize);
+
+  //
+  // Discover if Variable Store Info Hob has been published by platform driver.
+  // It contains information regards to HOB or NV Variable Store availability
+  //
+  ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header));
+  VarInfo.StoreIndex = VAR_INDEX_INVALID;
+  VarInfo.Buffer     = AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
+  if (VarInfo.Buffer == NULL) {
+    ASSERT (VarInfo.Buffer != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES ((MAX_VARIABLE_SIZE)));
+
+  Status = ContextIn->GetNextVariableInfo (&VarInfo);
+  if (EFI_ERROR (Status)) {
+    //
+    // Register for platform driver callback when Variable Store is available.
+    //
+    DEBUG ((DEBUG_INFO, "Variable Store is not available. Register for a integrity check callback\n"));
+    Status = PeiServicesNotifyPpi (mVariableStoreNotifyList);
+    return Status;
+  }
+
+  //
+  // HOB Variable store is not available
+  // Assume NV Variable store is available instead
+  // Perform integrity check on NV Variable Store
+  //
+  DEBUG ((DEBUG_INFO, "NV Variable Store is available. Perform integrity check\n"));
+  Status = PerformVariableIntegrityCheck (ContextInHob);
+  return Status;
+}
+
+/**
+
+  Prepare for variable update.
+
+  (Not suppported in PEI phase.)
+
+  @retval EFI_UNSUPPORTED         Updating variable is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+  VOID
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Update a variable with protection provided by this library.
+
+  Not supported in PEI phase.
+
+  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
+                                      adding a new variable.
+  @param[in]      CurrVariableInDel   In-delete-transition copy of updating variable.
+  @param[in,out]  NewVariable         Buffer of new variable data.
+                                      Buffer of "MetaDataHmacVar" and new
+                                      variable (encrypted).
+  @param[in,out]  NewVariableSize     Size of NewVariable.
+                                      Size of (encrypted) NewVariable and
+                                      "MetaDataHmacVar".
+
+  @retval EFI_UNSUPPORTED         Not support updating variable in PEI phase.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+  IN  OUT VARIABLE_HEADER  *CurrVariable,
+  IN      VARIABLE_HEADER  *CurrVariableInDel,
+  IN  OUT VARIABLE_HEADER  *NewVariable,
+  IN  OUT UINTN            *NewVariableSize
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Finalize a variable updating after it's written to NV variable storage
+  successfully.
+
+  @param[in]      NewVariable       Buffer of new variables and MetaDataHmacVar.
+  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
+  @param[in]      StoreIndex        StoreIndex to NV variable storage from where the new
+                                    variable and MetaDataHmacVar have been written.
+
+  @retval EFI_UNSUPPORTED           Not support updating variable in PEI phase.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+  IN  VARIABLE_HEADER  *NewVariable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
new file mode 100644
index 000000000000..8e964f4cd28d
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
@@ -0,0 +1,209 @@
+/** @file
+  Implemention of ProtectedVariableLib for SMM variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Guid/SmmVariableCommon.h"
+
+#include "Library/MmServicesTableLib.h"
+#include "Library/MemoryAllocationLib.h"
+
+#include "ProtectedVariableInternal.h"
+
+PROTECTED_VARIABLE_CONTEXT_IN  mVariableContextIn = {
+  PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
+  sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
+  0,
+  FromSmmModule,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+PROTECTED_VARIABLE_GLOBAL  mProtectedVariableGlobal = {
+  PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
+  sizeof (PROTECTED_VARIABLE_GLOBAL),
+  { 0 },
+  { 0 },
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  { 0,                                          0,  0 },
+  0,
+  0,
+  { 0,                                          0,  0, 0}
+};
+
+/**
+
+  Callback function to call variable write.
+
+  @param[in]  Protocol    Not Used.
+  @param[in]  Interface   Not Used.
+  @param[in]  Handle      Not Used.
+
+  @retval EFI_SUCCESS     Protected variable write successful.
+  @retval others          Protected variable write failed.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableWriteProtocolCallback (
+  IN CONST EFI_GUID  *Protocol,
+  IN VOID            *Interface,
+  IN EFI_HANDLE      Handle
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = ProtectedVariableLibWriteInit ();
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Initialization for protected variable services.
+
+  If this initialization failed upon any error, the whole variable services
+  should not be used.  A system reset might be needed to re-construct NV
+  variable storage to be the default state.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected variables.
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
+  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ProtectedVarContext;
+  PROTECTED_VARIABLE_GLOBAL      *OldGlobal;
+  PROTECTED_VARIABLE_GLOBAL      *NewGlobal;
+  VARIABLE_DIGEST                *VarDig;
+  VARIABLE_DIGEST                *NewVarDig;
+  EFI_PHYSICAL_ADDRESS           NewCacheIndex;
+  UINTN                          VarSize;
+  UNPROTECTED_VARIABLE_INDEX     Index;
+
+  if (  (ContextIn == NULL)
+     || (ContextIn->StructVersion != PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
+     || (ContextIn->StructSize != sizeof (PROTECTED_VARIABLE_CONTEXT_IN))
+     || (ContextIn->GetVariableInfo == NULL)
+     || (ContextIn->GetNextVariableInfo == NULL)
+     || (ContextIn->UpdateVariableStore == NULL)
+     || (ContextIn->UpdateVariable == NULL))
+  {
+    ASSERT (ContextIn != NULL);
+    ASSERT (ContextIn->StructVersion == PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION);
+    ASSERT (ContextIn->StructSize == sizeof (PROTECTED_VARIABLE_CONTEXT_IN));
+    ASSERT (ContextIn->GetVariableInfo != NULL);
+    ASSERT (ContextIn->GetNextVariableInfo != NULL);
+    ASSERT (ContextIn->UpdateVariableStore != NULL);
+    ASSERT (ContextIn->UpdateVariable != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  GetProtectedVariableGlobal (&NewGlobal);
+  ProtectedVarContext = GET_CNTX (NewGlobal);
+  CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn));
+  ProtectedVarContext->VariableServiceUser = FromSmmModule;
+
+  //
+  // Get root key and HMAC key from HOB created by PEI variable driver.
+  //
+  Status = GetProtectedVariableGlobalFromHob (&OldGlobal);
+  ASSERT_EFI_ERROR (Status);
+
+  CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof (*OldGlobal));
+
+  //
+  // The keys must not be available outside SMM.
+  //
+  if (ProtectedVarContext->VariableServiceUser == FromSmmModule) {
+    ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey));
+    ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal->MetaDataHmacKey));
+  }
+
+  NewGlobal->Flags.WriteInit      = FALSE;
+  NewGlobal->Flags.WriteReady     = FALSE;
+  NewGlobal->LastAccessedVariable = 0;
+  NewGlobal->VariableCache        = GET_ADRS (AllocateZeroPool (MAX_VARIABLE_SIZE));
+  NewGlobal->DigestContext        = GET_ADRS (AllocateZeroPool (DIGEST_CONTEXT_SIZE));
+  if (NewGlobal->DigestContext == 0) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Copy over variable from HOB to SMM memory
+  //
+  NewGlobal->VariableDigests = 0;
+  VarDig                     = VAR_DIG_PTR (OldGlobal->VariableDigests);
+  while (VarDig != NULL) {
+    //
+    // Allocate new Var Digest in SMM memory
+    //
+    NewVarDig = (VARIABLE_DIGEST *)AllocateZeroPool (
+                                     sizeof (VARIABLE_DIGEST) + VarDig->NameSize + METADATA_HMAC_SIZE
+                                     );
+    if (NewVarDig == NULL) {
+      ASSERT (NewVarDig != NULL);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    CopyMem (NewVarDig, VarDig, sizeof (VARIABLE_DIGEST));
+    NewVarDig->Prev = 0;
+    NewVarDig->Next = 0;
+
+    CopyMem (VAR_DIG_NAME (NewVarDig), VAR_DIG_NAME (VarDig), VarDig->NameSize);
+    CopyMem (VAR_DIG_VALUE (NewVarDig), VAR_DIG_VALUE (VarDig), VarDig->DigestSize);
+
+    VarSize  =  VARIABLE_HEADER_SIZE (NewGlobal->Flags.Auth);
+    VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+    VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+    VarSize  = HEADER_ALIGN (VarSize);
+
+    NewCacheIndex = GET_ADRS (AllocateZeroPool (VarSize));
+    if (GET_BUFR (NewCacheIndex) == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    CopyMem (GET_BUFR (NewCacheIndex), GET_BUFR (VarDig->CacheIndex), VarSize);
+    NewVarDig->CacheIndex     = NewCacheIndex;
+    NewVarDig->Flags.Freeable = TRUE;
+
+    for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
+      if (OldGlobal->Unprotected[Index] == VAR_DIG_ADR (VarDig)) {
+        NewGlobal->Unprotected[Index] = VAR_DIG_ADR (NewVarDig);
+      }
+    }
+
+    InsertVariableDigestNode (NewGlobal, NewVarDig, NULL);
+
+    VarDig = VAR_DIG_NEXT (VarDig);
+  }
+
+  return Status;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
new file mode 100644
index 000000000000..8472fc8a33c7
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
@@ -0,0 +1,967 @@
+/** @file
+  Implemention of ProtectedVariableLib for SMM variable services.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Guid/SmmVariableCommon.h"
+
+#include "Library/MmServicesTableLib.h"
+#include "Library/MemoryAllocationLib.h"
+#include <Library/HobLib.h>
+
+#include "ProtectedVariableInternal.h"
+
+/**
+
+  Get context and/or global data structure used to process protected variable.
+
+  @param[out]   Global      Pointer to global configuration data.
+
+  @retval EFI_SUCCESS         Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
+  )
+{
+  if (Global != NULL) {
+    mProtectedVariableGlobal.ContextIn = GET_ADRS (&mVariableContextIn);
+    *Global                            = &mProtectedVariableGlobal;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Encrypt given variable data and generate new HMAC value against it.
+
+  @param[in]      Global          Pointer to global configuration data.
+  @param[in,out]  NewVarInfo      Pointer to buffer of new variable data.
+  @param[in,out]  NewVarDig       Pointer to buffer of new variable digest.
+
+  @retval EFI_SUCCESS           No error occurred during the encryption and HMC calculation.
+  @retval EFI_ABORTED           Failed to do HMC calculation.
+  @return EFI_OUT_OF_RESOURCES  Not enough resource to calculate HMC value.
+  @return EFI_NOT_FOUND         The MetaDataHmacVar was not found in storage.
+
+**/
+STATIC
+EFI_STATUS
+UpdateVariableInternal (
+  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
+  IN  OUT PROTECTED_VARIABLE_INFO    *NewVarInfo,
+  IN  OUT VARIABLE_DIGEST            *NewVarDig
+  )
+{
+  EFI_STATUS               Status;
+  PROTECTED_VARIABLE_INFO  CachedVarInfo;
+  VOID                     *Buffer;
+  UINTN                    VarSize;
+
+  if ((NewVarInfo == NULL) || (NewVarDig == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If Add or update variable, encrypt new data first.
+  //
+  if (NewVarInfo->Buffer != NULL) {
+    Status = EFI_UNSUPPORTED;
+
+    if (NewVarDig->Flags.Encrypted) {
+      NewVarInfo->PlainData          = NULL;
+      NewVarInfo->PlainDataSize      = 0;
+      NewVarInfo->CipherData         = NULL;
+      NewVarInfo->CipherDataSize     = 0;
+      NewVarInfo->Key                = Global->RootKey;
+      NewVarInfo->KeySize            = sizeof (Global->RootKey);
+      NewVarInfo->Header.Attributes &= (~EFI_VARIABLE_APPEND_WRITE);
+      Status                         = EncryptVariable (NewVarInfo);
+      if (!EFI_ERROR (Status)) {
+        //
+        // Update new data size in variable header.
+        //
+        SET_VARIABLE_DATA_SIZE (NewVarInfo, NewVarInfo->CipherDataSize);
+      } else if (Status != EFI_UNSUPPORTED) {
+        ASSERT (FALSE);
+        return Status;
+      }
+    }
+
+    if (Status == EFI_UNSUPPORTED) {
+      NewVarInfo->CipherData     = NewVarInfo->Header.Data;
+      NewVarInfo->CipherDataSize = (UINT32)NewVarInfo->Header.DataSize;
+      NewVarInfo->PlainData      = NULL;
+      NewVarInfo->PlainDataSize  = 0;
+    }
+  } else {
+    NewVarInfo->CipherData     = NULL;
+    NewVarInfo->CipherDataSize = 0;
+    NewVarInfo->PlainData      = NULL;
+    NewVarInfo->PlainDataSize  = 0;
+  }
+
+  if (NewVarDig->CacheIndex != 0) {
+    //
+    // Update the cached copy.
+    //
+    ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo));
+    CachedVarInfo.Buffer     = GET_BUFR (NewVarDig->CacheIndex);
+    CachedVarInfo.StoreIndex = VAR_INDEX_INVALID;
+    CachedVarInfo.Flags.Auth = NewVarInfo->Flags.Auth;
+
+    Status = GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo);
+    ASSERT_EFI_ERROR (Status);
+
+    if ((CachedVarInfo.Header.DataSize != 0) && (NewVarInfo->CipherDataSize > CachedVarInfo.Header.DataSize)) {
+      //
+      // allocate new VarInfo buffer that is of greater CipherDataSize
+      //
+      VarSize  =  VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth);
+      VarSize += NewVarInfo->Header.NameSize + GET_PAD_SIZE (NewVarInfo->Header.NameSize);
+      VarSize += NewVarInfo->CipherDataSize + GET_PAD_SIZE (NewVarInfo->CipherDataSize);
+      VarSize  = HEADER_ALIGN (VarSize);
+      Buffer   = AllocateZeroPool (VarSize);
+      if (Buffer != NULL) {
+        VarSize  =  VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth);
+        VarSize += CachedVarInfo.Header.NameSize + GET_PAD_SIZE (CachedVarInfo.Header.NameSize);
+        VarSize += CachedVarInfo.Header.DataSize + GET_PAD_SIZE (CachedVarInfo.DataSize);
+        VarSize  = HEADER_ALIGN (VarSize);
+
+        CopyMem (
+          Buffer,
+          CachedVarInfo.Buffer,
+          VarSize
+          );
+
+        FreePool (CachedVarInfo.Buffer);
+
+        //
+        // Update the cached copy.
+        //
+        ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo));
+        CachedVarInfo.Buffer     = Buffer;
+        CachedVarInfo.StoreIndex = VAR_INDEX_INVALID;
+        CachedVarInfo.Flags.Auth = NewVarInfo->Flags.Auth;
+        Status                   = GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo);
+        ASSERT_EFI_ERROR (Status);
+        NewVarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+      }
+    }
+
+    CopyMem (
+      CachedVarInfo.Header.Data,
+      NewVarInfo->CipherData,
+      NewVarInfo->CipherDataSize
+      );
+    SET_VARIABLE_DATA_SIZE (&CachedVarInfo, NewVarInfo->CipherDataSize);
+
+    NewVarDig->State    = VAR_ADDED;
+    NewVarDig->DataSize = NewVarInfo->CipherDataSize;
+
+    if (NewVarInfo->PlainDataSize > 0) {
+      NewVarDig->PlainDataSize = NewVarInfo->PlainDataSize;
+    } else {
+      NewVarDig->PlainDataSize = NewVarDig->DataSize;
+    }
+
+    //
+    // (Re-)Calculate the hash of the variable.
+    //
+    if (NewVarDig->Flags.Protected) {
+      GetVariableDigest (Global, NewVarInfo, VAR_DIG_VALUE (NewVarDig));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Fix state of MetaDataHmacVar on NV variable storage, if there's failure at
+  last boot during updating variable.
+
+  This must be done before the first writing of variable in current boot,
+  including storage reclaim.
+
+  @retval EFI_UNSUPPORTED        Updating NV variable storage is not supported.
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource to complete the operation.
+  @retval EFI_SUCCESS            Variable store was successfully updated.
+
+**/
+EFI_STATUS
+FixupHmacVariable (
+  VOID
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_INFO        HmacVarInfo;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  VARIABLE_DIGEST                *VarDig;
+  UINTN                          Index;
+
+  Status = GetProtectedVariableGlobal (&Global);
+  ASSERT_EFI_ERROR (Status);
+
+  if (Global->Flags.WriteReady) {
+    return EFI_SUCCESS;
+  }
+
+  ContextIn = GET_CNTX (Global);
+
+  //
+  // Delete invalid MetaDataHmacVar.
+  //
+  for (Index = 0; Index <= IndexHmacAdded; ++Index) {
+    if (Global->Unprotected[Index] == VAR_INDEX_INVALID) {
+      continue;
+    }
+
+    VarDig = VAR_DIG_PTR (Global->Unprotected[Index]);
+    if (VarDig->Flags.Valid) {
+      continue;
+    }
+
+    ZeroMem ((VOID *)&HmacVarInfo, sizeof (HmacVarInfo));
+    HmacVarInfo.StoreIndex = VarDig->StoreIndex;
+    HmacVarInfo.Flags.Auth = VarDig->Flags.Auth;
+
+    Status = ContextIn->GetVariableInfo (&HmacVarInfo);
+    if (!EFI_ERROR (Status) && (HmacVarInfo.Buffer != NULL)) {
+      HmacVarInfo.Buffer->State &= VAR_DELETED;
+      Status                     = ContextIn->UpdateVariableStore (
+                                                &HmacVarInfo,
+                                                OFFSET_OF (VARIABLE_HEADER, State),
+                                                sizeof (HmacVarInfo.Buffer->State),
+                                                &HmacVarInfo.Buffer->State
+                                                );
+      if (EFI_ERROR (Status)) {
+        ASSERT_EFI_ERROR (Status);
+        return Status;
+      }
+    }
+
+    //
+    // Release the resource and update related states.
+    //
+    VarDig->State &= VAR_DELETED;
+    RemoveVariableDigestNode (Global, VarDig, FALSE);
+    Global->Unprotected[Index] = VAR_INDEX_INVALID;
+  }
+
+  //
+  // There should be no MetaDataHmacVar if in variable storage recovery mode.
+  //
+  if (Global->Flags.RecoveryMode) {
+    ASSERT (Global->Unprotected[IndexHmacAdded] == VAR_INDEX_INVALID);
+    ASSERT (Global->Unprotected[IndexHmacInDel] == VAR_INDEX_INVALID);
+  }
+
+  Global->Flags.WriteReady = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Prepare for variable update.
+
+  This is needed only once during current boot to mitigate replay attack. Its
+  major job is to advance RPMC (Replay Protected Monotonic Counter).
+
+  @retval EFI_SUCCESS             Variable is ready to update hereafter.
+  @retval EFI_UNSUPPORTED         Updating variable is not supported.
+  @retval EFI_DEVICE_ERROR        Error in advancing RPMC.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+  VOID
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+
+  (VOID)GetProtectedVariableGlobal (&Global);
+  ContextIn = GET_CNTX (Global);
+
+  //
+  // HmacVarInfo should be here
+  //
+  if (Global->Flags.RecoveryMode) {
+    //
+    // Flush default variables to variable storage if in variable recovery mode.
+    //
+    Status = ContextIn->UpdateVariableStore (NULL, 0, (UINT32)-1, NULL);
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+  } else {
+    ContextIn = GET_CNTX (Global);
+
+    //
+    // Fix any wrong MetaDataHmacVar information before adding new one.
+    //
+    Status = FixupHmacVariable ();
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+
+    if (!Global->Flags.WriteReady) {
+      return EFI_NOT_READY;
+    }
+
+    //
+    // Refresh MetaDataHmacVar with RPMC2 by 1 in each boot before any variable
+    // update,  by deleting (attr == 0 && datasize == 0) the old one.
+    //
+    ZeroMem (&VarInfo, sizeof (PROTECTED_VARIABLE_INFO));  // Zero attr & datasize
+
+    VarInfo.Flags.Auth          = Global->Flags.Auth;
+    VarInfo.Header.VariableName = METADATA_HMAC_VARIABLE_NAME;
+    VarInfo.Header.NameSize     = METADATA_HMAC_VARIABLE_NAME_SIZE;
+    VarInfo.Header.VendorGuid   = &METADATA_HMAC_VARIABLE_GUID;
+
+    //
+    // Pretend to delete MetaDataHmacVar.
+    //
+    Status = ContextIn->UpdateVariable (&VarInfo.Header);
+    if (EFI_ERROR (Status)) {
+      ASSERT_EFI_ERROR (Status);
+      return Status;
+    }
+  }
+
+  mProtectedVariableGlobal.Flags.WriteInit = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Update a variable with protection provided by this library.
+
+  If variable encryption is employed, the new variable data will be encrypted
+  before being written to NV variable storage.
+
+  A special variable, called "MetaDataHmacVar", will always be updated along
+  with variable being updated to reflect the changes (HMAC value) of all
+  protected valid variables. The only exceptions, currently, is variable
+  variable "VarErrorLog".
+
+  The buffer passed by NewVariable must be double of maximum variable size,
+  which allows to pass the "MetaDataHmacVar" back to caller along with encrypted
+  new variable data, if any. This can make sure the new variable data and
+  "MetaDataHmacVar" can be written at almost the same time to reduce the chance
+  of compromising the integrity.
+
+  If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
+  and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
+  case because of less variables in storage. NewVariable should be always passed
+  in to convey new "MetaDataHmacVar" back.
+
+  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
+                                      adding a new variable.
+  @param[in]      CurrVariableInDel   In-delete-transition copy of updating variable.
+  @param[in,out]  NewVariable         Buffer of new variable data.
+                                      Buffer of "MetaDataHmacVar" and new
+                                      variable (encrypted).
+  @param[in,out]  NewVariableSize     Size of NewVariable.
+                                      Size of (encrypted) NewVariable and
+                                      "MetaDataHmacVar".
+
+  @retval EFI_SUCCESS             The variable is updated with protection successfully.
+  @retval EFI_INVALID_PARAMETER   NewVariable is NULL.
+  @retval EFI_NOT_FOUND           Information missing to finish the operation.
+  @retval EFI_ABORTED             Failed to encrypt variable or calculate HMAC.
+  @retval EFI_NOT_READY           The RPMC device is not yet initialized.
+  @retval EFI_DEVICE_ERROR        The RPMC device has error in updating.
+  @retval EFI_ACCESS_DENIED       The given variable is not allowed to update.
+                                  Currently this only happens on updating
+                                  "MetaDataHmacVar" from code outside of this
+                                  library.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+  IN  OUT VARIABLE_HEADER  *CurrVariable,
+  IN      VARIABLE_HEADER  *CurrVariableInDel,
+  IN  OUT VARIABLE_HEADER  *NewVariable,
+  IN  OUT UINTN            *NewVariableSize
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+  VARIABLE_DIGEST                *VarDig;
+  VARIABLE_DIGEST                *CurrVarDig;
+  VARIABLE_DIGEST                *NewVarDig;
+  PROTECTED_VARIABLE_INFO        NewVarInfo;
+  PROTECTED_VARIABLE_INFO        NewHmacVarInfo;
+  UINTN                          VarSize;
+  UINT64                         UnprotectedVarIndex;
+
+  //
+  // Advance RPMC
+  //
+  Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Buffer for new variable is always needed, even this function is called to
+  // delete an existing one, because we need to pass the MetaDataHmacVar back
+  // which will be updated upon each variable addition or deletion.
+  //
+  if ((NewVariable == NULL) || (NewVariableSize == NULL)) {
+    ASSERT (NewVariable != NULL);
+    ASSERT (NewVariableSize != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetProtectedVariableGlobal (&Global);
+  ASSERT_EFI_ERROR (Status);
+  ContextIn = GET_CNTX (Global);
+
+  if (!Global->Flags.WriteReady && !Global->Flags.WriteInit) {
+    return EFI_NOT_READY;
+  }
+
+  VarSize             = 0;
+  CurrVarDig          = NULL;
+  NewVarDig           = NULL;
+  UnprotectedVarIndex = VAR_INDEX_INVALID;
+
+  //
+  // Check existing copy of the same variable.
+  //
+  if (CurrVariable != NULL) {
+    //
+    // Find local cached copy, if possible.
+    //
+    ZeroMem (&VarInfo, sizeof (VarInfo));
+    VarInfo.Buffer     = CurrVariable;
+    VarInfo.StoreIndex = VAR_INDEX_INVALID;
+    VarInfo.Flags.Auth = Global->Flags.Auth;
+
+    Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
+    ASSERT_EFI_ERROR (Status);
+
+    UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+    if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
+      CurrVarDig = VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]);
+    } else {
+      CurrVarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+    }
+
+    ASSERT (CurrVarDig != NULL);
+    CurrVarDig->State &= VAR_DELETED;
+  }
+
+  //
+  // The old copy of the variable might haven't been deleted completely.
+  //
+  if (CurrVariableInDel != NULL) {
+    //
+    // Find local cached copy, if possible.
+    //
+    ZeroMem (&VarInfo, sizeof (VarInfo));
+    VarInfo.Buffer     = CurrVariableInDel;
+    VarInfo.StoreIndex = VAR_INDEX_INVALID;
+    VarInfo.Flags.Auth = Global->Flags.Auth;
+
+    Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
+    ASSERT_EFI_ERROR (Status);
+
+    if (UnprotectedVarIndex == VAR_INDEX_INVALID) {
+      UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+    }
+
+    if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
+      VarDig = VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]);
+    } else {
+      VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+    }
+
+    if ((VarDig != NULL) && (VAR_DIG_ADR (VarDig) != VAR_INDEX_INVALID)) {
+      VarDig->State &= VAR_DELETED;
+
+      //
+      // Just need one node for the same variable. So remove the one
+      // in-del-transition.
+      //
+      if ((CurrVarDig != NULL) && (VarDig != CurrVarDig)) {
+        RemoveVariableDigestNode (Global, VarDig, TRUE);
+      } else {
+        CurrVarDig = VarDig;  // Reuse the one in-del-transition.
+      }
+    }
+  }
+
+  //
+  // New data of the variable or new variable to be added.
+  //
+  if (NewVariable != NULL) {
+    //
+    // Completely new variable?
+    //
+    if (UnprotectedVarIndex == VAR_INDEX_INVALID) {
+      ZeroMem (&VarInfo, sizeof (VarInfo));
+      VarInfo.Buffer     = NewVariable;
+      VarInfo.StoreIndex = VAR_INDEX_INVALID;
+      VarInfo.Flags.Auth = Global->Flags.Auth;
+
+      Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
+      ASSERT_EFI_ERROR (Status);
+
+      UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
+    }
+  }
+
+  //
+  // Reserve space for MetaDataHmacVar (before the new variable so
+  // that it can be written first).
+  //
+  ZeroMem (&NewVarInfo, sizeof (NewVarInfo));
+  ZeroMem (&NewHmacVarInfo, sizeof (NewHmacVarInfo));
+
+  //
+  // Put the MetaDataHmacVar at the beginning of buffer.
+  //
+  NewHmacVarInfo.Buffer = NewVariable;
+
+  if (*NewVariableSize == 0) {
+    //
+    // Delete variable (but not MetaDataHmacVar)
+    //
+    if (  (UnprotectedVarIndex != IndexHmacAdded)
+       && (UnprotectedVarIndex != IndexHmacInDel))
+    {
+      RemoveVariableDigestNode (Global, CurrVarDig, TRUE);
+    }
+
+    NewVarInfo.Buffer = NULL;
+  } else if (UnprotectedVarIndex >= IndexPlatformVar) {
+    //
+    // Add/update variable. Move new variable data to be after MetaDataHmacVar.
+    //
+    // TRICK: New MetaDataHmacVar will be put at the beginning of buffer
+    //        for new variable so that they can be written into non-volatile
+    //        variable storage in one call. This can avoid writing one variable
+    //        (NewHmacVarInfo) in the middle of writing another variable
+    //        (NewVarInfo), which will need two calls and introduce extra
+    //        complexities (from temp variable buffer reservation to variable
+    //        space reclaim, etc.) in current implementation of variable
+    //        services. The caller must make sure there's enough space in
+    //        variable buffer (i.e. at least 2 * MaxVariableSize).
+    //
+    NewVarInfo.Buffer = (VARIABLE_HEADER *)((UINTN)NewVariable
+                                            + GetMetaDataHmacVarSize (Global->Flags.Auth));
+    CopyMem ((VOID *)NewVarInfo.Buffer, (VOID *)NewVariable, *NewVariableSize);
+
+    NewVarInfo.StoreIndex = VAR_INDEX_INVALID;   // Skip offset calculation (it's new one)
+    NewVarInfo.Flags.Auth = Global->Flags.Auth;
+
+    Status = ContextIn->GetVariableInfo (&NewVarInfo);
+    ASSERT_EFI_ERROR (Status);
+
+    if (CurrVarDig != NULL) {
+      //
+      // Update existing variable. Re-use the node.
+      //
+      NewVarDig = CurrVarDig;
+    } else {
+      //
+      // Add new variable.
+      //
+      NewVarDig = CreateVariableDigestNode (
+                    NewVarInfo.Header.VariableName,
+                    NewVarInfo.Header.VendorGuid,
+                    (UINT16)NewVarInfo.Header.NameSize,
+                    (UINT32)NewVarInfo.Header.DataSize,
+                    NewVarInfo.Flags.Auth,
+                    Global
+                    );
+      if (NewVarDig == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      NewVarDig->Attributes = NewVarInfo.Header.Attributes;
+      if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
+        NewVarDig->Flags.Protected               = FALSE;
+        NewVarDig->Flags.Encrypted               = FALSE;
+        Global->Unprotected[UnprotectedVarIndex] = VAR_DIG_ADR (NewVarDig);
+      }
+
+      //
+      // copy new variable to CacheIndex
+      //
+      VarSize  =  VARIABLE_HEADER_SIZE (NewVarInfo.Flags.Auth);
+      VarSize += NewVarInfo.Header.NameSize + GET_PAD_SIZE (NewVarInfo.Header.NameSize);
+      VarSize += NewVarInfo.Header.DataSize + GET_PAD_SIZE (NewVarInfo.Header.DataSize);
+      VarSize  = HEADER_ALIGN (VarSize);
+      CopyMem (GET_BUFR (NewVarDig->CacheIndex), GET_BUFR (NewVarInfo.Buffer), VarSize);
+      InsertVariableDigestNode (Global, NewVarDig, NULL);
+    }
+  }
+
+  if (  (UnprotectedVarIndex == IndexHmacAdded)
+     || (UnprotectedVarIndex == IndexHmacInDel))
+  {
+    //
+    // MetaDataHmacVar should be managed only by this library. It's not
+    // supposed to be updated by external users of variable service. The only
+    // exception is that deleting it (not really delete but refresh the HMAC
+    // value against RPMC+1) is allowed before WriteInit, as a way to always
+    // increment RPMC once in current boot before any variable updates.
+    //
+    if ((NewVarInfo.Buffer != NULL) || Global->Flags.WriteInit) {
+      return EFI_ACCESS_DENIED;
+    }
+  } else {
+    //
+    // Do encryption, if enabled.
+    //
+    if ((NewVarDig != NULL) && (NewVarInfo.Buffer != NULL)) {
+      Status = UpdateVariableInternal (Global, &NewVarInfo, NewVarDig);
+      if (EFI_ERROR (Status)) {
+        ASSERT_EFI_ERROR (Status);
+        return Status;
+      }
+    }
+  }
+
+  //
+  // Refresh MetaDataHmacVar.
+  //
+  Status = RefreshVariableMetadataHmac (Global, NULL, &NewHmacVarInfo);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // Return size for both MetaDataHmacVar and added/updated one.
+  //
+  VarSize          = VARIABLE_SIZE (&NewHmacVarInfo);
+  *NewVariableSize = HEADER_ALIGN (VarSize);
+  if (NewVarInfo.Buffer != NULL) {
+    VarSize = VARIABLE_SIZE (&NewVarInfo);
+    VarSize = HEADER_ALIGN (VarSize);
+
+    if (VarSize > GET_CNTX (Global)->MaxVariableSize) {
+      return EFI_BAD_BUFFER_SIZE;
+    }
+
+    *NewVariableSize += VarSize;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Finalize a variable updating after it's written to NV variable storage
+  successfully.
+
+  This usually includes works like increasing RPMC, synchronizing local cache,
+  updating new position of "MetaDataHmacVar", deleting old copy of "MetaDataHmacVar"
+  completely, etc.
+
+  @param[in]      NewVariable       Buffer of new variables and MetaDataHmacVar.
+  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
+  @param[in]      StoreIndex        StoreIndex to NV variable storage from where the new
+                                    variable and MetaDataHmacVar have been written.
+
+  @retval EFI_SUCCESS         No problem in winding up the variable write operation.
+  @retval Others              Failed to updating state of old copy of updated
+                              variable, or failed to increase RPMC, etc.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+  IN  VARIABLE_HEADER  *NewVariable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex
+  )
+{
+  EFI_STATUS                     Status;
+  PROTECTED_VARIABLE_INFO        VarInfo;
+  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
+  PROTECTED_VARIABLE_GLOBAL      *Global;
+  UNPROTECTED_VARIABLE_INDEX     Index;
+  VARIABLE_DIGEST                *VarDig;
+  VOID                           *Buffer;
+  UINTN                          VarSize;
+  UINTN                          NewVarSize;
+
+  Status = GetProtectedVariableGlobal (&Global);
+  ASSERT_EFI_ERROR (Status);
+  ContextIn = GET_CNTX (Global);
+
+  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+  VarInfo.Buffer     = NewVariable;
+  VarInfo.StoreIndex = VAR_INDEX_INVALID;
+  VarInfo.Flags.Auth = Global->Flags.Auth;
+
+  Status = ContextIn->GetVariableInfo (&VarInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  Index = CheckKnownUnprotectedVariable (Global, &VarInfo);
+  if (Index < UnprotectedVarIndexMax) {
+    VarDig = VAR_DIG_PTR (Global->Unprotected[Index]);
+  } else {
+    VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+  }
+
+  if (Index == IndexHmacAdded) {
+    //
+    // Advance the RPMC to let it match new MetaDataHmacVar.
+    //
+    Status = IncrementMonotonicCounter (RPMC_COUNTER_2);
+    ASSERT_EFI_ERROR (Status);
+
+    if ((VarDig->StoreIndex != VAR_INDEX_INVALID) && (VarDig->State != VAR_ADDED)) {
+      ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+      VarInfo.StoreIndex = VarDig->StoreIndex;  // Still point to old copy
+      VarInfo.Flags.Auth = Global->Flags.Auth;
+
+      //
+      // Delete variable completely.
+      //
+      Status = ContextIn->GetVariableInfo (&VarInfo);
+      ASSERT_EFI_ERROR (Status);
+
+      if (  (VarInfo.Buffer->State == VAR_ADDED)
+         || (VarInfo.Buffer->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
+      {
+        VarInfo.Buffer->State &= VAR_DELETED;
+        Status                 = ContextIn->UpdateVariableStore (
+                                              &VarInfo,
+                                              OFFSET_OF (VARIABLE_HEADER, State),
+                                              sizeof (VarInfo.Buffer->State),
+                                              &VarInfo.Buffer->State
+                                              );
+        if (EFI_ERROR (Status)) {
+          ASSERT_EFI_ERROR (Status);
+          return Status;
+        }
+      }
+    }
+  }
+
+  VarDig->StoreIndex = StoreIndex;
+  VarDig->State      = VAR_ADDED;
+
+  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+  VarInfo.Buffer     = NULL;
+  VarInfo.StoreIndex = VarDig->StoreIndex;
+  VarInfo.Flags.Auth = Global->Flags.Auth;
+  Status             = ContextIn->GetVariableInfo (&VarInfo);
+
+  //
+  // Check if cache pool need re-allocation due to variable size increase
+  //
+  VarSize  =  VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
+  VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+  VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+  VarSize  = HEADER_ALIGN (VarSize);
+
+  NewVarSize  =  VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth);
+  NewVarSize += VarInfo.Header.NameSize + GET_PAD_SIZE (VarInfo.Header.NameSize);
+  NewVarSize += VarInfo.Header.DataSize + GET_PAD_SIZE (VarInfo.Header.DataSize);
+  NewVarSize  = HEADER_ALIGN (NewVarSize);
+
+  if (VarSize < NewVarSize) {
+    if (VarDig->Flags.Freeable == TRUE) {
+      FreePool (GET_BUFR (VarDig->CacheIndex));
+    }
+
+    Buffer = AllocatePool (NewVarSize);
+    if (Buffer != NULL) {
+      VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+    } else {
+      ASSERT (FALSE);
+      return EFI_ABORTED;
+    }
+  }
+
+  //
+  // Update cached copy.
+  //
+  CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize);
+
+  //
+  // Check if there is consecutive variable as part of the write or
+  // is it just the MetaDataHmacVar variable
+  //
+  if (NewVarSize < VariableSize) {
+    //
+    // Advance to consecutive Variable
+    //
+    NewVariable = GET_BUFR (GET_ADRS (NewVariable) + NewVarSize);
+
+    //
+    // Update the StoreIndex of consecutive Variable
+    //
+    ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+    VarInfo.Buffer     = NULL;
+    VarInfo.StoreIndex = VarDig->StoreIndex;
+    VarInfo.Flags.Auth = Global->Flags.Auth;
+    Status             = ContextIn->GetNextVariableInfo (&VarInfo);
+    StoreIndex         = VarInfo.StoreIndex;
+
+    //
+    // The new StoreIndex does not exist in the variable digest.
+    // It is yet to be updated.
+    // Therefore, find variable by Name & Guid instead.
+    //
+    VarInfo.StoreIndex = VAR_INDEX_INVALID;
+    VarDig             = FindVariableInternal (Global, &VarInfo, FALSE);
+
+    //
+    // Check if cache pool need re-allocation due to variable size increase
+    //
+    VarSize  =  VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
+    VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
+    VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
+    VarSize  = HEADER_ALIGN (VarSize);
+
+    NewVarSize  =  VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth);
+    NewVarSize += VarInfo.Header.NameSize + GET_PAD_SIZE (VarInfo.Header.NameSize);
+    NewVarSize += VarInfo.Header.DataSize + GET_PAD_SIZE (VarInfo.Header.DataSize);
+    NewVarSize  = HEADER_ALIGN (NewVarSize);
+
+    if (VarSize < NewVarSize) {
+      if (VarDig->Flags.Freeable == TRUE) {
+        FreePool (GET_BUFR (VarDig->CacheIndex));
+      }
+
+      Buffer = AllocatePool (NewVarSize);
+      if (Buffer != NULL) {
+        VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+      } else {
+        ASSERT (FALSE);
+        return EFI_ABORTED;
+      }
+    }
+
+    //
+    // Update cached copy.
+    //
+    CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize);
+    VarDig->StoreIndex = StoreIndex;
+  }
+
+  return Status;
+}
+
+/**
+  Refresh variable information changed by variable service.
+
+  @param[in]  Variable         Pointer to buffer of the updated variable.
+  @param[in]  VariableSize     Size of variable pointed by Variable.
+  @param[in]  StoreIndex       New index of the variable in store.
+  @param[in]  RefreshData      Flag to indicate if the variable has been updated.
+
+  @return EFI_SUCCESS     No error occurred in updating.
+  @return EFI_NOT_FOUND   The given variable was not found in
+                          ProtectedVariableLib.
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibRefresh (
+  IN  VARIABLE_HEADER  *Variable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex,
+  IN  BOOLEAN          RefreshData
+  )
+{
+  EFI_STATUS                 Status;
+  PROTECTED_VARIABLE_INFO    VarInfo;
+  PROTECTED_VARIABLE_GLOBAL  *Global;
+  VARIABLE_DIGEST            *VarDig;
+
+  (VOID)GetProtectedVariableGlobal (&Global);
+
+  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
+  VarInfo.Buffer     = Variable;
+  VarInfo.StoreIndex = VAR_INDEX_INVALID;
+  VarInfo.Flags.Auth = Global->Flags.Auth;
+
+  Status = GET_CNTX (Global)->GetVariableInfo (&VarInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
+  if (VarDig == NULL) {
+    ASSERT (VarDig != NULL);
+    return EFI_NOT_FOUND;
+  }
+
+  if (StoreIndex != VAR_INDEX_INVALID) {
+    VarDig->StoreIndex = StoreIndex;
+  }
+
+  if (RefreshData) {
+    if (VarDig->CacheIndex == VAR_INDEX_INVALID) {
+      VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)
+                           AllocatePool (MAX_VARIABLE_SIZE);
+    }
+
+    CopyMem (GET_BUFR (VarDig->CacheIndex), Variable, VariableSize);
+  }
+
+  //
+  // Information should stay the same other than following ones.
+  //
+  VarDig->State    = VarInfo.Header.State;
+  VarDig->DataSize = (UINT32)VarInfo.Header.DataSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Determine if the variable is the HMAC variable
+
+  @param VariableName   Pointer to variable name.
+
+  @return TRUE      Variable is HMAC variable
+  @return FALSE     Variable is not HMAC variable
+
+**/
+BOOLEAN
+ProtectedVariableLibIsHmac (
+  IN CHAR16  *VariableName
+  )
+{
+  INTN  Result;
+
+  Result = StrnCmp (
+             METADATA_HMAC_VARIABLE_NAME,
+             VariableName,
+             METADATA_HMAC_VARIABLE_NAME_SIZE
+             );
+
+  if (Result == 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
new file mode 100644
index 000000000000..4591d1cd59e5
--- /dev/null
+++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
@@ -0,0 +1,233 @@
+/** @file
+  Implemention of ProtectedVariableLib for BootService/Runtime use cases.
+
+Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include "Library/MemoryAllocationLib.h"
+#include "Library/UefiBootServicesTableLib.h"
+#include "Library/UefiRuntimeLib.h"
+#include "ProtectedVariableInternal.h"
+
+EFI_EVENT  mVaChangeEvent = NULL;
+
+PROTECTED_VARIABLE_CONTEXT_IN  mRtVariableContextIn = {
+  PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
+  sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
+  0,
+  FromRuntimeModule,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+PROTECTED_VARIABLE_GLOBAL  mRtProtectedVariableGlobal = {
+  PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
+  sizeof (PROTECTED_VARIABLE_GLOBAL),
+  { 0 },
+  { 0 },
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  { 0,                                          0,  0 },
+  0,
+  0,
+  { 0,                                          0,  0, 0, 0, 0}
+};
+
+/**
+
+  Get global data structure used to process protected variable.
+
+  @param[out]   Global      Pointer to global configuration data.
+
+  @retval EFI_SUCCESS         Get requested structure successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProtectedVariableGlobal (
+  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
+  )
+{
+  if (Global != NULL) {
+    mRtProtectedVariableGlobal.ContextIn = GET_ADRS (&mRtVariableContextIn);
+    *Global                              = &mRtProtectedVariableGlobal;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  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
+VirtualAddressChangeEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  if (mRtVariableContextIn.FindVariableSmm != NULL) {
+    EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.FindVariableSmm);
+  }
+
+  if (mRtVariableContextIn.GetVariableInfo != NULL) {
+    EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.GetVariableInfo);
+  }
+
+  if (mRtVariableContextIn.GetNextVariableInfo != NULL) {
+    EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.GetNextVariableInfo);
+  }
+
+  if (mRtVariableContextIn.UpdateVariableStore != NULL) {
+    EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.UpdateVariableStore);
+  }
+
+  EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn);
+  if (mRtProtectedVariableGlobal.VariableCache != 0) {
+    EfiConvertPointer (0x0, (VOID **)&mRtProtectedVariableGlobal.VariableCache);
+  }
+
+  EfiConvertPointer (0x0, (VOID **)&mRtProtectedVariableGlobal);
+}
+
+/**
+
+  Initialization for protected variable services.
+
+  If this initialization failed upon any error, the whole variable services
+  should not be used.  A system reset might be needed to re-construct NV
+  variable storage to be the default state.
+
+  @param[in]  ContextIn   Pointer to variable service context needed by
+                          protected variable.
+
+  @retval EFI_SUCCESS               Protected variable services are ready.
+  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something missing or
+                                    mismatching in the content in ContextIn.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibInitialize (
+  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
+  )
+{
+  if (  (ContextIn == NULL)
+     || (ContextIn->StructVersion != PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
+     || (ContextIn->FindVariableSmm == NULL)
+     || (ContextIn->GetVariableInfo == NULL))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CopyMem (&mRtVariableContextIn, ContextIn, sizeof (mRtVariableContextIn));
+
+  //
+  // Register the event to convert the pointer for runtime.
+  //
+  gBS->CreateEventEx (
+         EVT_NOTIFY_SIGNAL,
+         TPL_NOTIFY,
+         VirtualAddressChangeEvent,
+         NULL,
+         &gEfiEventVirtualAddressChangeGuid,
+         &mVaChangeEvent
+         );
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Prepare for variable update.
+
+  Not supported in DXE phase.
+
+  @retval EFI_UNSUPPORTED         Updating variable is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteInit (
+  VOID
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Update a variable with protection provided by this library.
+
+  Not supported in DXE phase.
+
+  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
+                                      adding a new variable.
+  @param[in]      CurrVariableInDel   In-delete-transition copy of updating variable.
+  @param[in,out]  NewVariable         Buffer of new variable data or
+                                      Buffer of "MetaDataHmacVar" and new variable (encrypted).
+  @param[in,out]  NewVariableSize     Size of NewVariable or
+                                      Size of (encrypted) NewVariable and "MetaDataHmacVar".
+
+  @retval EFI_UNSUPPORTED             Not support updating variable.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibUpdate (
+  IN  OUT VARIABLE_HEADER  *CurrVariable,
+  IN      VARIABLE_HEADER  *CurrVariableInDel,
+  IN  OUT VARIABLE_HEADER  *NewVariable,
+  IN  OUT UINTN            *NewVariableSize
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Finalize a variable updating after it's written to NV variable storage
+  successfully.
+
+  (Not supported for BootService/Runtime use cases.)
+
+  @param[in]      NewVariable       Buffer of new variables and MetaDataHmacVar.
+  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
+  @param[in]      StoreIndex        StoreIndex to NV variable storage from where the new
+                                    variable and MetaDataHmacVar have been written.
+
+  @retval EFI_UNSUPPORTED           Not supported for BootService/Runtime use cases.
+
+**/
+EFI_STATUS
+EFIAPI
+ProtectedVariableLibWriteFinal (
+  IN  VARIABLE_HEADER  *NewVariable,
+  IN  UINTN            VariableSize,
+  IN  UINT64           StoreIndex
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (17 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services Judah Vang
@ 2022-11-06  7:35 ` Judah Vang
  2022-11-22  8:05   ` Wang, Jian J
  2022-12-09  8:03 ` [edk2-devel] [PATCH v5 00/19] UEFI variable protection Yao, Jiewen
       [not found] ` <172F11512E3044E7.1612@groups.io>
  20 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-06  7:35 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Jiewen Yao, Nishant C Mistry

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

Add references to the different *ProtectedVariableLib.inf.
Also add references to VariableKeyLibNull.inf,
EncryptionVariableLibNull.inf, ProtectedVariableNull.inf.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
Signed-off-by: Judah Vang <judah.vang@intel.com>
---
 SecurityPkg/SecurityPkg.dsc | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc
index 6bf53c565882..3134b103ff53 100644
--- a/SecurityPkg/SecurityPkg.dsc
+++ b/SecurityPkg/SecurityPkg.dsc
@@ -1,7 +1,7 @@
 ## @file
 #  Security Module Package for All Architectures.
 #
-# Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR>
 # (C) Copyright 2015-2020 Hewlett Packard Enterprise Development LP<BR>
 # Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -67,8 +67,11 @@ [LibraryClasses]
   TcgStorageCoreLib|SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf
   TcgStorageOpalLib|SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
   ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+
+  # These should be Null by default
   VariableKeyLib|SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf
   RpmcLib|SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf
+  EncryptionVariableLib|SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
   TcgEventLogRecordLib|SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.inf
   MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
   SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
@@ -261,9 +264,17 @@ [Components]
   #
   # Variable Confidentiality & Integrity
   #
+  SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
+  SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
+  SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
+  SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
+  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
+  SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
+
   SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf
   SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf
   SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf
+  SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
 
   #
   # Other
-- 
2.35.1.windows.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
  2022-11-06  7:34 ` [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality Judah Vang
@ 2022-11-14  3:43   ` Wang, Jian J
       [not found]   ` <1727569A8ECB6F9D.19699@groups.io>
  1 sibling, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-14  3:43 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C

Hi Judah,

See my comments (starting with [JianJW]) inline below.


> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
> Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V5: Add PEI Variable Protection into a new directory and leave the
> existing PEI Variable unchanged.
> 
> V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo()
> and SafeUint64ToUint32().
> 
> V1: Provide new APIs for retrieving variable information.
> Add new function stubs for retrieving Protected
> variable information.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> Acked-by: Hao A Wu <hao.a.wu@intel.com>
> ---
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf      |  79 ++
>  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h           | 225 +++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h    | 309
> +++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h      | 116 +++
>  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c           | 628
> +++++++++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c    | 941
> ++++++++++++++++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c      | 307
> +++++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni      |  16 +
>  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni |  14 +
>  9 files changed, 2635 insertions(+)
> 
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> new file mode 100644
> index 000000000000..953a7c6b884f
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> @@ -0,0 +1,79 @@
> +## @file
> +#  Implements ReadOnly Variable Services required by PEIM and installs PEI
> ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +#
> +#  This module implements ReadOnly Variable Services required by PEIM and
> installs PEI ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +#
> +#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PeiVariable
> +  MODULE_UNI_FILE                = PeiVariable.uni
> +  FILE_GUID                      = 8D104D19-593B-4DDF-81CF-8168A9EDE9C7
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = PeimInitializeVariableServices
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 EBC
> +#
> +
> +[Sources]
> +  Variable.c
> +  Variable.h
> +  VariableStore.c
> +  VariableStore.h
> +  VariableParsing.c
> +  VariableParsing.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  PcdLib
> +  HobLib
> +  PeimEntryPoint
> +  DebugLib
> +  PeiServicesTablePointerLib
> +  PeiServicesLib
> +  SafeIntLib
> +  VariableFlashInfoLib
> +  ProtectedVariableLib
> +
> +[Guids]
> +  ## CONSUMES             ## GUID # Variable store header
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  gEfiAuthenticatedVariableGuid
> +  ## SOMETIMES_CONSUMES   ## GUID # Variable store header
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  gEfiVariableGuid
> +  ## SOMETIMES_PRODUCES   ## HOB
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  gEfiVariableIndexTableGuid
> +  gEfiSystemNvDataFvGuid            ## SOMETIMES_CONSUMES   ## GUID
> +  ## SOMETIMES_CONSUMES   ## HOB
> +  ## CONSUMES             ## GUID # Dependence
> +  gEdkiiFaultTolerantWriteGuid
> +
> +[Ppis]
> +  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
> +  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ##
> SOMETIMES_CONSUMES
> +
> +[Depex]
> +  gEdkiiFaultTolerantWriteGuid
> +
> +# [BootMode]
> +# RECOVERY_FULL             ## SOMETIMES_CONSUMES
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  PeiVariableExtra.uni
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> new file mode 100644
> index 000000000000..1bdbdd2b807b
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> @@ -0,0 +1,225 @@
> +/** @file
> +  The internal header file includes the common header files, defines
> +  internal structure and functions used by PeiVariable module.
> +
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_H_
> +#define PEI_VARIABLE_H_
> +
> +#include <PiPei.h>
> +#include <Ppi/ReadOnlyVariable2.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <Library/HobLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PeiServicesTablePointerLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/SafeIntLib.h>
> +#include <Library/VariableFlashInfoLib.h>
> +#include <Library/ProtectedVariableLib.h>
> +
> +#include <Guid/VariableFormat.h>
> +#include <Guid/VariableIndexTable.h>
> +#include <Guid/SystemNvDataGuid.h>
> +#include <Guid/FaultTolerantWrite.h>
> +#include <Guid/ProtectedVariable.h>
> +
> +typedef enum {
> +  VariableStoreTypeHob,
> +  VariableStoreTypeNv,
> +  VariableStoreTypeMax
> +} VARIABLE_STORE_TYPE;
> +
> +typedef struct {
> +  VARIABLE_STORE_HEADER                   *VariableStoreHeader;
> +  VARIABLE_INDEX_TABLE                    *IndexTable;
> +  //
> +  // If it is not NULL, it means there may be an inconsecutive variable whose
> +  // partial content is still in NV storage, but another partial content is backed
> up
> +  // in spare block.
> +  //
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA    *FtwLastWriteData;
> +  BOOLEAN                                 AuthFlag;
> +} VARIABLE_STORE_INFO;
> +
> +//
> +// Functions
> +//
> +
> +/**
> +  Provide the functionality of the variable services.
> +
> +  @param  FileHandle  Handle of the file being invoked.
> +                      Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
> +  @param  PeiServices  General purpose services available to every PEIM.
> +
> +  @retval EFI_SUCCESS  If the interface could be successfully installed
> +  @retval Others       Returned from PeiServicesInstallPpi()
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeimInitializeVariableServices (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  );
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariable (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  );
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +
> +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableName (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  );
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  );
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +
> +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  );
> +
> +#endif

[JianJW] 
a. The function header comments for PeiGetVariableEx/PeiGetNextVariableNameEx
    are the same as non-ex version of PeiGetVariable/PeiGetNextVariableName. This
    doesn't do any help to users to get know about what're the differences between
    these two version of functions. Please update the Ex version function header to
    give more accurate descriptions.
b. Please update the function header in Variable.c as well.

> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> new file mode 100644
> index 000000000000..d7af6cb6e8be
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> @@ -0,0 +1,309 @@
> +/** @file
> +  The internal header file includes the common header files, defines
> +  internal structure and functions used by PeiVariable module.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_PARSING_H_
> +#define PEI_VARIABLE_PARSING_H_
> +
> +#include "Variable.h"
> +
> +/**
> +
> +  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
> +  );
> +
> +/**
> +  This code checks if variable header is valid or not.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +
> +  @retval TRUE      Variable header is valid.
> +  @retval FALSE     Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> +  IN  VARIABLE_HEADER  *Variable
> +  );
> +
> +/**
> +  This code gets the pointer to the next variable header.
> +
> +  @param[in]  StoreInfo         Pointer to variable store info structure.
> +  @param[in]  Variable          Pointer to the Variable Header.
> +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> consecutive content.
> +
> +  @return  A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> +  IN  VARIABLE_HEADER      *Variable,
> +  IN  VARIABLE_HEADER      *VariableHeader
> +  );
> +
> +/**
> +  This code gets the pointer to the variable guid.
> +
> +  @param[in]  Variable   Pointer to the Variable Header.
> +  @param[in]  AuthFlag   Authenticated variable flag.
> +
> +  @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the pointer to the variable name.
> +
> +  @param[in]   Variable  Pointer to the Variable Header.
> +  @param[in]   AuthFlag  Authenticated variable flag.
> +
> +  @return  A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the size of name of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the size of data of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  This code gets the pointer to the variable data.
> +
> +  @param[in]   Variable         Pointer to the Variable Header.
> +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]   AuthFlag         Authenticated variable flag.
> +
> +  @return  A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  VARIABLE_HEADER  *VariableHeader,
> +  IN  BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +  Get variable header that has consecutive content.
> +
> +  @param[in]  StoreInfo      Pointer to variable store info structure.
> +  @param[in]  Variable       Pointer to the Variable Header.
> +  @param[out] VariableHeader Pointer to Pointer to the Variable Header that
> has consecutive content.
> +
> +  @retval TRUE          Variable header is valid.
> +  @retval FALSE         Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN VARIABLE_HEADER      *Variable,
> +  OUT VARIABLE_HEADER     **VariableHeader
> +  );
> +
> +/**
> +  This code gets the size of variable header.
> +
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> +  IN  BOOLEAN  AuthFlag
> +  );
> +
> +/**
> +  Get variable name or data to output buffer.
> +
> +  @param[in]  StoreInfo     Pointer to variable store info structure.
> +  @param[in]  NameOrData    Pointer to the variable name/data that may be
> inconsecutive.
> +  @param[in]  Size          Variable name/data size.
> +  @param[out] Buffer        Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN UINT8                *NameOrData,
> +  IN UINTN                Size,
> +  OUT UINT8               *Buffer
> +  );
> +
> +/**
> +  This function compares a variable with variable entries in database.
> +
> +  @param[in]  StoreInfo     Pointer to variable store info structure.
> +  @param[in]  Variable      Pointer to the variable in our database
> +  @param[in]  VariableHeader Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]  VariableName  Name of the variable to compare to 'Variable'
> +  @param[in]  VendorGuid    GUID of the variable to compare to 'Variable'
> +  @param[out] PtrTrack      Variable Track Pointer structure that contains
> Variable Information.
> +
> +  @retval EFI_SUCCESS    Found match variable
> +  @retval EFI_NOT_FOUND  Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> +  IN  VARIABLE_HEADER         *Variable,
> +  IN  VARIABLE_HEADER         *VariableHeader,
> +  IN  CONST CHAR16            *VariableName,
> +  IN  CONST EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  );
> +
> +/**
> +
> +  Retrieve details of the variable next to given variable within VariableStore.
> +
> +  If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> +  VariableStart and/or VariableEnd can be given optionally for the situation
> +  in which the valid storage space is smaller than the VariableStore->Size.
> +  This usually happens when PEI variable services make a compact variable
> +  cache to save memory, which cannot make use VariableStore->Size to
> determine
> +  the correct variable storage range.

[JianJW] This part doesn't match the function implementation any more.
It can be removed.

> +
> +  @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->Address 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->Address 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->Address,
> +  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
> +  );
> +
> +/**
> +
> +  Find variable specified with input parameters.
> +
> +  @param[in] StoreInfo             Pointer to variable information.
> +  @param[in] VariableName          Pointer to variable name.
> +  @param[in] VendorGuid            Pointer to variable GUID.
> +  @param[in] PtrTrack              Pointer to variable track.
> +
> +  @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
> +FindVariableEx (
> +  IN VARIABLE_STORE_INFO      *StoreInfo,
> +  IN CONST CHAR16             *VariableName,
> +  IN CONST EFI_GUID           *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> new file mode 100644
> index 000000000000..6e2f6f939bab
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> @@ -0,0 +1,116 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.

[JianJW] typo: ' Varaiable2' -> ' Variable2'

> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PEI_VARIABLE_STORE_H_
> +#define PEI_VARIABLE_STORE_H_
> +
> +/**
> +  Get variable store status.
> +
> +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @retval  EfiRaw      Variable store is raw
> +  @retval  EfiValid    Variable store is valid
> +  @retval  EfiInvalid  Variable store is invalid
> +
> +**/
> +VARIABLE_STORE_STATUS
> +GetVariableStoreStatus (
> +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> +  );
> +
> +/**
> +  Reports HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> +  VOID
> +  );
> +
> +/**
> +  Get HOB variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  );
> +
> +/**
> +  Get NV variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +  @param[out] VariableStoreHeader   Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> +  );
> +
> +/**
> +  Return the variable store header and the store info based on the Index.
> +
> +  @param[in]  Type       The type of the variable store.
> +  @param[out] StoreInfo  Return the store info.
> +
> +  @return  Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> +  IN VARIABLE_STORE_TYPE   Type,
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  );
> +
> +/**
> +  Make a cached copy of NV variable storage.
> +
> +  To save memory in PEI phase, only valid variables are copied into cache.
> +  An IndexTable could be used to store the offset (relative to NV storage
> +  base) of each copied variable, in case we need to restore the storage
> +  as the same (valid) variables layout as in original one.
> +
> +  Variables with valid format and following state can be taken as valid:
> +    - with state VAR_ADDED;
> +    - with state VAR_IN_DELETED_TRANSITION but without the same variable
> +      with state VAR_ADDED;
> +    - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable
> +      MetaDataHmacVar.
> +
> +  @param[out]     StoreCacheBase    Base address of variable storage cache.
> +  @param[in,out]  StoreCacheSize    Size of space in StoreCacheBase.
> +  @param[out]     IndexTable        Buffer of index (offset) table with entries of
> +                                    VariableNumber.
> +  @param[out]     VariableNumber    Number of valid variables.
> +  @param[out]     AuthFlag          Aut-variable indicator.
> +
> +  @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or
> StoreCacheBase.
> +  @return EFI_VOLUME_CORRUPTED  Invalid or no NV variable storage found.
> +  @return EFI_BUFFER_TOO_SMALL  StoreCacheSize is smaller than needed.
> +  @return EFI_SUCCESS           NV variable storage is cached successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitNvVariableStore (
> +  OUT  EFI_PHYSICAL_ADDRESS  StoreCacheBase OPTIONAL,
> +  IN OUT  UINT32             *StoreCacheSize,
> +  OUT  UINT32                *IndexTable OPTIONAL,
> +  OUT  UINT32                *VariableNumber OPTIONAL,
> +  OUT  BOOLEAN               *AuthFlag OPTIONAL
> +  );
> +
> +#endif
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> new file mode 100644
> index 000000000000..ce790946626e
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> @@ -0,0 +1,628 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.

[JianJW] typo: ' Varaiable2' -> ' Variable2'

> +
> +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) Microsoft Corporation.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Variable.h"
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> +
> +//
> +// Module globals
> +//
> +EFI_PEI_READ_ONLY_VARIABLE2_PPI  mVariablePpi = {
> +  PeiGetVariableEx,
> +  PeiGetNextVariableNameEx
> +};
> +
> +EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
> +  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +  &gEfiPeiReadOnlyVariable2PpiGuid,
> +  &mVariablePpi
> +};
> +
> +/**
> +  Provide the functionality of the variable services.
> +
> +  @param  FileHandle   Handle of the file being invoked.
> +                       Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
> +  @param  PeiServices  General purpose services available to every PEIM.
> +
> +  @retval EFI_SUCCESS  If the interface could be successfully installed
> +  @retval Others       Returned from PeiServicesInstallPpi()
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeimInitializeVariableServices (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
> +
> +  //
> +  // If protected variable services are not supported, EFI_UNSUPPORTED should
> +  // be always returned. Check it here.
> +  //
> +  ContextIn.StructVersion =
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> +  ContextIn.StructSize    = sizeof (ContextIn);
> +
> +  ContextIn.MaxVariableSize             = 0;
> +  ContextIn.VariableServiceUser         = FromPeiModule;
> +  ContextIn.GetVariableInfo             = GetVariableInfo;
> +  ContextIn.GetNextVariableInfo         = GetNextVariableInfo;
> +  ContextIn.FindVariableSmm             = NULL;
> +  ContextIn.UpdateVariableStore         = NULL;
> +  ContextIn.UpdateVariable              = NULL;
> +  ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
> +
> +  Status = ProtectedVariableLibInitialize (&ContextIn);
> +  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> +    return Status;
> +  }
> +
> +  return PeiServicesInstallPpi (&mPpiListVariable);
> +}
> +
> +/**
> +  Find the variable in the specified variable store.
> +
> +  @param  StoreInfo           Pointer to the store info structure.
> +  @param  VariableName        Name of the variable to be found
> +  @param  VendorGuid          Vendor GUID to be found.
> +  @param  PtrTrack            Variable Track Pointer structure that contains
> Variable Information.
> +
> +  @retval  EFI_SUCCESS            Variable found successfully
> +  @retval  EFI_NOT_FOUND          Variable not found
> +  @retval  EFI_INVALID_PARAMETER  Invalid variable name
> +
> +**/
> +EFI_STATUS
> +FindVariableEx (
> +  IN VARIABLE_STORE_INFO      *StoreInfo,
> +  IN CONST CHAR16             *VariableName,
> +  IN CONST EFI_GUID           *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  )
> +{
> +  VARIABLE_HEADER        *Variable;
> +  VARIABLE_HEADER        *LastVariable;
> +  VARIABLE_HEADER        *MaxIndex;
> +  UINTN                  Index;
> +  UINTN                  Offset;
> +  BOOLEAN                StopRecord;
> +  VARIABLE_HEADER        *InDeletedVariable;
> +  VARIABLE_STORE_HEADER  *VariableStoreHeader;
> +  VARIABLE_INDEX_TABLE   *IndexTable;
> +  VARIABLE_HEADER        *VariableHeader;
> +
> +  VariableStoreHeader = StoreInfo->VariableStoreHeader;
> +
> +  if (VariableStoreHeader == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (~VariableStoreHeader->Size == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  IndexTable         = StoreInfo->IndexTable;
> +  PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
> +  PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader);
> +
> +  InDeletedVariable = NULL;
> +
> +  //
> +  // No Variable Address equals zero, so 0 as initial value is safe.
> +  //
> +  MaxIndex       = NULL;
> +  VariableHeader = NULL;
> +
> +  if (IndexTable != NULL) {
> +    //
> +    // traverse the variable index table to look for varible.
> +    // The IndexTable->Index[Index] records the distance of two neighbouring
> VAR_ADDED type variables.
> +    //
> +    for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
> +      ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
> +      Offset  += IndexTable->Index[Index];
> +      MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset);
> +      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
> +      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader,
> VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
> +        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> VAR_ADDED)) {
> +          InDeletedVariable = PtrTrack->CurrPtr;
> +        } else {
> +          return EFI_SUCCESS;
> +        }
> +      }
> +    }
> +
> +    if (IndexTable->GoneThrough != 0) {
> +      //
> +      // If the table has all the existing variables indexed, return.
> +      //
> +      PtrTrack->CurrPtr = InDeletedVariable;
> +      return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
> +    }
> +  }
> +
> +  if (MaxIndex != NULL) {
> +    //
> +    // HOB exists but the variable cannot be found in HOB
> +    // If not found in HOB, then let's start from the MaxIndex we've found.
> +    //
> +    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
> +    LastVariable = MaxIndex;
> +  } else {
> +    //
> +    // Start Pointers for the variable.
> +    // Actual Data Pointer where data can be written.
> +    //
> +    Variable     = PtrTrack->StartPtr;
> +    LastVariable = PtrTrack->StartPtr;
> +  }
> +
> +  //
> +  // Find the variable by walk through variable store
> +  //
> +  StopRecord = FALSE;
> +  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
> +    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> +      //
> +      // Record Variable in VariableIndex HOB
> +      //
> +      if ((IndexTable != NULL) && !StopRecord) {
> +        Offset = (UINTN)Variable - (UINTN)LastVariable;
> +        if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index)
> / sizeof (IndexTable->Index[0]))) {
> +          //
> +          // Stop to record if the distance of two neighbouring VAR_ADDED
> variable is larger than the allowable scope(UINT16),
> +          // or the record buffer is full.
> +          //
> +          StopRecord = TRUE;
> +        } else {
> +          IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;
> +          LastVariable                            = Variable;
> +        }
> +      }
> +
> +      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader,
> VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
> +        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> VAR_ADDED)) {
> +          InDeletedVariable = PtrTrack->CurrPtr;
> +        } else {
> +          return EFI_SUCCESS;
> +        }
> +      }
> +    }
> +
> +    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
> +  }
> +
> +  //
> +  // If gone through the VariableStore, that means we never find in Firmware
> any more.
> +  //
> +  if ((IndexTable != NULL) && !StopRecord) {
> +    IndexTable->GoneThrough = 1;
> +  }
> +
> +  PtrTrack->CurrPtr = InDeletedVariable;
> +
> +  return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
> +}
> +
> +/**
> +  Find the variable in HOB and Non-Volatile variable storages.
> +
> +  @param  VariableName  Name of the variable to be found
> +  @param  VendorGuid    Vendor GUID to be found.
> +  @param  PtrTrack      Variable Track Pointer structure that contains Variable
> Information.
> +  @param  StoreInfo     Return the store info.
> +
> +  @retval  EFI_SUCCESS            Variable found successfully
> +  @retval  EFI_NOT_FOUND          Variable not found
> +  @retval  EFI_INVALID_PARAMETER  Invalid variable name
> +**/
> +EFI_STATUS
> +FindVariable (
> +  IN CONST  CHAR16            *VariableName,
> +  IN CONST  EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
> +  OUT VARIABLE_STORE_INFO     *StoreInfo
> +  )
> +{
> +  EFI_STATUS           Status;
> +  VARIABLE_STORE_TYPE  Type;
> +
> +  if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++)
> {
> +    GetVariableStore (Type, StoreInfo);
> +    Status = FindVariableEx (
> +               StoreInfo,
> +               VariableName,
> +               VendorGuid,
> +               PtrTrack
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariable (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  )
> +{
> +  VARIABLE_POINTER_TRACK  Variable;
> +  UINTN                   VarDataSize;
> +  EFI_STATUS              Status;
> +  VARIABLE_STORE_INFO     StoreInfo;
> +  VARIABLE_HEADER         *VariableHeader;
> +
> +  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (VariableName[0] == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  VariableHeader = NULL;
> +
> +  //
> +  // Find existing variable
> +  //
> +  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
> +
> +  //
> +  // Get data size
> +  //
> +  VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
> +  if (*DataSize >= VarDataSize) {
> +    if (Data == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr,
> VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
> +    Status = EFI_SUCCESS;
> +  } else {
> +    Status = EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  if (Attributes != NULL) {
> +    *Attributes = VariableHeader->Attributes;
> +  }
> +
> +  *DataSize = VarDataSize;
> +
> +  return Status;
> +}
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableName (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  )
> +{
> +  VARIABLE_STORE_TYPE     Type;
> +  VARIABLE_POINTER_TRACK  Variable;
> +  VARIABLE_POINTER_TRACK  VariableInHob;
> +  VARIABLE_POINTER_TRACK  VariablePtrTrack;
> +  UINTN                   VarNameSize;
> +  EFI_STATUS              Status;
> +  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
> +  VARIABLE_HEADER         *VariableHeader;
> +  VARIABLE_STORE_INFO     StoreInfo;
> +  VARIABLE_STORE_INFO     StoreInfoForNv;
> +  VARIABLE_STORE_INFO     StoreInfoForHob;
> +
> +  if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize
> == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  VariableHeader = NULL;
> +
> +  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
> +  if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {
> +    return Status;
> +  }
> +
> +  if (VariableName[0] != 0) {
> +    //
> +    // If variable name is not NULL, get next variable
> +    //
> +    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
> +    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> VariableHeader);
> +  }
> +
> +  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore
> (VariableStoreTypeHob, &StoreInfoForHob);
> +  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore
> (VariableStoreTypeNv, &StoreInfoForNv);
> +
> +  while (TRUE) {
> +    //
> +    // Switch from HOB to Non-Volatile.
> +    //
> +    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
> +      //
> +      // Find current storage index
> +      //
> +      for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax;
> Type++) {
> +        if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr ==
> GetStartPointer (VariableStoreHeader[Type]))) {
> +          break;
> +        }
> +      }
> +
> +      ASSERT (Type < VariableStoreTypeMax);
> +      //
> +      // Switch to next storage
> +      //
> +      for (Type++; Type < VariableStoreTypeMax; Type++) {
> +        if (VariableStoreHeader[Type] != NULL) {
> +          break;
> +        }
> +      }
> +
> +      //
> +      // Capture the case that
> +      // 1. current storage is the last one, or
> +      // 2. no further storage
> +      //
> +      if (Type == VariableStoreTypeMax) {
> +        return EFI_NOT_FOUND;
> +      }
> +
> +      Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
> +      Variable.EndPtr   = GetEndPointer (VariableStoreHeader[Type]);
> +      Variable.CurrPtr  = Variable.StartPtr;
> +      GetVariableStore (Type, &StoreInfo);
> +    }
> +
> +    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State ==
> (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> +      if (VariableHeader->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.
> +        //
> +        Status = FindVariableEx (
> +                   &StoreInfo,
> +                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
> +                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
> +                   &VariablePtrTrack
> +                   );
> +        if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr)) {
> +          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> VariableHeader);
> +          continue;
> +        }
> +      }
> +
> +      //
> +      // Don't return NV variable when HOB overrides it
> +      //
> +      if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) &&
> (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
> +          (Variable.StartPtr == GetStartPointer
> (VariableStoreHeader[VariableStoreTypeNv]))
> +          )
> +      {
> +        Status = FindVariableEx (
> +                   &StoreInfoForHob,
> +                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
> +                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
> +                   &VariableInHob
> +                   );
> +        if (!EFI_ERROR (Status)) {
> +          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> VariableHeader);
> +          continue;
> +        }
> +      }
> +
> +      VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
> +      ASSERT (VarNameSize != 0);
> +
> +      if (VarNameSize <= *VariableNameSize) {
> +        GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr
> (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);
> +
> +        CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader,
> StoreInfo.AuthFlag), sizeof (EFI_GUID));
> +
> +        Status = EFI_SUCCESS;
> +      } else {
> +        Status = EFI_BUFFER_TOO_SMALL;
> +      }
> +
> +      *VariableNameSize = VarNameSize;
> +      //
> +      // Variable is found
> +      //
> +      return Status;
> +    } else {
> +      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> VariableHeader);
> +    }
> +  }
> +}
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  This                  A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetVariableEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN CONST  CHAR16                           *VariableName,
> +  IN CONST  EFI_GUID                         *VariableGuid,
> +  OUT       UINT32                           *Attributes,
> +  IN OUT    UINTN                            *DataSize,
> +  OUT       VOID                             *Data OPTIONAL
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // If variable protection is employed, always get variable data through
> +  // ProtectedVariableLib.
> +  //
> +  Status = ProtectedVariableLibGetByName (VariableName, VariableGuid,
> Attributes, DataSize, Data);
> +  if (Status != EFI_UNSUPPORTED) {
> +    return Status;
> +  }
> +
> +  return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize,
> Data);
> +}
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  This              A pointer to this instance of the
> EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiGetNextVariableNameEx (
> +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> +  IN OUT UINTN                               *VariableNameSize,
> +  IN OUT CHAR16                              *VariableName,
> +  IN OUT EFI_GUID                            *VariableGuid
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // If variable protection is employed, always get next variable through
> +  // ProtectedVariableLib.
> +  //
> +  Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName,
> VariableGuid);
> +  if (Status != EFI_UNSUPPORTED) {
> +    return Status;
> +  }
> +
> +  return PeiGetNextVariableName (This, VariableNameSize, VariableName,
> VariableGuid);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> new file mode 100644
> index 000000000000..2d605d39cbb6
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> @@ -0,0 +1,941 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.

[JianJW] typo: ' Varaiable2' -> ' Variable2'

> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Variable.h"
> +#include "VariableStore.h"
> +
> +/**
> +
> +  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);
> +}
> +
> +/**
> +  This code checks if variable header is valid or not.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +
> +  @retval TRUE      Variable header is valid.
> +  @retval FALSE     Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +IsValidVariableHeader (
> +  IN  VARIABLE_HEADER  *Variable
> +  )
> +{
> +  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  This code gets the size of variable header.
> +
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return Size of variable header in bytes in type UINTN.
> +
> +**/
> +UINTN
> +GetVariableHeaderSize (
> +  IN  BOOLEAN  AuthFlag
> +  )
> +{
> +  UINTN  Value;
> +
> +  if (AuthFlag) {
> +    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]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +NameSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  )
> +{
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +  if (AuthFlag) {
> +    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 gets the size of data of variable.
> +
> +  @param[in]  Variable  Pointer to the Variable Header.
> +  @param[in]  AuthFlag  Authenticated variable flag.
> +
> +  @return Size of variable in bytes in type UINTN.
> +
> +**/
> +UINTN
> +DataSizeOfVariable (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  BOOLEAN          AuthFlag
> +  )
> +{
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +  if (AuthFlag) {
> +    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 gets the pointer to the variable name.
> +
> +  @param[in]   Variable  Pointer to the Variable Header.
> +  @param[in]   AuthFlag  Authenticated variable flag.
> +
> +  @return  A CHAR16* pointer to Variable Name.
> +
> +**/
> +CHAR16 *
> +GetVariableNamePtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  )
> +{
> +  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
> +}
> +
> +/**
> +  This code gets the pointer to the variable guid.
> +
> +  @param[in] Variable   Pointer to the Variable Header.
> +  @param[in] AuthFlag   Authenticated variable flag.
> +
> +  @return A EFI_GUID* pointer to Vendor Guid.
> +
> +**/
> +EFI_GUID *
> +GetVendorGuidPtr (
> +  IN VARIABLE_HEADER  *Variable,
> +  IN BOOLEAN          AuthFlag
> +  )
> +{
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +  if (AuthFlag) {
> +    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]   VariableHeader   Pointer to the Variable Header that has
> consecutive content.
> +  @param[in]   AuthFlag         Authenticated variable flag.
> +
> +  @return  A UINT8* pointer to Variable Data.
> +
> +**/
> +UINT8 *
> +GetVariableDataPtr (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  VARIABLE_HEADER  *VariableHeader,
> +  IN  BOOLEAN          AuthFlag
> +  )
> +{
> +  UINTN  Value;
> +
> +  //
> +  // Be careful about pad size for alignment
> +  //
> +  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
> +  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
> +  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
> +
> +  return (UINT8 *)Value;
> +}
> +
> +/**
> +  This code gets the pointer to the next variable header.
> +
> +  @param[in]  StoreInfo         Pointer to variable store info structure.
> +  @param[in]  Variable          Pointer to the Variable Header.
> +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> consecutive content.
> +
> +  @return  A VARIABLE_HEADER* pointer to next variable header.
> +
> +**/
> +VARIABLE_HEADER *
> +GetNextVariablePtr (
> +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> +  IN  VARIABLE_HEADER      *Variable,
> +  IN  VARIABLE_HEADER      *VariableHeader
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  UINTN                 Value;
> +
> +  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo-
> >AuthFlag);
> +  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
> +  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo-
> >AuthFlag));
> +  //
> +  // Be careful about pad size for alignment
> +  //
> +  Value = HEADER_ALIGN (Value);
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >=
> (UINTN)TargetAddress)) {
> +      //
> +      // Next variable is in spare block.
> +      //
> +      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
> +    }
> +  }
> +
> +  return (VARIABLE_HEADER *)Value;
> +}
> +
> +/**
> +  Compare two variable names, one of them may be inconsecutive.
> +
> +  @param[in] StoreInfo      Pointer to variable store info structure.
> +  @param[in] Name1          Pointer to one variable name.
> +  @param[in] Name2          Pointer to another variable name.
> +  @param[in] NameSize       Variable name size.
> +
> +  @retval TRUE          Name1 and Name2 are identical.
> +  @retval FALSE         Name1 and Name2 are not identical.
> +
> +**/
> +BOOLEAN
> +CompareVariableName (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN CONST CHAR16         *Name1,
> +  IN CONST CHAR16         *Name2,
> +  IN UINTN                NameSize
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  UINTN                 PartialNameSize;
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 +
> NameSize) > (UINTN)TargetAddress)) {
> +      //
> +      // Name1 is inconsecutive.
> +      //
> +      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
> +      //
> +      // Partial content is in NV storage.
> +      //
> +      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) ==
> 0) {
> +        //
> +        // Another partial content is in spare block.
> +        //
> +        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> +          return TRUE;
> +        }
> +      }
> +
> +      return FALSE;
> +    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 +
> NameSize) > (UINTN)TargetAddress)) {
> +      //
> +      // Name2 is inconsecutive.
> +      //
> +      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
> +      //
> +      // Partial content is in NV storage.
> +      //
> +      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) ==
> 0) {
> +        //
> +        // Another partial content is in spare block.
> +        //
> +        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 +
> PartialNameSize, NameSize - PartialNameSize) == 0) {
> +          return TRUE;
> +        }
> +      }
> +
> +      return FALSE;
> +    }
> +  }
> +
> +  //
> +  // Both Name1 and Name2 are consecutive.
> +  //
> +  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  This function compares a variable with variable entries in database.
> +
> +  @param[in]   StoreInfo        Pointer to variable store info structure.
> +  @param[in]   Variable         Pointer to the variable in our database
> +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> +                                consecutive content.
> +  @param[in]   VariableName     Name of the variable to compare to 'Variable'
> +  @param[in]   VendorGuid       GUID of the variable to compare to 'Variable'
> +  @param[out]  PtrTrack         Variable Track Pointer structure that contains
> +                                Variable Information.
> +
> +  @retval EFI_SUCCESS    Found match variable
> +  @retval EFI_NOT_FOUND  Variable not found
> +
> +**/
> +EFI_STATUS
> +CompareWithValidVariable (
> +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> +  IN  VARIABLE_HEADER         *Variable,
> +  IN  VARIABLE_HEADER         *VariableHeader,
> +  IN  CONST CHAR16            *VariableName,
> +  IN  CONST EFI_GUID          *VendorGuid,
> +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> +  )
> +{
> +  VOID      *Point;
> +  EFI_GUID  *TempVendorGuid;
> +
> +  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
> +
> +  if (VariableName[0] == 0) {
> +    PtrTrack->CurrPtr = Variable;
> +    return EFI_SUCCESS;
> +  } else {
> +    //
> +    // Don't use CompareGuid function here for performance reasons.
> +    // Instead we compare the GUID a UINT32 at a time and branch
> +    // on the first failed comparison.
> +    //
> +    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
> +        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
> +        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
> +        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
> +        )
> +    {
> +      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
> +      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
> +      if (CompareVariableName (StoreInfo, VariableName, Point,
> NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
> +        PtrTrack->CurrPtr = Variable;
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Get variable header that has consecutive content.
> +
> +  @param[in]  StoreInfo       Pointer to variable store info structure.
> +  @param[in]  Variable        Pointer to the Variable Header.
> +  @param[out] VariableHeader  Pointer to Pointer to the Variable Header
> +                              that has consecutive content.
> +
> +  @retval TRUE          Variable header is valid.
> +  @retval FALSE         Variable header is not valid.
> +
> +**/
> +BOOLEAN
> +GetVariableHeader (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN VARIABLE_HEADER      *Variable,
> +  OUT VARIABLE_HEADER     **VariableHeader
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  EFI_HOB_GUID_TYPE     *GuidHob;
> +  UINTN                 PartialHeaderSize;
> +
> +  if (Variable == NULL) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // First assume variable header pointed by Variable is consecutive.
> +  //
> +  *VariableHeader = Variable;
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)Variable > (UINTN)SpareAddress) &&
> +        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >=
> (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
> +    {
> +      //
> +      // Reach the end of variable store.
> +      //
> +      return FALSE;
> +    }
> +
> +    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable +
> GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
> +      //
> +      // Variable header pointed by Variable is inconsecutive,
> +      // create a guid hob to combine the two partial variable header content
> together.
> +      //
> +      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
> +      if (GuidHob != NULL) {
> +        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA
> (GuidHob);
> +      } else {
> +        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob
> (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
> +        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
> +        //
> +        // Partial content is in NV storage.
> +        //
> +        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable,
> PartialHeaderSize);
> +        //
> +        // Another partial content is in spare block.
> +        //
> +        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8
> *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) -
> PartialHeaderSize);
> +      }
> +    }
> +  } else {
> +    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
> +      //
> +      // Reach the end of variable store.
> +      //
> +      return FALSE;
> +    }
> +  }
> +
> +  return IsValidVariableHeader (*VariableHeader);
> +}
> +
> +/**
> +  Get variable name or data to output buffer.
> +
> +  @param[in]   StoreInfo     Pointer to variable store info structure.
> +  @param[in]   NameOrData    Pointer to the variable name/data that may be
> inconsecutive.
> +  @param[in]   Size          Variable name/data size.
> +  @param[out]  Buffer        Pointer to output buffer to hold the variable
> name/data.
> +
> +**/
> +VOID
> +GetVariableNameOrData (
> +  IN VARIABLE_STORE_INFO  *StoreInfo,
> +  IN UINT8                *NameOrData,
> +  IN UINTN                Size,
> +  OUT UINT8               *Buffer
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> +  UINTN                 PartialSize;
> +
> +  if (StoreInfo->FtwLastWriteData != NULL) {
> +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> +    if (((UINTN)NameOrData < (UINTN)TargetAddress) &&
> (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
> +      //
> +      // Variable name/data is inconsecutive.
> +      //
> +      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
> +      //
> +      // Partial content is in NV storage.
> +      //
> +      CopyMem (Buffer, NameOrData, PartialSize);
> +      //
> +      // Another partial content is in spare block.
> +      //
> +      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size -
> PartialSize);
> +      return;
> +    }
> +  }
> +
> +  //
> +  // Variable name/data is consecutive.
> +  //
> +  CopyMem (Buffer, NameOrData, Size);
> +}
> +
> +/**
> +
> +  Internal function to retrieve variable information.
> +
> +  @param[in,out] VariableInfo     Pointer to variable information.
> +  @param[in]     StoreInfo        Pointer to store copy of variable (optional).
> +  @param[in]     VariablePtr      Pointer to variable buffer.
> +  @param[in]     VariableHeader   Pointer to variable header.
> +
> +  @retval EFI_INVALID_PARAMETER  One ore more required parameters are
> NULL.
> +  @retval EFI_BUFFER_TOO_SMALL   Given buffer is too small to hold data.
> +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetVariableInfoInternal (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo,
> +  IN      VARIABLE_STORE_INFO      *StoreInfo OPTIONAL,
> +  IN      VARIABLE_HEADER          *VariablePtr,
> +  IN      VARIABLE_HEADER          *VariableHeader
> +  )
> +{
> +  VARIABLE_HEADER                *VariableBuffer;
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariableHeader;
> +  UINTN                          NameSize;
> +  UINTN                          DataSize;
> +  UINTN                          VariableSize;
> +
> +  if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader ==
> NULL)) {
> +    ASSERT (VariableInfo != NULL);
> +    ASSERT (VariablePtr != NULL);
> +    ASSERT (VariableHeader != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  VariableBuffer = VariableInfo->Buffer;
> +
> +  //
> +  // Make a copy of the whole variable if VariableInfo->Buffer is given. But
> +  // don't do this if StoreInfo is not given, because VariableInfo->Buffer
> +  // has already hold a copy of variable in such situation.
> +  //
> +  NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> +  DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> +  if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
> +    if (StoreInfo != NULL) {
> +      CopyMem (
> +        VariableBuffer,
> +        VariableHeader,
> +        GetVariableHeaderSize (VariableInfo->Flags.Auth)
> +        );
> +      GetVariableNameOrData (
> +        StoreInfo,
> +        (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> +        NameSize,
> +        (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
> +        );
> +      GetVariableNameOrData (
> +        StoreInfo,
> +        (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo-
> >Flags.Auth),
> +        DataSize,
> +        (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader,
> VariableInfo->Flags.Auth)
> +        );
> +    } else {
> +      //
> +      // Suppose the variable is in consecutive space.
> +      //
> +      VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
> +                     + NameSize + GET_PAD_SIZE (NameSize)
> +                     + DataSize;
> +      CopyMem (VariableBuffer, VariablePtr, VariableSize);
> +    }
> +  }
> +
> +  //
> +  // Generally, if no consecutive buffer passed in, don't return back any data.
> +  //
> +  // If follow pointers are NULL, return back pointers to following data inside
> +  // VariableInfo->Buffer, if it's given.
> +  //
> +  //  VariableInfo->Header.VariableName
> +  //  VariableInfo->Header.Data
> +  //  VariableInfo->Header.VendorGuid
> +  //  VariableInfo->Header.TimeStamp
> +  //
> +  // Otherwise, suppose they're buffers used to hold a copy of corresponding
> +  // data.
> +  //
> +  //
> +
> +  //
> +  // AuthVariable header
> +  //
> +  if (VariableInfo->Flags.Auth) {
> +    AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableHeader;
> +
> +    VariableInfo->Header.State          = AuthVariableHeader->State;
> +    VariableInfo->Header.Attributes     = AuthVariableHeader->Attributes;
> +    VariableInfo->Header.PubKeyIndex    = AuthVariableHeader->PubKeyIndex;
> +    VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
> +                                            &(AuthVariableHeader->MonotonicCount)
> +                                            );
> +    if (VariableInfo->Header.TimeStamp != NULL) {
> +      CopyMem (
> +        VariableInfo->Header.TimeStamp,
> +        &AuthVariableHeader->TimeStamp,
> +        sizeof (EFI_TIME)
> +        );
> +    } else if (VariableBuffer != NULL) {
> +      AuthVariableHeader             = (AUTHENTICATED_VARIABLE_HEADER
> *)VariableBuffer;
> +      VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
> +    }
> +  } else {
> +    VariableInfo->Header.State          = VariableHeader->State;
> +    VariableInfo->Header.Attributes     = VariableHeader->Attributes;
> +    VariableInfo->Header.PubKeyIndex    = 0;
> +    VariableInfo->Header.MonotonicCount = 0;
> +    VariableInfo->Header.TimeStamp      = NULL;
> +  }
> +
> +  //
> +  // VendorGuid
> +  //
> +  if (VariableInfo->Header.VendorGuid != NULL) {
> +    CopyGuid (
> +      VariableInfo->Header.VendorGuid,
> +      GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
> +      );
> +  } else if (VariableBuffer != NULL) {
> +    VariableInfo->Header.VendorGuid
> +      = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
> +  }
> +
> +  //
> +  // VariableName
> +  //
> +  if (  (VariableInfo->Header.VariableName != NULL)
> +     && (VariableInfo->Header.NameSize >= NameSize))
> +  {
> +    GetVariableNameOrData (
> +      StoreInfo,
> +      (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> +      NameSize,
> +      (UINT8 *)VariableInfo->Header.VariableName
> +      );
> +  } else if (VariableBuffer != NULL) {
> +    VariableInfo->Header.VariableName
> +      = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
> +  } else if (VariableInfo->Header.VariableName != NULL) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  //
> +  // Data
> +  //
> +  if (  (VariableInfo->Header.Data != NULL)
> +     && (VariableInfo->Header.DataSize >= DataSize))
> +  {
> +    GetVariableNameOrData (
> +      StoreInfo,
> +      GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
> +      DataSize,
> +      VariableInfo->Header.Data
> +      );
> +  } else if (VariableBuffer != NULL) {
> +    VariableInfo->Header.Data
> +      = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo-
> >Flags.Auth);
> +  } else if (VariableInfo->Header.Data != NULL) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  //
> +  // Update size information about name & data.
> +  //
> +  VariableInfo->Header.NameSize = NameSize;
> +  VariableInfo->Header.DataSize = DataSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Retrieve details about a variable, given by VariableInfo->Buffer or
> +  VariableInfo->Index, and pass the details back in VariableInfo->Header.
> +
> +  This function is used to resolve the variable data structure into
> +  VariableInfo->Header, for easier access later without revisiting the variable
> +  data in variable store. If pointers in the structure of VariableInfo->Header
> +  are not NULL, it's supposed that they are buffers passed in to hold a copy of
> +  data of corresponding data fields in variable data structure. Otherwise, this
> +  function simply returns pointers pointing to address of those data fields.
> +
> +  The variable is specified by either VariableInfo->Index or VariableInfo->Buffer.
> +  If VariableInfo->Index is given, this function finds the corresponding variable
> +  first from variable storage according to the Index.
> +
> +  If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
> +  that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
> +  requested variable data to be returned.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both VariableInfo-
> >Buffer
> +                                 and VariableInfo->Index are NULL (0).
> +  @retval EFI_NOT_FOUND          If given Buffer or Index 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_HEADER      *VariablePtr;
> +  VARIABLE_HEADER      *VariableHeader;
> +  VARIABLE_STORE_TYPE  StoreType;
> +  VARIABLE_STORE_INFO  StoreInfo;
> +  UINTN                Offset;
> +
> +  if ((VariableInfo == NULL) ||
> +      ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex ==
> VAR_INDEX_INVALID)))
> +  {
> +    ASSERT (VariableInfo != NULL);
> +    ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo-
> >Buffer != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  StoreInfo.VariableStoreHeader = NULL;
> +  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> ++StoreType) {
> +    GetVariableStore (StoreType, &StoreInfo);
> +    if (StoreInfo.VariableStoreHeader != NULL) {
> +      break;
> +    }
> +  }
> +
> +  ASSERT (StoreInfo.VariableStoreHeader != NULL);
> +
> +  //
> +  // No StoreIndex? Don't retrieve variable information from store but just from
> +  // VariableInfo->Buffer.
> +  //
> +  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> +    VariablePtr    = VariableInfo->Buffer;
> +    VariableHeader = VariablePtr;
> +
> +    return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr,
> VariableHeader);
> +  }
> +
> +  Offset = (UINTN)VariableInfo->StoreIndex;
> +  if (  (StoreInfo.FtwLastWriteData != NULL)
> +     && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                    - (UINTN)StoreInfo.VariableStoreHeader)))
> +  {
> +    Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +               - (UINTN)StoreInfo.VariableStoreHeader);
> +    VariablePtr = (VARIABLE_HEADER *)
> +                  ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> +  } else {
> +    VariablePtr = (VARIABLE_HEADER *)
> +                  ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> +  }
> +
> +  //
> +  // Note that variable might be in unconsecutive space. Always get a copy

[JianJW] typo: "unconsecutive" -> "inconsecutive"

> +  // of its header in consecutive buffer.
> +  //
> +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> +
> +/**
> +
> +  Retrieve details of the variable next to given variable within VariableStore.
> +
> +  If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
> +
> +  VariableStart and/or VariableEnd can be given optionally for the situation
> +  in which the valid storage space is smaller than the VariableStore->Size.
> +  This usually happens when PEI variable services make a compact variable
> +  cache to save memory, which cannot make use VariableStore->Size to
> determine
> +  the correct variable storage range.
> +
> +  @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_HEADER      *VariablePtr;
> +  VARIABLE_HEADER      *VariableHeader;
> +  VARIABLE_STORE_INFO  StoreInfo;
> +  VARIABLE_STORE_TYPE  StoreType;
> +  UINTN                Offset;
> +
> +  if (VariableInfo == NULL) {
> +    ASSERT (VariableInfo != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  StoreInfo.VariableStoreHeader = NULL;
> +  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> ++StoreType) {
> +    GetVariableStore (StoreType, &StoreInfo);
> +    if (StoreInfo.VariableStoreHeader != NULL) {
> +      break;
> +    }
> +  }
> +
> +  ASSERT (StoreInfo.VariableStoreHeader != NULL);
> +
> +  //
> +  // VariableInfo->StoreIndex is supposed to be the index to variable found
> +  // last time. Use it to get the variable next to it in store. If it's invalid,
> +  // return the first variable available in store.
> +  //
> +  VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
> +  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> +    VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
> +  } else {
> +    Offset = (UINTN)VariableInfo->StoreIndex;
> +    if (  (StoreInfo.FtwLastWriteData != NULL)
> +       && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                      - (UINTN)StoreInfo.VariableStoreHeader)))
> +    {
> +      Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                 - (UINTN)StoreInfo.VariableStoreHeader);
> +      VariablePtr = (VARIABLE_HEADER *)
> +                    ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> +    } else {
> +      VariablePtr = (VARIABLE_HEADER *)
> +                    ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> +    }
> +
> +    //
> +    // Note that variable might be in unconsecutive space. Always get a copy

[JianJW] typo: "unconsecutive" -> "inconsecutive"

> +    // of its header in consecutive buffer.
> +    //
> +    if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
> +  }
> +
> +  //
> +  // Get a copy of variable header in consecutive buffer.
> +  //
> +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Use the offset to the start of variable store as index of the variable.
> +  //
> +  if (  (StoreInfo.FtwLastWriteData == NULL)
> +     || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData-
> >TargetAddress))
> +  {
> +    VariableInfo->StoreIndex
> +      = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
> +  } else {
> +    VariableInfo->StoreIndex
> +      = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> +                 - (UINTN)StoreInfo.VariableStoreHeader);
> +    VariableInfo->StoreIndex
> +      += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData-
> >SpareAddress);
> +  }
> +
> +  if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) {
> +    VariableInfo->Buffer = VariablePtr;
> +  }
> +
> +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> VariableHeader);
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> new file mode 100644
> index 000000000000..75edc3fc5051
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> @@ -0,0 +1,307 @@
> +/** @file
> +  Implement ReadOnly Variable Services required by PEIM and install
> +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage
> space.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "VariableParsing.h"
> +#include "VariableStore.h"
> +
> +/**
> +  Get variable store status.
> +
> +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> +
> +  @retval  EfiRaw      Variable store is raw
> +  @retval  EfiValid    Variable store is valid
> +  @retval  EfiInvalid  Variable store 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;
> +  }
> +
> +  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;
> +  }
> +}
> +
> +/**
> +  Reports HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +IsHobVariableStoreAvailable (
> +  VOID
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +  VOID               *VariableStoreInfoHob;
> +
> +  //
> +  // Discover if Variable Store Info Hob has been published by platform driver.
> +  // It contains information regards to HOB or NV Variable Store availability
> +  //
> +  GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
> +  if (GuidHob == NULL) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  //
> +  // Check if HOB Variable Store is available
> +  //
> +  VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
> +  if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // This might be NV Variable Store
> +  //
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Get HOB variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +
> +**/
> +VOID
> +GetHobVariableStore (
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  //
> +  // 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 ();
> +
> +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> +  if (GuidHob != NULL) {
> +    StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> +    StoreInfo->AuthFlag            = TRUE;
> +  } else {
> +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> +    if (GuidHob != NULL) {
> +      StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> *)GET_GUID_HOB_DATA (GuidHob);
> +      StoreInfo->AuthFlag            = FALSE;
> +    }
> +  }
> +}
> +
> +/**
> +  Get NV variable store.
> +
> +  @param[out] StoreInfo             Return the store info.
> +  @param[out] VariableFvHeader      Return header of FV containing the store.
> +
> +**/
> +VOID
> +GetNvVariableStore (
> +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_HOB_GUID_TYPE                     *GuidHob;
> +  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
> +  VARIABLE_STORE_HEADER                 *StoreHeader;
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *HobData;
> +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
> +  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
> +  UINT32                                NvStorageSize;
> +  UINT32                                BackUpOffset;
> +  UINT64                                NvStorageSize64;
> +
> +  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);
> +
> +  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> +
> +  //
> +  // Check the FTW last write data hob.
> +  //
> +  BackUpOffset     = 0;
> +  FtwLastWriteData = NULL;
> +  HobData          = NULL;
> +  GuidHob          = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> +
> +  if (GuidHob != NULL) {
> +    HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> *)GET_GUID_HOB_DATA (GuidHob);
> +    if (HobData->TargetAddress == NvStorageBase) {
> +      //
> +      // Let FvHeader point to spare block.
> +      //
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
> +        (UINTN)HobData->SpareAddress
> +        ));
> +
> +      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData-
> >SpareAddress;
> +      HobData  = NULL;
> +    } else if ((HobData->TargetAddress > NvStorageBase) &&
> +               (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
> +    {
> +      //
> +      // Flash NV storage from the offset is backed up in spare block.
> +      //
> +      BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "PeiVariable: High partial NV storage from offset: %x is backed up in spare
> block: 0x%x\n",
> +        BackUpOffset,
> +        (UINTN)FtwLastWriteData->SpareAddress
> +        ));
> +      //
> +      // At least one block data in flash NV storage is still valid, so still
> +      // leave FvHeader point to NV storage base.
> +      //
> +    }
> +  }
> +
> +  if (StoreInfo != NULL) {
> +    StoreInfo->FtwLastWriteData = HobData;
> +  }
> +
> +  if (VariableFvHeader != NULL) {
> +    *VariableFvHeader = FvHeader;
> +  }
> +
> +  //
> +  // Check if the Firmware Volume is not corrupted
> +  //
> +  if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
> +      CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
> +  {
> +    StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader-
> >HeaderLength);
> +  } else {
> +    StoreHeader = NULL;
> +    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> corrupted\n"));
> +  }
> +
> +  if (StoreInfo != NULL) {
> +    StoreInfo->VariableStoreHeader = StoreHeader;
> +    if (StoreHeader != NULL) {
> +      StoreInfo->AuthFlag = CompareGuid (
> +                              &StoreHeader->Signature,
> +                              &gEfiAuthenticatedVariableGuid
> +                              );
> +    }
> +  }
> +}
> +
> +/**
> +  Return the variable store header and the store info based on the Index.
> +
> +  @param[in]  Type       The type of the variable store.
> +  @param[out] StoreInfo  Return the store info.
> +
> +  @return  Pointer to the variable store header.
> +**/
> +VARIABLE_STORE_HEADER *
> +GetVariableStore (
> +  IN VARIABLE_STORE_TYPE   Type,
> +  OUT VARIABLE_STORE_INFO  *StoreInfo
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  StoreInfo->VariableStoreHeader = NULL;
> +  StoreInfo->IndexTable          = NULL;
> +  StoreInfo->FtwLastWriteData    = NULL;
> +  StoreInfo->AuthFlag            = FALSE;
> +  switch (Type) {
> +    case VariableStoreTypeHob:
> +      GetHobVariableStore (StoreInfo);
> +      break;
> +
> +    case VariableStoreTypeNv:
> +      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> +        //
> +        // Emulated non-volatile variable mode is not enabled.
> +        //
> +        GetNvVariableStore (StoreInfo, NULL);
> +        if (StoreInfo->VariableStoreHeader != NULL) {
> +          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> +          if (GuidHob != NULL) {
> +            StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> +          } else {
> +            //
> +            // If it's the first time to access variable region in flash, create a guid hob
> to record
> +            // VAR_ADDED type variable info.
> +            // Note that as the resource of PEI phase is limited, only store the
> limited number of
> +            // VAR_ADDED type variables to reduce access time.
> +            //
> +            StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE
> *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
> +            StoreInfo->IndexTable->Length      = 0;
> +            StoreInfo->IndexTable->StartPtr    = GetStartPointer (StoreInfo-
> >VariableStoreHeader);
> +            StoreInfo->IndexTable->EndPtr      = GetEndPointer (StoreInfo-
> >VariableStoreHeader);
> +            StoreInfo->IndexTable->GoneThrough = 0;
> +          }
> +        }
> +      }
> +
> +      break;
> +
> +    default:
> +      ASSERT (FALSE);
> +      break;
> +  }
> +
> +  return StoreInfo->VariableStoreHeader;
> +}
> diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> new file mode 100644
> index 000000000000..106c1dfdc5c0
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> @@ -0,0 +1,16 @@
> +// /** @file
> +// Implements ReadOnly Variable Services required by PEIM and installs PEI
> ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +//
> +// This module implements ReadOnly Variable Services required by PEIM and
> installs PEI ReadOnly Varaiable2 PPI.

[JianJW] typo: "Varaiable2" -> "Variable2"

> +//
> +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "Implements
> ReadOnly Variable Services required by PEIM and installs PEI ReadOnly
> Varaiable2 PPI"

[JianJW] typo: "Varaiable2" -> "Variable2"

> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This module
> implements ReadOnly Variable Services required by PEIM and installs PEI
> ReadOnly Varaiable2 PPI."

[JianJW] typo: "Varaiable2" -> "Variable2"

> +
> diff --git
> a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> new file mode 100644
> index 000000000000..22dd992be908
> --- /dev/null
> +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// PeiVariable 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
> +"Variable Access PEI Module"
> +
> +
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [edk2-devel] [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
       [not found]   ` <1727569A8ECB6F9D.19699@groups.io>
@ 2022-11-14  4:27     ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-14  4:27 UTC (permalink / raw)
  To: devel@edk2.groups.io, Wang, Jian J, Vang, Judah
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C

One more comment:

For all header files, no need to remove the opening '_' of include guard macro.
Protected variable code are now in different folder than original variable driver.
They won't reference code from each other. Please add the opening '_' for those
macros to confirm to edk2 coding convention.

Regards,
Jian

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Wang, Jian
> J
> Sent: Monday, November 14, 2022 11:43 AM
> To: Vang, Judah <judah.vang@intel.com>; devel@edk2.groups.io
> Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A
> <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: Re: [edk2-devel] [PATCH v5 07/19] MdeModulePkg: Add new Variable
> functionality
> 
> Hi Judah,
> 
> See my comments (starting with [JianJW]) inline below.
> 
> 
> > -----Original Message-----
> > From: Vang, Judah <judah.vang@intel.com>
> > Sent: Sunday, November 06, 2022 3:35 PM
> > To: devel@edk2.groups.io
> > Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> > <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
> > Nishant C <nishant.c.mistry@intel.com>
> > Subject: [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality
> >
> > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> >
> > V5: Add PEI Variable Protection into a new directory and leave the
> > existing PEI Variable unchanged.
> >
> > V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo()
> > and SafeUint64ToUint32().
> >
> > V1: Provide new APIs for retrieving variable information.
> > Add new function stubs for retrieving Protected
> > variable information.
> >
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Liming Gao <gaoliming@byosoft.com.cn>
> > Cc: Hao A Wu <hao.a.wu@intel.com>
> > Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> > Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> > Signed-off-by: Judah Vang <judah.vang@intel.com>
> > Acked-by: Hao A Wu <hao.a.wu@intel.com>
> > ---
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf      |  79 ++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h           | 225
> +++++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h    | 309
> > +++++++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h      | 116
> +++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c           | 628
> > +++++++++++++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c    | 941
> > ++++++++++++++++++++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c      | 307
> > +++++++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni      |  16 +
> >  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni |  14 +
> >  9 files changed, 2635 insertions(+)
> >
> > diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> > new file mode 100644
> > index 000000000000..953a7c6b884f
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> > @@ -0,0 +1,79 @@
> > +## @file
> > +#  Implements ReadOnly Variable Services required by PEIM and installs PEI
> > ReadOnly Varaiable2 PPI.
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +#
> > +#  This module implements ReadOnly Variable Services required by PEIM and
> > installs PEI ReadOnly Varaiable2 PPI.
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +#
> > +#  Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x00010005
> > +  BASE_NAME                      = PeiVariable
> > +  MODULE_UNI_FILE                = PeiVariable.uni
> > +  FILE_GUID                      = 8D104D19-593B-4DDF-81CF-8168A9EDE9C7
> > +  MODULE_TYPE                    = PEIM
> > +  VERSION_STRING                 = 1.0
> > +  ENTRY_POINT                    = PeimInitializeVariableServices
> > +
> > +#
> > +# The following information is for reference only and not required by the
> build
> > tools.
> > +#
> > +#  VALID_ARCHITECTURES           = IA32 X64 EBC
> > +#
> > +
> > +[Sources]
> > +  Variable.c
> > +  Variable.h
> > +  VariableStore.c
> > +  VariableStore.h
> > +  VariableParsing.c
> > +  VariableParsing.h
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +
> > +[LibraryClasses]
> > +  BaseMemoryLib
> > +  PcdLib
> > +  HobLib
> > +  PeimEntryPoint
> > +  DebugLib
> > +  PeiServicesTablePointerLib
> > +  PeiServicesLib
> > +  SafeIntLib
> > +  VariableFlashInfoLib
> > +  ProtectedVariableLib
> > +
> > +[Guids]
> > +  ## CONSUMES             ## GUID # Variable store header
> > +  ## SOMETIMES_CONSUMES   ## HOB
> > +  gEfiAuthenticatedVariableGuid
> > +  ## SOMETIMES_CONSUMES   ## GUID # Variable store header
> > +  ## SOMETIMES_CONSUMES   ## HOB
> > +  gEfiVariableGuid
> > +  ## SOMETIMES_PRODUCES   ## HOB
> > +  ## SOMETIMES_CONSUMES   ## HOB
> > +  gEfiVariableIndexTableGuid
> > +  gEfiSystemNvDataFvGuid            ## SOMETIMES_CONSUMES   ## GUID
> > +  ## SOMETIMES_CONSUMES   ## HOB
> > +  ## CONSUMES             ## GUID # Dependence
> > +  gEdkiiFaultTolerantWriteGuid
> > +
> > +[Ppis]
> > +  gEfiPeiReadOnlyVariable2PpiGuid        ## PRODUCES
> > +  gEfiPeiVariableStoreDiscoveredPpiGuid  ## CONSUMES
> > +
> > +[Pcd]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable         ##
> > SOMETIMES_CONSUMES
> > +
> > +[Depex]
> > +  gEdkiiFaultTolerantWriteGuid
> > +
> > +# [BootMode]
> > +# RECOVERY_FULL             ## SOMETIMES_CONSUMES
> > +
> > +[UserExtensions.TianoCore."ExtraFiles"]
> > +  PeiVariableExtra.uni
> > diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> > new file mode 100644
> > index 000000000000..1bdbdd2b807b
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> > @@ -0,0 +1,225 @@
> > +/** @file
> > +  The internal header file includes the common header files, defines
> > +  internal structure and functions used by PeiVariable module.
> > +
> > +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef PEI_VARIABLE_H_
> > +#define PEI_VARIABLE_H_
> > +
> > +#include <PiPei.h>
> > +#include <Ppi/ReadOnlyVariable2.h>
> > +
> > +#include <Library/DebugLib.h>
> > +#include <Library/PeimEntryPoint.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/PeiServicesTablePointerLib.h>
> > +#include <Library/PeiServicesLib.h>
> > +#include <Library/SafeIntLib.h>
> > +#include <Library/VariableFlashInfoLib.h>
> > +#include <Library/ProtectedVariableLib.h>
> > +
> > +#include <Guid/VariableFormat.h>
> > +#include <Guid/VariableIndexTable.h>
> > +#include <Guid/SystemNvDataGuid.h>
> > +#include <Guid/FaultTolerantWrite.h>
> > +#include <Guid/ProtectedVariable.h>
> > +
> > +typedef enum {
> > +  VariableStoreTypeHob,
> > +  VariableStoreTypeNv,
> > +  VariableStoreTypeMax
> > +} VARIABLE_STORE_TYPE;
> > +
> > +typedef struct {
> > +  VARIABLE_STORE_HEADER                   *VariableStoreHeader;
> > +  VARIABLE_INDEX_TABLE                    *IndexTable;
> > +  //
> > +  // If it is not NULL, it means there may be an inconsecutive variable whose
> > +  // partial content is still in NV storage, but another partial content is backed
> > up
> > +  // in spare block.
> > +  //
> > +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA    *FtwLastWriteData;
> > +  BOOLEAN                                 AuthFlag;
> > +} VARIABLE_STORE_INFO;
> > +
> > +//
> > +// Functions
> > +//
> > +
> > +/**
> > +  Provide the functionality of the variable services.
> > +
> > +  @param  FileHandle  Handle of the file being invoked.
> > +                      Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
> > +  @param  PeiServices  General purpose services available to every PEIM.
> > +
> > +  @retval EFI_SUCCESS  If the interface could be successfully installed
> > +  @retval Others       Returned from PeiServicesInstallPpi()
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeimInitializeVariableServices (
> > +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> > +  IN CONST EFI_PEI_SERVICES     **PeiServices
> > +  );
> > +
> > +/**
> > +  This service retrieves a variable's value using its name and GUID.
> > +
> > +  Read the specified variable from the UEFI variable store. If the Data
> > +  buffer is too small to hold the contents of the variable, the error
> > +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required
> buffer
> > +  size to obtain the data.
> > +
> > +  @param  This                  A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +  @param  VariableName          A pointer to a null-terminated string that is the
> > variable's name.
> > +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> > GUID. The combination of
> > +                                VariableGuid and VariableName must be unique.
> > +  @param  Attributes            If non-NULL, on return, points to the variable's
> > attributes.
> > +  @param  DataSize              On entry, points to the size in bytes of the Data
> > buffer.
> > +                                On return, points to the size of the data returned in Data.
> > +  @param  Data                  Points to the buffer which will hold the returned
> > variable value.
> > +                                May be NULL with a zero DataSize in order to determine the
> > size of the buffer needed.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable was not found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the
> resulting
> > data.
> > +                                DataSize is updated with the size required for
> > +                                the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> > Data is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetVariable (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN CONST  CHAR16                           *VariableName,
> > +  IN CONST  EFI_GUID                         *VariableGuid,
> > +  OUT       UINT32                           *Attributes,
> > +  IN OUT    UINTN                            *DataSize,
> > +  OUT       VOID                             *Data OPTIONAL
> > +  );
> > +
> > +/**
> > +  Return the next variable name and GUID.
> > +
> > +  This function is called multiple times to retrieve the VariableName
> > +  and VariableGuid of all variables currently available in the system.
> > +  On each call, the previous results are passed into the interface,
> > +  and, on return, the interface returns the data for the next
> > +  interface. When the entire variable list has been returned,
> > +  EFI_NOT_FOUND is returned.
> > +
> > +  @param  This              A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +
> > +  @param  VariableNameSize  On entry, points to the size of the buffer
> pointed
> > to by VariableName.
> > +  @param  VariableName      On entry, a pointer to a null-terminated string
> that
> > is the variable's name.
> > +                            On return, points to the next variable's null-terminated name
> > string.
> > +
> > +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> > variable's GUID.
> > +                            On return, a pointer to the next variable's GUID.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable could not be found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for
> the
> > resulting
> > +                                data. VariableNameSize is updated with the size
> > +                                required for the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> > +                                VariableNameSize is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetNextVariableName (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN OUT UINTN                               *VariableNameSize,
> > +  IN OUT CHAR16                              *VariableName,
> > +  IN OUT EFI_GUID                            *VariableGuid
> > +  );
> > +
> > +/**
> > +  This service retrieves a variable's value using its name and GUID.
> > +
> > +  Read the specified variable from the UEFI variable store. If the Data
> > +  buffer is too small to hold the contents of the variable, the error
> > +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required
> buffer
> > +  size to obtain the data.
> > +
> > +  @param  This                  A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +  @param  VariableName          A pointer to a null-terminated string that is the
> > variable's name.
> > +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> > GUID. The combination of
> > +                                VariableGuid and VariableName must be unique.
> > +  @param  Attributes            If non-NULL, on return, points to the variable's
> > attributes.
> > +  @param  DataSize              On entry, points to the size in bytes of the Data
> > buffer.
> > +                                On return, points to the size of the data returned in Data.
> > +  @param  Data                  Points to the buffer which will hold the returned
> > variable value.
> > +                                May be NULL with a zero DataSize in order to determine the
> > size of the buffer needed.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable was not found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the
> resulting
> > data.
> > +                                DataSize is updated with the size required for
> > +                                the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> > Data is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetVariableEx (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN CONST  CHAR16                           *VariableName,
> > +  IN CONST  EFI_GUID                         *VariableGuid,
> > +  OUT       UINT32                           *Attributes,
> > +  IN OUT    UINTN                            *DataSize,
> > +  OUT       VOID                             *Data OPTIONAL
> > +  );
> > +
> > +/**
> > +  Return the next variable name and GUID.
> > +
> > +  This function is called multiple times to retrieve the VariableName
> > +  and VariableGuid of all variables currently available in the system.
> > +  On each call, the previous results are passed into the interface,
> > +  and, on return, the interface returns the data for the next
> > +  interface. When the entire variable list has been returned,
> > +  EFI_NOT_FOUND is returned.
> > +
> > +  @param  This              A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +
> > +  @param  VariableNameSize  On entry, points to the size of the buffer
> pointed
> > to by VariableName.
> > +  @param  VariableName      On entry, a pointer to a null-terminated string
> that
> > is the variable's name.
> > +                            On return, points to the next variable's null-terminated name
> > string.
> > +
> > +  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the
> > variable's GUID.
> > +                            On return, a pointer to the next variable's GUID.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable could not be found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for
> the
> > resulting
> > +                                data. VariableNameSize is updated with the size
> > +                                required for the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> > +                                VariableNameSize is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetNextVariableNameEx (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN OUT UINTN                               *VariableNameSize,
> > +  IN OUT CHAR16                              *VariableName,
> > +  IN OUT EFI_GUID                            *VariableGuid
> > +  );
> > +
> > +#endif
> 
> [JianJW]
> a. The function header comments for
> PeiGetVariableEx/PeiGetNextVariableNameEx
>     are the same as non-ex version of PeiGetVariable/PeiGetNextVariableName.
> This
>     doesn't do any help to users to get know about what're the differences
> between
>     these two version of functions. Please update the Ex version function header
> to
>     give more accurate descriptions.
> b. Please update the function header in Variable.c as well.
> 
> > diff --git
> a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> > new file mode 100644
> > index 000000000000..d7af6cb6e8be
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> > @@ -0,0 +1,309 @@
> > +/** @file
> > +  The internal header file includes the common header files, defines
> > +  internal structure and functions used by PeiVariable module.
> > +
> > +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef PEI_VARIABLE_PARSING_H_
> > +#define PEI_VARIABLE_PARSING_H_
> > +
> > +#include "Variable.h"
> > +
> > +/**
> > +
> > +  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
> > +  );
> > +
> > +/**
> > +  This code checks if variable header is valid or not.
> > +
> > +  @param[in]  Variable  Pointer to the Variable Header.
> > +
> > +  @retval TRUE      Variable header is valid.
> > +  @retval FALSE     Variable header is not valid.
> > +
> > +**/
> > +BOOLEAN
> > +IsValidVariableHeader (
> > +  IN  VARIABLE_HEADER  *Variable
> > +  );
> > +
> > +/**
> > +  This code gets the pointer to the next variable header.
> > +
> > +  @param[in]  StoreInfo         Pointer to variable store info structure.
> > +  @param[in]  Variable          Pointer to the Variable Header.
> > +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> > consecutive content.
> > +
> > +  @return  A VARIABLE_HEADER* pointer to next variable header.
> > +
> > +**/
> > +VARIABLE_HEADER *
> > +GetNextVariablePtr (
> > +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN  VARIABLE_HEADER      *Variable,
> > +  IN  VARIABLE_HEADER      *VariableHeader
> > +  );
> > +
> > +/**
> > +  This code gets the pointer to the variable guid.
> > +
> > +  @param[in]  Variable   Pointer to the Variable Header.
> > +  @param[in]  AuthFlag   Authenticated variable flag.
> > +
> > +  @return A EFI_GUID* pointer to Vendor Guid.
> > +
> > +**/
> > +EFI_GUID *
> > +GetVendorGuidPtr (
> > +  IN VARIABLE_HEADER  *Variable,
> > +  IN BOOLEAN          AuthFlag
> > +  );
> > +
> > +/**
> > +  This code gets the pointer to the variable name.
> > +
> > +  @param[in]   Variable  Pointer to the Variable Header.
> > +  @param[in]   AuthFlag  Authenticated variable flag.
> > +
> > +  @return  A CHAR16* pointer to Variable Name.
> > +
> > +**/
> > +CHAR16 *
> > +GetVariableNamePtr (
> > +  IN VARIABLE_HEADER  *Variable,
> > +  IN BOOLEAN          AuthFlag
> > +  );
> > +
> > +/**
> > +  This code gets the size of name of variable.
> > +
> > +  @param[in]  Variable  Pointer to the Variable Header.
> > +  @param[in]  AuthFlag  Authenticated variable flag.
> > +
> > +  @return Size of variable in bytes in type UINTN.
> > +
> > +**/
> > +UINTN
> > +NameSizeOfVariable (
> > +  IN  VARIABLE_HEADER  *Variable,
> > +  IN  BOOLEAN          AuthFlag
> > +  );
> > +
> > +/**
> > +  This code gets the size of data of variable.
> > +
> > +  @param[in]  Variable  Pointer to the Variable Header.
> > +  @param[in]  AuthFlag  Authenticated variable flag.
> > +
> > +  @return Size of variable in bytes in type UINTN.
> > +
> > +**/
> > +UINTN
> > +DataSizeOfVariable (
> > +  IN  VARIABLE_HEADER  *Variable,
> > +  IN  BOOLEAN          AuthFlag
> > +  );
> > +
> > +/**
> > +  This code gets the pointer to the variable data.
> > +
> > +  @param[in]   Variable         Pointer to the Variable Header.
> > +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> > consecutive content.
> > +  @param[in]   AuthFlag         Authenticated variable flag.
> > +
> > +  @return  A UINT8* pointer to Variable Data.
> > +
> > +**/
> > +UINT8 *
> > +GetVariableDataPtr (
> > +  IN  VARIABLE_HEADER  *Variable,
> > +  IN  VARIABLE_HEADER  *VariableHeader,
> > +  IN  BOOLEAN          AuthFlag
> > +  );
> > +
> > +/**
> > +  Get variable header that has consecutive content.
> > +
> > +  @param[in]  StoreInfo      Pointer to variable store info structure.
> > +  @param[in]  Variable       Pointer to the Variable Header.
> > +  @param[out] VariableHeader Pointer to Pointer to the Variable Header that
> > has consecutive content.
> > +
> > +  @retval TRUE          Variable header is valid.
> > +  @retval FALSE         Variable header is not valid.
> > +
> > +**/
> > +BOOLEAN
> > +GetVariableHeader (
> > +  IN VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN VARIABLE_HEADER      *Variable,
> > +  OUT VARIABLE_HEADER     **VariableHeader
> > +  );
> > +
> > +/**
> > +  This code gets the size of variable header.
> > +
> > +  @param[in] AuthFlag   Authenticated variable flag.
> > +
> > +  @return Size of variable header in bytes in type UINTN.
> > +
> > +**/
> > +UINTN
> > +GetVariableHeaderSize (
> > +  IN  BOOLEAN  AuthFlag
> > +  );
> > +
> > +/**
> > +  Get variable name or data to output buffer.
> > +
> > +  @param[in]  StoreInfo     Pointer to variable store info structure.
> > +  @param[in]  NameOrData    Pointer to the variable name/data that may be
> > inconsecutive.
> > +  @param[in]  Size          Variable name/data size.
> > +  @param[out] Buffer        Pointer to output buffer to hold the variable
> > name/data.
> > +
> > +**/
> > +VOID
> > +GetVariableNameOrData (
> > +  IN VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN UINT8                *NameOrData,
> > +  IN UINTN                Size,
> > +  OUT UINT8               *Buffer
> > +  );
> > +
> > +/**
> > +  This function compares a variable with variable entries in database.
> > +
> > +  @param[in]  StoreInfo     Pointer to variable store info structure.
> > +  @param[in]  Variable      Pointer to the variable in our database
> > +  @param[in]  VariableHeader Pointer to the Variable Header that has
> > consecutive content.
> > +  @param[in]  VariableName  Name of the variable to compare to 'Variable'
> > +  @param[in]  VendorGuid    GUID of the variable to compare to 'Variable'
> > +  @param[out] PtrTrack      Variable Track Pointer structure that contains
> > Variable Information.
> > +
> > +  @retval EFI_SUCCESS    Found match variable
> > +  @retval EFI_NOT_FOUND  Variable not found
> > +
> > +**/
> > +EFI_STATUS
> > +CompareWithValidVariable (
> > +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> > +  IN  VARIABLE_HEADER         *Variable,
> > +  IN  VARIABLE_HEADER         *VariableHeader,
> > +  IN  CONST CHAR16            *VariableName,
> > +  IN  CONST EFI_GUID          *VendorGuid,
> > +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> > +  );
> > +
> > +/**
> > +
> > +  Retrieve details of the variable next to given variable within VariableStore.
> > +
> > +  If VarInfo->Address is NULL, the first one in VariableStore is returned.
> > +
> > +  VariableStart and/or VariableEnd can be given optionally for the situation
> > +  in which the valid storage space is smaller than the VariableStore->Size.
> > +  This usually happens when PEI variable services make a compact variable
> > +  cache to save memory, which cannot make use VariableStore->Size to
> > determine
> > +  the correct variable storage range.
> 
> [JianJW] This part doesn't match the function implementation any more.
> It can be removed.
> 
> > +
> > +  @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->Address 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->Address 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->Address,
> > +  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
> > +  );
> > +
> > +/**
> > +
> > +  Find variable specified with input parameters.
> > +
> > +  @param[in] StoreInfo             Pointer to variable information.
> > +  @param[in] VariableName          Pointer to variable name.
> > +  @param[in] VendorGuid            Pointer to variable GUID.
> > +  @param[in] PtrTrack              Pointer to variable track.
> > +
> > +  @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
> > +FindVariableEx (
> > +  IN VARIABLE_STORE_INFO      *StoreInfo,
> > +  IN CONST CHAR16             *VariableName,
> > +  IN CONST EFI_GUID           *VendorGuid,
> > +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> > +  );
> > +
> > +#endif
> > diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> > new file mode 100644
> > index 000000000000..6e2f6f939bab
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> > @@ -0,0 +1,116 @@
> > +/** @file
> > +  Implement ReadOnly Variable Services required by PEIM and install
> > +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile
> storage
> > space.
> 
> [JianJW] typo: ' Varaiable2' -> ' Variable2'
> 
> > +
> > +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef PEI_VARIABLE_STORE_H_
> > +#define PEI_VARIABLE_STORE_H_
> > +
> > +/**
> > +  Get variable store status.
> > +
> > +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> > +
> > +  @retval  EfiRaw      Variable store is raw
> > +  @retval  EfiValid    Variable store is valid
> > +  @retval  EfiInvalid  Variable store is invalid
> > +
> > +**/
> > +VARIABLE_STORE_STATUS
> > +GetVariableStoreStatus (
> > +  IN VARIABLE_STORE_HEADER  *VarStoreHeader
> > +  );
> > +
> > +/**
> > +  Reports HOB variable store is available or not.
> > +
> > +  @retval EFI_NOT_READY  HOB variable store info not available.
> > +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> > +  @retval EFI_SUCCESS    HOB variable store is available.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +IsHobVariableStoreAvailable (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  Get HOB variable store.
> > +
> > +  @param[out] StoreInfo             Return the store info.
> > +
> > +**/
> > +VOID
> > +GetHobVariableStore (
> > +  OUT VARIABLE_STORE_INFO  *StoreInfo
> > +  );
> > +
> > +/**
> > +  Get NV variable store.
> > +
> > +  @param[out] StoreInfo             Return the store info.
> > +  @param[out] VariableStoreHeader   Return header of FV containing the
> store.
> > +
> > +**/
> > +VOID
> > +GetNvVariableStore (
> > +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> > +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> > +  );
> > +
> > +/**
> > +  Return the variable store header and the store info based on the Index.
> > +
> > +  @param[in]  Type       The type of the variable store.
> > +  @param[out] StoreInfo  Return the store info.
> > +
> > +  @return  Pointer to the variable store header.
> > +**/
> > +VARIABLE_STORE_HEADER *
> > +GetVariableStore (
> > +  IN VARIABLE_STORE_TYPE   Type,
> > +  OUT VARIABLE_STORE_INFO  *StoreInfo
> > +  );
> > +
> > +/**
> > +  Make a cached copy of NV variable storage.
> > +
> > +  To save memory in PEI phase, only valid variables are copied into cache.
> > +  An IndexTable could be used to store the offset (relative to NV storage
> > +  base) of each copied variable, in case we need to restore the storage
> > +  as the same (valid) variables layout as in original one.
> > +
> > +  Variables with valid format and following state can be taken as valid:
> > +    - with state VAR_ADDED;
> > +    - with state VAR_IN_DELETED_TRANSITION but without the same variable
> > +      with state VAR_ADDED;
> > +    - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for
> variable
> > +      MetaDataHmacVar.
> > +
> > +  @param[out]     StoreCacheBase    Base address of variable storage cache.
> > +  @param[in,out]  StoreCacheSize    Size of space in StoreCacheBase.
> > +  @param[out]     IndexTable        Buffer of index (offset) table with entries of
> > +                                    VariableNumber.
> > +  @param[out]     VariableNumber    Number of valid variables.
> > +  @param[out]     AuthFlag          Aut-variable indicator.
> > +
> > +  @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or
> > StoreCacheBase.
> > +  @return EFI_VOLUME_CORRUPTED  Invalid or no NV variable storage found.
> > +  @return EFI_BUFFER_TOO_SMALL  StoreCacheSize is smaller than needed.
> > +  @return EFI_SUCCESS           NV variable storage is cached successfully.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +InitNvVariableStore (
> > +  OUT  EFI_PHYSICAL_ADDRESS  StoreCacheBase OPTIONAL,
> > +  IN OUT  UINT32             *StoreCacheSize,
> > +  OUT  UINT32                *IndexTable OPTIONAL,
> > +  OUT  UINT32                *VariableNumber OPTIONAL,
> > +  OUT  BOOLEAN               *AuthFlag OPTIONAL
> > +  );
> > +
> > +#endif
> > diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> > new file mode 100644
> > index 000000000000..ce790946626e
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> > @@ -0,0 +1,628 @@
> > +/** @file
> > +  Implement ReadOnly Variable Services required by PEIM and install
> > +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile
> storage
> > space.
> 
> [JianJW] typo: ' Varaiable2' -> ' Variable2'
> 
> > +
> > +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) Microsoft Corporation.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "Variable.h"
> > +#include "VariableParsing.h"
> > +#include "VariableStore.h"
> > +
> > +//
> > +// Module globals
> > +//
> > +EFI_PEI_READ_ONLY_VARIABLE2_PPI  mVariablePpi = {
> > +  PeiGetVariableEx,
> > +  PeiGetNextVariableNameEx
> > +};
> > +
> > +EFI_PEI_PPI_DESCRIPTOR  mPpiListVariable = {
> > +  (EFI_PEI_PPI_DESCRIPTOR_PPI |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> > +  &gEfiPeiReadOnlyVariable2PpiGuid,
> > +  &mVariablePpi
> > +};
> > +
> > +/**
> > +  Provide the functionality of the variable services.
> > +
> > +  @param  FileHandle   Handle of the file being invoked.
> > +                       Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
> > +  @param  PeiServices  General purpose services available to every PEIM.
> > +
> > +  @retval EFI_SUCCESS  If the interface could be successfully installed
> > +  @retval Others       Returned from PeiServicesInstallPpi()
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeimInitializeVariableServices (
> > +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> > +  IN CONST EFI_PEI_SERVICES     **PeiServices
> > +  )
> > +{
> > +  EFI_STATUS                     Status;
> > +  PROTECTED_VARIABLE_CONTEXT_IN  ContextIn;
> > +
> > +  //
> > +  // If protected variable services are not supported, EFI_UNSUPPORTED
> should
> > +  // be always returned. Check it here.
> > +  //
> > +  ContextIn.StructVersion =
> > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION;
> > +  ContextIn.StructSize    = sizeof (ContextIn);
> > +
> > +  ContextIn.MaxVariableSize             = 0;
> > +  ContextIn.VariableServiceUser         = FromPeiModule;
> > +  ContextIn.GetVariableInfo             = GetVariableInfo;
> > +  ContextIn.GetNextVariableInfo         = GetNextVariableInfo;
> > +  ContextIn.FindVariableSmm             = NULL;
> > +  ContextIn.UpdateVariableStore         = NULL;
> > +  ContextIn.UpdateVariable              = NULL;
> > +  ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable;
> > +
> > +  Status = ProtectedVariableLibInitialize (&ContextIn);
> > +  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
> > +    return Status;
> > +  }
> > +
> > +  return PeiServicesInstallPpi (&mPpiListVariable);
> > +}
> > +
> > +/**
> > +  Find the variable in the specified variable store.
> > +
> > +  @param  StoreInfo           Pointer to the store info structure.
> > +  @param  VariableName        Name of the variable to be found
> > +  @param  VendorGuid          Vendor GUID to be found.
> > +  @param  PtrTrack            Variable Track Pointer structure that contains
> > Variable Information.
> > +
> > +  @retval  EFI_SUCCESS            Variable found successfully
> > +  @retval  EFI_NOT_FOUND          Variable not found
> > +  @retval  EFI_INVALID_PARAMETER  Invalid variable name
> > +
> > +**/
> > +EFI_STATUS
> > +FindVariableEx (
> > +  IN VARIABLE_STORE_INFO      *StoreInfo,
> > +  IN CONST CHAR16             *VariableName,
> > +  IN CONST EFI_GUID           *VendorGuid,
> > +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> > +  )
> > +{
> > +  VARIABLE_HEADER        *Variable;
> > +  VARIABLE_HEADER        *LastVariable;
> > +  VARIABLE_HEADER        *MaxIndex;
> > +  UINTN                  Index;
> > +  UINTN                  Offset;
> > +  BOOLEAN                StopRecord;
> > +  VARIABLE_HEADER        *InDeletedVariable;
> > +  VARIABLE_STORE_HEADER  *VariableStoreHeader;
> > +  VARIABLE_INDEX_TABLE   *IndexTable;
> > +  VARIABLE_HEADER        *VariableHeader;
> > +
> > +  VariableStoreHeader = StoreInfo->VariableStoreHeader;
> > +
> > +  if (VariableStoreHeader == NULL) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  if (~VariableStoreHeader->Size == 0) {
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  IndexTable         = StoreInfo->IndexTable;
> > +  PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
> > +  PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader);
> > +
> > +  InDeletedVariable = NULL;
> > +
> > +  //
> > +  // No Variable Address equals zero, so 0 as initial value is safe.
> > +  //
> > +  MaxIndex       = NULL;
> > +  VariableHeader = NULL;
> > +
> > +  if (IndexTable != NULL) {
> > +    //
> > +    // traverse the variable index table to look for varible.
> > +    // The IndexTable->Index[Index] records the distance of two neighbouring
> > VAR_ADDED type variables.
> > +    //
> > +    for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
> > +      ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable-
> >Index[0]));
> > +      Offset  += IndexTable->Index[Index];
> > +      MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr +
> Offset);
> > +      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
> > +      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader,
> > VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
> > +        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> > VAR_ADDED)) {
> > +          InDeletedVariable = PtrTrack->CurrPtr;
> > +        } else {
> > +          return EFI_SUCCESS;
> > +        }
> > +      }
> > +    }
> > +
> > +    if (IndexTable->GoneThrough != 0) {
> > +      //
> > +      // If the table has all the existing variables indexed, return.
> > +      //
> > +      PtrTrack->CurrPtr = InDeletedVariable;
> > +      return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
> > +    }
> > +  }
> > +
> > +  if (MaxIndex != NULL) {
> > +    //
> > +    // HOB exists but the variable cannot be found in HOB
> > +    // If not found in HOB, then let's start from the MaxIndex we've found.
> > +    //
> > +    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
> > +    LastVariable = MaxIndex;
> > +  } else {
> > +    //
> > +    // Start Pointers for the variable.
> > +    // Actual Data Pointer where data can be written.
> > +    //
> > +    Variable     = PtrTrack->StartPtr;
> > +    LastVariable = PtrTrack->StartPtr;
> > +  }
> > +
> > +  //
> > +  // Find the variable by walk through variable store
> > +  //
> > +  StopRecord = FALSE;
> > +  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
> > +    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State ==
> > (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> > +      //
> > +      // Record Variable in VariableIndex HOB
> > +      //
> > +      if ((IndexTable != NULL) && !StopRecord) {
> > +        Offset = (UINTN)Variable - (UINTN)LastVariable;
> > +        if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable-
> >Index)
> > / sizeof (IndexTable->Index[0]))) {
> > +          //
> > +          // Stop to record if the distance of two neighbouring VAR_ADDED
> > variable is larger than the allowable scope(UINT16),
> > +          // or the record buffer is full.
> > +          //
> > +          StopRecord = TRUE;
> > +        } else {
> > +          IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;
> > +          LastVariable                            = Variable;
> > +        }
> > +      }
> > +
> > +      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader,
> > VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
> > +        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION &
> > VAR_ADDED)) {
> > +          InDeletedVariable = PtrTrack->CurrPtr;
> > +        } else {
> > +          return EFI_SUCCESS;
> > +        }
> > +      }
> > +    }
> > +
> > +    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
> > +  }
> > +
> > +  //
> > +  // If gone through the VariableStore, that means we never find in Firmware
> > any more.
> > +  //
> > +  if ((IndexTable != NULL) && !StopRecord) {
> > +    IndexTable->GoneThrough = 1;
> > +  }
> > +
> > +  PtrTrack->CurrPtr = InDeletedVariable;
> > +
> > +  return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  Find the variable in HOB and Non-Volatile variable storages.
> > +
> > +  @param  VariableName  Name of the variable to be found
> > +  @param  VendorGuid    Vendor GUID to be found.
> > +  @param  PtrTrack      Variable Track Pointer structure that contains Variable
> > Information.
> > +  @param  StoreInfo     Return the store info.
> > +
> > +  @retval  EFI_SUCCESS            Variable found successfully
> > +  @retval  EFI_NOT_FOUND          Variable not found
> > +  @retval  EFI_INVALID_PARAMETER  Invalid variable name
> > +**/
> > +EFI_STATUS
> > +FindVariable (
> > +  IN CONST  CHAR16            *VariableName,
> > +  IN CONST  EFI_GUID          *VendorGuid,
> > +  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
> > +  OUT VARIABLE_STORE_INFO     *StoreInfo
> > +  )
> > +{
> > +  EFI_STATUS           Status;
> > +  VARIABLE_STORE_TYPE  Type;
> > +
> > +  if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax;
> Type++)
> > {
> > +    GetVariableStore (Type, StoreInfo);
> > +    Status = FindVariableEx (
> > +               StoreInfo,
> > +               VariableName,
> > +               VendorGuid,
> > +               PtrTrack
> > +               );
> > +    if (!EFI_ERROR (Status)) {
> > +      return Status;
> > +    }
> > +  }
> > +
> > +  return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +  This service retrieves a variable's value using its name and GUID.
> > +
> > +  Read the specified variable from the UEFI variable store. If the Data
> > +  buffer is too small to hold the contents of the variable, the error
> > +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required
> buffer
> > +  size to obtain the data.
> > +
> > +  @param  This                  A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +  @param  VariableName          A pointer to a null-terminated string that is the
> > variable's name.
> > +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> > GUID. The combination of
> > +                                VariableGuid and VariableName must be unique.
> > +  @param  Attributes            If non-NULL, on return, points to the variable's
> > attributes.
> > +  @param  DataSize              On entry, points to the size in bytes of the Data
> > buffer.
> > +                                On return, points to the size of the data returned in Data.
> > +  @param  Data                  Points to the buffer which will hold the returned
> > variable value.
> > +                                May be NULL with a zero DataSize in order to determine the
> > size of the buffer needed.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable was be found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the
> resulting
> > data.
> > +                                DataSize is updated with the size required for
> > +                                the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> > Data is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetVariable (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN CONST  CHAR16                           *VariableName,
> > +  IN CONST  EFI_GUID                         *VariableGuid,
> > +  OUT       UINT32                           *Attributes,
> > +  IN OUT    UINTN                            *DataSize,
> > +  OUT       VOID                             *Data OPTIONAL
> > +  )
> > +{
> > +  VARIABLE_POINTER_TRACK  Variable;
> > +  UINTN                   VarDataSize;
> > +  EFI_STATUS              Status;
> > +  VARIABLE_STORE_INFO     StoreInfo;
> > +  VARIABLE_HEADER         *VariableHeader;
> > +
> > +  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL))
> {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (VariableName[0] == 0) {
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  VariableHeader = NULL;
> > +
> > +  //
> > +  // Find existing variable
> > +  //
> > +  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
> > +
> > +  //
> > +  // Get data size
> > +  //
> > +  VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
> > +  if (*DataSize >= VarDataSize) {
> > +    if (Data == NULL) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr,
> > VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
> > +    Status = EFI_SUCCESS;
> > +  } else {
> > +    Status = EFI_BUFFER_TOO_SMALL;
> > +  }
> > +
> > +  if (Attributes != NULL) {
> > +    *Attributes = VariableHeader->Attributes;
> > +  }
> > +
> > +  *DataSize = VarDataSize;
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Return the next variable name and GUID.
> > +
> > +  This function is called multiple times to retrieve the VariableName
> > +  and VariableGuid of all variables currently available in the system.
> > +  On each call, the previous results are passed into the interface,
> > +  and, on return, the interface returns the data for the next
> > +  interface. When the entire variable list has been returned,
> > +  EFI_NOT_FOUND is returned.
> > +
> > +  @param  This              A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +
> > +  @param  VariableNameSize  On entry, points to the size of the buffer
> pointed
> > to by VariableName.
> > +                            On return, the size of the variable name buffer.
> > +  @param  VariableName      On entry, a pointer to a null-terminated string
> that
> > is the variable's name.
> > +                            On return, points to the next variable's null-terminated name
> > string.
> > +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> > variable's GUID.
> > +                            On return, a pointer to the next variable's GUID.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable could not be found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for
> the
> > resulting
> > +                                data. VariableNameSize is updated with the size
> > +                                required for the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> > +                                VariableNameSize is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetNextVariableName (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN OUT UINTN                               *VariableNameSize,
> > +  IN OUT CHAR16                              *VariableName,
> > +  IN OUT EFI_GUID                            *VariableGuid
> > +  )
> > +{
> > +  VARIABLE_STORE_TYPE     Type;
> > +  VARIABLE_POINTER_TRACK  Variable;
> > +  VARIABLE_POINTER_TRACK  VariableInHob;
> > +  VARIABLE_POINTER_TRACK  VariablePtrTrack;
> > +  UINTN                   VarNameSize;
> > +  EFI_STATUS              Status;
> > +  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
> > +  VARIABLE_HEADER         *VariableHeader;
> > +  VARIABLE_STORE_INFO     StoreInfo;
> > +  VARIABLE_STORE_INFO     StoreInfoForNv;
> > +  VARIABLE_STORE_INFO     StoreInfoForHob;
> > +
> > +  if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize
> > == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  VariableHeader = NULL;
> > +
> > +  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
> > +  if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {
> > +    return Status;
> > +  }
> > +
> > +  if (VariableName[0] != 0) {
> > +    //
> > +    // If variable name is not NULL, get next variable
> > +    //
> > +    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
> > +    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> > VariableHeader);
> > +  }
> > +
> > +  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore
> > (VariableStoreTypeHob, &StoreInfoForHob);
> > +  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore
> > (VariableStoreTypeNv, &StoreInfoForNv);
> > +
> > +  while (TRUE) {
> > +    //
> > +    // Switch from HOB to Non-Volatile.
> > +    //
> > +    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader))
> {
> > +      //
> > +      // Find current storage index
> > +      //
> > +      for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax;
> > Type++) {
> > +        if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr ==
> > GetStartPointer (VariableStoreHeader[Type]))) {
> > +          break;
> > +        }
> > +      }
> > +
> > +      ASSERT (Type < VariableStoreTypeMax);
> > +      //
> > +      // Switch to next storage
> > +      //
> > +      for (Type++; Type < VariableStoreTypeMax; Type++) {
> > +        if (VariableStoreHeader[Type] != NULL) {
> > +          break;
> > +        }
> > +      }
> > +
> > +      //
> > +      // Capture the case that
> > +      // 1. current storage is the last one, or
> > +      // 2. no further storage
> > +      //
> > +      if (Type == VariableStoreTypeMax) {
> > +        return EFI_NOT_FOUND;
> > +      }
> > +
> > +      Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
> > +      Variable.EndPtr   = GetEndPointer (VariableStoreHeader[Type]);
> > +      Variable.CurrPtr  = Variable.StartPtr;
> > +      GetVariableStore (Type, &StoreInfo);
> > +    }
> > +
> > +    if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State ==
> > (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
> > +      if (VariableHeader->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.
> > +        //
> > +        Status = FindVariableEx (
> > +                   &StoreInfo,
> > +                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
> > +                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
> > +                   &VariablePtrTrack
> > +                   );
> > +        if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr))
> {
> > +          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> > VariableHeader);
> > +          continue;
> > +        }
> > +      }
> > +
> > +      //
> > +      // Don't return NV variable when HOB overrides it
> > +      //
> > +      if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) &&
> > (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
> > +          (Variable.StartPtr == GetStartPointer
> > (VariableStoreHeader[VariableStoreTypeNv]))
> > +          )
> > +      {
> > +        Status = FindVariableEx (
> > +                   &StoreInfoForHob,
> > +                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
> > +                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
> > +                   &VariableInHob
> > +                   );
> > +        if (!EFI_ERROR (Status)) {
> > +          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> > VariableHeader);
> > +          continue;
> > +        }
> > +      }
> > +
> > +      VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
> > +      ASSERT (VarNameSize != 0);
> > +
> > +      if (VarNameSize <= *VariableNameSize) {
> > +        GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr
> > (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);
> > +
> > +        CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader,
> > StoreInfo.AuthFlag), sizeof (EFI_GUID));
> > +
> > +        Status = EFI_SUCCESS;
> > +      } else {
> > +        Status = EFI_BUFFER_TOO_SMALL;
> > +      }
> > +
> > +      *VariableNameSize = VarNameSize;
> > +      //
> > +      // Variable is found
> > +      //
> > +      return Status;
> > +    } else {
> > +      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr,
> > VariableHeader);
> > +    }
> > +  }
> > +}
> > +
> > +/**
> > +  This service retrieves a variable's value using its name and GUID.
> > +
> > +  Read the specified variable from the UEFI variable store. If the Data
> > +  buffer is too small to hold the contents of the variable, the error
> > +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required
> buffer
> > +  size to obtain the data.
> > +
> > +  @param  This                  A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +  @param  VariableName          A pointer to a null-terminated string that is the
> > variable's name.
> > +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> > GUID. The combination of
> > +                                VariableGuid and VariableName must be unique.
> > +  @param  Attributes            If non-NULL, on return, points to the variable's
> > attributes.
> > +  @param  DataSize              On entry, points to the size in bytes of the Data
> > buffer.
> > +                                On return, points to the size of the data returned in Data.
> > +  @param  Data                  Points to the buffer which will hold the returned
> > variable value.
> > +                                May be NULL with a zero DataSize in order to determine the
> > size of the buffer needed.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable was be found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the
> resulting
> > data.
> > +                                DataSize is updated with the size required for
> > +                                the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> > Data is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetVariableEx (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN CONST  CHAR16                           *VariableName,
> > +  IN CONST  EFI_GUID                         *VariableGuid,
> > +  OUT       UINT32                           *Attributes,
> > +  IN OUT    UINTN                            *DataSize,
> > +  OUT       VOID                             *Data OPTIONAL
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +
> > +  //
> > +  // If variable protection is employed, always get variable data through
> > +  // ProtectedVariableLib.
> > +  //
> > +  Status = ProtectedVariableLibGetByName (VariableName, VariableGuid,
> > Attributes, DataSize, Data);
> > +  if (Status != EFI_UNSUPPORTED) {
> > +    return Status;
> > +  }
> > +
> > +  return PeiGetVariable (This, VariableName, VariableGuid, Attributes,
> DataSize,
> > Data);
> > +}
> > +
> > +/**
> > +  Return the next variable name and GUID.
> > +
> > +  This function is called multiple times to retrieve the VariableName
> > +  and VariableGuid of all variables currently available in the system.
> > +  On each call, the previous results are passed into the interface,
> > +  and, on return, the interface returns the data for the next
> > +  interface. When the entire variable list has been returned,
> > +  EFI_NOT_FOUND is returned.
> > +
> > +  @param  This              A pointer to this instance of the
> > EFI_PEI_READ_ONLY_VARIABLE2_PPI.
> > +
> > +  @param  VariableNameSize  On entry, points to the size of the buffer
> pointed
> > to by VariableName.
> > +                            On return, the size of the variable name buffer.
> > +  @param  VariableName      On entry, a pointer to a null-terminated string
> that
> > is the variable's name.
> > +                            On return, points to the next variable's null-terminated name
> > string.
> > +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> > variable's GUID.
> > +                            On return, a pointer to the next variable's GUID.
> > +
> > +  @retval EFI_SUCCESS           The variable was read successfully.
> > +  @retval EFI_NOT_FOUND         The variable could not be found.
> > +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for
> the
> > resulting
> > +                                data. VariableNameSize is updated with the size
> > +                                required for the specified variable.
> > +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> > +                                VariableNameSize is NULL.
> > +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because
> of
> > a device error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +PeiGetNextVariableNameEx (
> > +  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI  *This,
> > +  IN OUT UINTN                               *VariableNameSize,
> > +  IN OUT CHAR16                              *VariableName,
> > +  IN OUT EFI_GUID                            *VariableGuid
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +
> > +  //
> > +  // If variable protection is employed, always get next variable through
> > +  // ProtectedVariableLib.
> > +  //
> > +  Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName,
> > VariableGuid);
> > +  if (Status != EFI_UNSUPPORTED) {
> > +    return Status;
> > +  }
> > +
> > +  return PeiGetNextVariableName (This, VariableNameSize, VariableName,
> > VariableGuid);
> > +}
> > diff --git
> a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> > new file mode 100644
> > index 000000000000..2d605d39cbb6
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> > @@ -0,0 +1,941 @@
> > +/** @file
> > +  Implement ReadOnly Variable Services required by PEIM and install
> > +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile
> storage
> > space.
> 
> [JianJW] typo: ' Varaiable2' -> ' Variable2'
> 
> > +
> > +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "Variable.h"
> > +#include "VariableStore.h"
> > +
> > +/**
> > +
> > +  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);
> > +}
> > +
> > +/**
> > +  This code checks if variable header is valid or not.
> > +
> > +  @param[in]  Variable  Pointer to the Variable Header.
> > +
> > +  @retval TRUE      Variable header is valid.
> > +  @retval FALSE     Variable header is not valid.
> > +
> > +**/
> > +BOOLEAN
> > +IsValidVariableHeader (
> > +  IN  VARIABLE_HEADER  *Variable
> > +  )
> > +{
> > +  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> > +
> > +/**
> > +  This code gets the size of variable header.
> > +
> > +  @param[in] AuthFlag   Authenticated variable flag.
> > +
> > +  @return Size of variable header in bytes in type UINTN.
> > +
> > +**/
> > +UINTN
> > +GetVariableHeaderSize (
> > +  IN  BOOLEAN  AuthFlag
> > +  )
> > +{
> > +  UINTN  Value;
> > +
> > +  if (AuthFlag) {
> > +    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]  AuthFlag  Authenticated variable flag.
> > +
> > +  @return Size of variable in bytes in type UINTN.
> > +
> > +**/
> > +UINTN
> > +NameSizeOfVariable (
> > +  IN  VARIABLE_HEADER  *Variable,
> > +  IN  BOOLEAN          AuthFlag
> > +  )
> > +{
> > +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> > +
> > +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> > +  if (AuthFlag) {
> > +    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 gets the size of data of variable.
> > +
> > +  @param[in]  Variable  Pointer to the Variable Header.
> > +  @param[in]  AuthFlag  Authenticated variable flag.
> > +
> > +  @return Size of variable in bytes in type UINTN.
> > +
> > +**/
> > +UINTN
> > +DataSizeOfVariable (
> > +  IN  VARIABLE_HEADER  *Variable,
> > +  IN  BOOLEAN          AuthFlag
> > +  )
> > +{
> > +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> > +
> > +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> > +  if (AuthFlag) {
> > +    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 gets the pointer to the variable name.
> > +
> > +  @param[in]   Variable  Pointer to the Variable Header.
> > +  @param[in]   AuthFlag  Authenticated variable flag.
> > +
> > +  @return  A CHAR16* pointer to Variable Name.
> > +
> > +**/
> > +CHAR16 *
> > +GetVariableNamePtr (
> > +  IN VARIABLE_HEADER  *Variable,
> > +  IN BOOLEAN          AuthFlag
> > +  )
> > +{
> > +  return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));
> > +}
> > +
> > +/**
> > +  This code gets the pointer to the variable guid.
> > +
> > +  @param[in] Variable   Pointer to the Variable Header.
> > +  @param[in] AuthFlag   Authenticated variable flag.
> > +
> > +  @return A EFI_GUID* pointer to Vendor Guid.
> > +
> > +**/
> > +EFI_GUID *
> > +GetVendorGuidPtr (
> > +  IN VARIABLE_HEADER  *Variable,
> > +  IN BOOLEAN          AuthFlag
> > +  )
> > +{
> > +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> > +
> > +  AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> > +  if (AuthFlag) {
> > +    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]   VariableHeader   Pointer to the Variable Header that has
> > consecutive content.
> > +  @param[in]   AuthFlag         Authenticated variable flag.
> > +
> > +  @return  A UINT8* pointer to Variable Data.
> > +
> > +**/
> > +UINT8 *
> > +GetVariableDataPtr (
> > +  IN  VARIABLE_HEADER  *Variable,
> > +  IN  VARIABLE_HEADER  *VariableHeader,
> > +  IN  BOOLEAN          AuthFlag
> > +  )
> > +{
> > +  UINTN  Value;
> > +
> > +  //
> > +  // Be careful about pad size for alignment
> > +  //
> > +  Value  =  (UINTN)GetVariableNamePtr (Variable, AuthFlag);
> > +  Value += NameSizeOfVariable (VariableHeader, AuthFlag);
> > +  Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
> > +
> > +  return (UINT8 *)Value;
> > +}
> > +
> > +/**
> > +  This code gets the pointer to the next variable header.
> > +
> > +  @param[in]  StoreInfo         Pointer to variable store info structure.
> > +  @param[in]  Variable          Pointer to the Variable Header.
> > +  @param[in]  VariableHeader    Pointer to the Variable Header that has
> > consecutive content.
> > +
> > +  @return  A VARIABLE_HEADER* pointer to next variable header.
> > +
> > +**/
> > +VARIABLE_HEADER *
> > +GetNextVariablePtr (
> > +  IN  VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN  VARIABLE_HEADER      *Variable,
> > +  IN  VARIABLE_HEADER      *VariableHeader
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> > +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> > +  UINTN                 Value;
> > +
> > +  Value  =  (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo-
> > >AuthFlag);
> > +  Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
> > +  Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo-
> > >AuthFlag));
> > +  //
> > +  // Be careful about pad size for alignment
> > +  //
> > +  Value = HEADER_ALIGN (Value);
> > +
> > +  if (StoreInfo->FtwLastWriteData != NULL) {
> > +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> > +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> > +    if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >=
> > (UINTN)TargetAddress)) {
> > +      //
> > +      // Next variable is in spare block.
> > +      //
> > +      Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);
> > +    }
> > +  }
> > +
> > +  return (VARIABLE_HEADER *)Value;
> > +}
> > +
> > +/**
> > +  Compare two variable names, one of them may be inconsecutive.
> > +
> > +  @param[in] StoreInfo      Pointer to variable store info structure.
> > +  @param[in] Name1          Pointer to one variable name.
> > +  @param[in] Name2          Pointer to another variable name.
> > +  @param[in] NameSize       Variable name size.
> > +
> > +  @retval TRUE          Name1 and Name2 are identical.
> > +  @retval FALSE         Name1 and Name2 are not identical.
> > +
> > +**/
> > +BOOLEAN
> > +CompareVariableName (
> > +  IN VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN CONST CHAR16         *Name1,
> > +  IN CONST CHAR16         *Name2,
> > +  IN UINTN                NameSize
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> > +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> > +  UINTN                 PartialNameSize;
> > +
> > +  if (StoreInfo->FtwLastWriteData != NULL) {
> > +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> > +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> > +    if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 +
> > NameSize) > (UINTN)TargetAddress)) {
> > +      //
> > +      // Name1 is inconsecutive.
> > +      //
> > +      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;
> > +      //
> > +      // Partial content is in NV storage.
> > +      //
> > +      if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize)
> ==
> > 0) {
> > +        //
> > +        // Another partial content is in spare block.
> > +        //
> > +        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 +
> > PartialNameSize, NameSize - PartialNameSize) == 0) {
> > +          return TRUE;
> > +        }
> > +      }
> > +
> > +      return FALSE;
> > +    } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 +
> > NameSize) > (UINTN)TargetAddress)) {
> > +      //
> > +      // Name2 is inconsecutive.
> > +      //
> > +      PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;
> > +      //
> > +      // Partial content is in NV storage.
> > +      //
> > +      if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize)
> ==
> > 0) {
> > +        //
> > +        // Another partial content is in spare block.
> > +        //
> > +        if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 +
> > PartialNameSize, NameSize - PartialNameSize) == 0) {
> > +          return TRUE;
> > +        }
> > +      }
> > +
> > +      return FALSE;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Both Name1 and Name2 are consecutive.
> > +  //
> > +  if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {
> > +    return TRUE;
> > +  }
> > +
> > +  return FALSE;
> > +}
> > +
> > +/**
> > +  This function compares a variable with variable entries in database.
> > +
> > +  @param[in]   StoreInfo        Pointer to variable store info structure.
> > +  @param[in]   Variable         Pointer to the variable in our database
> > +  @param[in]   VariableHeader   Pointer to the Variable Header that has
> > +                                consecutive content.
> > +  @param[in]   VariableName     Name of the variable to compare to
> 'Variable'
> > +  @param[in]   VendorGuid       GUID of the variable to compare to 'Variable'
> > +  @param[out]  PtrTrack         Variable Track Pointer structure that contains
> > +                                Variable Information.
> > +
> > +  @retval EFI_SUCCESS    Found match variable
> > +  @retval EFI_NOT_FOUND  Variable not found
> > +
> > +**/
> > +EFI_STATUS
> > +CompareWithValidVariable (
> > +  IN  VARIABLE_STORE_INFO     *StoreInfo,
> > +  IN  VARIABLE_HEADER         *Variable,
> > +  IN  VARIABLE_HEADER         *VariableHeader,
> > +  IN  CONST CHAR16            *VariableName,
> > +  IN  CONST EFI_GUID          *VendorGuid,
> > +  OUT VARIABLE_POINTER_TRACK  *PtrTrack
> > +  )
> > +{
> > +  VOID      *Point;
> > +  EFI_GUID  *TempVendorGuid;
> > +
> > +  TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo-
> >AuthFlag);
> > +
> > +  if (VariableName[0] == 0) {
> > +    PtrTrack->CurrPtr = Variable;
> > +    return EFI_SUCCESS;
> > +  } else {
> > +    //
> > +    // Don't use CompareGuid function here for performance reasons.
> > +    // Instead we compare the GUID a UINT32 at a time and branch
> > +    // on the first failed comparison.
> > +    //
> > +    if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&
> > +        (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&
> > +        (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&
> > +        (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])
> > +        )
> > +    {
> > +      ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
> > +      Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
> > +      if (CompareVariableName (StoreInfo, VariableName, Point,
> > NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
> > +        PtrTrack->CurrPtr = Variable;
> > +        return EFI_SUCCESS;
> > +      }
> > +    }
> > +  }
> > +
> > +  return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +  Get variable header that has consecutive content.
> > +
> > +  @param[in]  StoreInfo       Pointer to variable store info structure.
> > +  @param[in]  Variable        Pointer to the Variable Header.
> > +  @param[out] VariableHeader  Pointer to Pointer to the Variable Header
> > +                              that has consecutive content.
> > +
> > +  @retval TRUE          Variable header is valid.
> > +  @retval FALSE         Variable header is not valid.
> > +
> > +**/
> > +BOOLEAN
> > +GetVariableHeader (
> > +  IN VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN VARIABLE_HEADER      *Variable,
> > +  OUT VARIABLE_HEADER     **VariableHeader
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> > +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> > +  EFI_HOB_GUID_TYPE     *GuidHob;
> > +  UINTN                 PartialHeaderSize;
> > +
> > +  if (Variable == NULL) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // First assume variable header pointed by Variable is consecutive.
> > +  //
> > +  *VariableHeader = Variable;
> > +
> > +  if (StoreInfo->FtwLastWriteData != NULL) {
> > +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> > +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> > +    if (((UINTN)Variable > (UINTN)SpareAddress) &&
> > +        (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >=
> > (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))
> > +    {
> > +      //
> > +      // Reach the end of variable store.
> > +      //
> > +      return FALSE;
> > +    }
> > +
> > +    if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable +
> > GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {
> > +      //
> > +      // Variable header pointed by Variable is inconsecutive,
> > +      // create a guid hob to combine the two partial variable header content
> > together.
> > +      //
> > +      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
> > +      if (GuidHob != NULL) {
> > +        *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA
> > (GuidHob);
> > +      } else {
> > +        *VariableHeader   = (VARIABLE_HEADER *)BuildGuidHob
> > (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
> > +        PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;
> > +        //
> > +        // Partial content is in NV storage.
> > +        //
> > +        CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable,
> > PartialHeaderSize);
> > +        //
> > +        // Another partial content is in spare block.
> > +        //
> > +        CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8
> > *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) -
> > PartialHeaderSize);
> > +      }
> > +    }
> > +  } else {
> > +    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
> > +      //
> > +      // Reach the end of variable store.
> > +      //
> > +      return FALSE;
> > +    }
> > +  }
> > +
> > +  return IsValidVariableHeader (*VariableHeader);
> > +}
> > +
> > +/**
> > +  Get variable name or data to output buffer.
> > +
> > +  @param[in]   StoreInfo     Pointer to variable store info structure.
> > +  @param[in]   NameOrData    Pointer to the variable name/data that may be
> > inconsecutive.
> > +  @param[in]   Size          Variable name/data size.
> > +  @param[out]  Buffer        Pointer to output buffer to hold the variable
> > name/data.
> > +
> > +**/
> > +VOID
> > +GetVariableNameOrData (
> > +  IN VARIABLE_STORE_INFO  *StoreInfo,
> > +  IN UINT8                *NameOrData,
> > +  IN UINTN                Size,
> > +  OUT UINT8               *Buffer
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  TargetAddress;
> > +  EFI_PHYSICAL_ADDRESS  SpareAddress;
> > +  UINTN                 PartialSize;
> > +
> > +  if (StoreInfo->FtwLastWriteData != NULL) {
> > +    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
> > +    SpareAddress  = StoreInfo->FtwLastWriteData->SpareAddress;
> > +    if (((UINTN)NameOrData < (UINTN)TargetAddress) &&
> > (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {
> > +      //
> > +      // Variable name/data is inconsecutive.
> > +      //
> > +      PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;
> > +      //
> > +      // Partial content is in NV storage.
> > +      //
> > +      CopyMem (Buffer, NameOrData, PartialSize);
> > +      //
> > +      // Another partial content is in spare block.
> > +      //
> > +      CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size -
> > PartialSize);
> > +      return;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Variable name/data is consecutive.
> > +  //
> > +  CopyMem (Buffer, NameOrData, Size);
> > +}
> > +
> > +/**
> > +
> > +  Internal function to retrieve variable information.
> > +
> > +  @param[in,out] VariableInfo     Pointer to variable information.
> > +  @param[in]     StoreInfo        Pointer to store copy of variable (optional).
> > +  @param[in]     VariablePtr      Pointer to variable buffer.
> > +  @param[in]     VariableHeader   Pointer to variable header.
> > +
> > +  @retval EFI_INVALID_PARAMETER  One ore more required parameters are
> > NULL.
> > +  @retval EFI_BUFFER_TOO_SMALL   Given buffer is too small to hold data.
> > +  @retval EFI_SUCCESS            Variable details are retrieved successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetVariableInfoInternal (
> > +  IN  OUT PROTECTED_VARIABLE_INFO  *VariableInfo,
> > +  IN      VARIABLE_STORE_INFO      *StoreInfo OPTIONAL,
> > +  IN      VARIABLE_HEADER          *VariablePtr,
> > +  IN      VARIABLE_HEADER          *VariableHeader
> > +  )
> > +{
> > +  VARIABLE_HEADER                *VariableBuffer;
> > +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariableHeader;
> > +  UINTN                          NameSize;
> > +  UINTN                          DataSize;
> > +  UINTN                          VariableSize;
> > +
> > +  if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader ==
> > NULL)) {
> > +    ASSERT (VariableInfo != NULL);
> > +    ASSERT (VariablePtr != NULL);
> > +    ASSERT (VariableHeader != NULL);
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  VariableBuffer = VariableInfo->Buffer;
> > +
> > +  //
> > +  // Make a copy of the whole variable if VariableInfo->Buffer is given. But
> > +  // don't do this if StoreInfo is not given, because VariableInfo->Buffer
> > +  // has already hold a copy of variable in such situation.
> > +  //
> > +  NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> > +  DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth);
> > +  if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) {
> > +    if (StoreInfo != NULL) {
> > +      CopyMem (
> > +        VariableBuffer,
> > +        VariableHeader,
> > +        GetVariableHeaderSize (VariableInfo->Flags.Auth)
> > +        );
> > +      GetVariableNameOrData (
> > +        StoreInfo,
> > +        (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> > +        NameSize,
> > +        (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth)
> > +        );
> > +      GetVariableNameOrData (
> > +        StoreInfo,
> > +        (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo-
> > >Flags.Auth),
> > +        DataSize,
> > +        (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader,
> > VariableInfo->Flags.Auth)
> > +        );
> > +    } else {
> > +      //
> > +      // Suppose the variable is in consecutive space.
> > +      //
> > +      VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth)
> > +                     + NameSize + GET_PAD_SIZE (NameSize)
> > +                     + DataSize;
> > +      CopyMem (VariableBuffer, VariablePtr, VariableSize);
> > +    }
> > +  }
> > +
> > +  //
> > +  // Generally, if no consecutive buffer passed in, don't return back any data.
> > +  //
> > +  // If follow pointers are NULL, return back pointers to following data inside
> > +  // VariableInfo->Buffer, if it's given.
> > +  //
> > +  //  VariableInfo->Header.VariableName
> > +  //  VariableInfo->Header.Data
> > +  //  VariableInfo->Header.VendorGuid
> > +  //  VariableInfo->Header.TimeStamp
> > +  //
> > +  // Otherwise, suppose they're buffers used to hold a copy of corresponding
> > +  // data.
> > +  //
> > +  //
> > +
> > +  //
> > +  // AuthVariable header
> > +  //
> > +  if (VariableInfo->Flags.Auth) {
> > +    AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER
> > *)VariableHeader;
> > +
> > +    VariableInfo->Header.State          = AuthVariableHeader->State;
> > +    VariableInfo->Header.Attributes     = AuthVariableHeader->Attributes;
> > +    VariableInfo->Header.PubKeyIndex    = AuthVariableHeader->PubKeyIndex;
> > +    VariableInfo->Header.MonotonicCount = ReadUnaligned64 (
> > +                                            &(AuthVariableHeader->MonotonicCount)
> > +                                            );
> > +    if (VariableInfo->Header.TimeStamp != NULL) {
> > +      CopyMem (
> > +        VariableInfo->Header.TimeStamp,
> > +        &AuthVariableHeader->TimeStamp,
> > +        sizeof (EFI_TIME)
> > +        );
> > +    } else if (VariableBuffer != NULL) {
> > +      AuthVariableHeader             = (AUTHENTICATED_VARIABLE_HEADER
> > *)VariableBuffer;
> > +      VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp;
> > +    }
> > +  } else {
> > +    VariableInfo->Header.State          = VariableHeader->State;
> > +    VariableInfo->Header.Attributes     = VariableHeader->Attributes;
> > +    VariableInfo->Header.PubKeyIndex    = 0;
> > +    VariableInfo->Header.MonotonicCount = 0;
> > +    VariableInfo->Header.TimeStamp      = NULL;
> > +  }
> > +
> > +  //
> > +  // VendorGuid
> > +  //
> > +  if (VariableInfo->Header.VendorGuid != NULL) {
> > +    CopyGuid (
> > +      VariableInfo->Header.VendorGuid,
> > +      GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth)
> > +      );
> > +  } else if (VariableBuffer != NULL) {
> > +    VariableInfo->Header.VendorGuid
> > +      = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth);
> > +  }
> > +
> > +  //
> > +  // VariableName
> > +  //
> > +  if (  (VariableInfo->Header.VariableName != NULL)
> > +     && (VariableInfo->Header.NameSize >= NameSize))
> > +  {
> > +    GetVariableNameOrData (
> > +      StoreInfo,
> > +      (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth),
> > +      NameSize,
> > +      (UINT8 *)VariableInfo->Header.VariableName
> > +      );
> > +  } else if (VariableBuffer != NULL) {
> > +    VariableInfo->Header.VariableName
> > +      = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth);
> > +  } else if (VariableInfo->Header.VariableName != NULL) {
> > +    return EFI_BUFFER_TOO_SMALL;
> > +  }
> > +
> > +  //
> > +  // Data
> > +  //
> > +  if (  (VariableInfo->Header.Data != NULL)
> > +     && (VariableInfo->Header.DataSize >= DataSize))
> > +  {
> > +    GetVariableNameOrData (
> > +      StoreInfo,
> > +      GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag),
> > +      DataSize,
> > +      VariableInfo->Header.Data
> > +      );
> > +  } else if (VariableBuffer != NULL) {
> > +    VariableInfo->Header.Data
> > +      = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo-
> > >Flags.Auth);
> > +  } else if (VariableInfo->Header.Data != NULL) {
> > +    return EFI_BUFFER_TOO_SMALL;
> > +  }
> > +
> > +  //
> > +  // Update size information about name & data.
> > +  //
> > +  VariableInfo->Header.NameSize = NameSize;
> > +  VariableInfo->Header.DataSize = DataSize;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +
> > +  Retrieve details about a variable, given by VariableInfo->Buffer or
> > +  VariableInfo->Index, and pass the details back in VariableInfo->Header.
> > +
> > +  This function is used to resolve the variable data structure into
> > +  VariableInfo->Header, for easier access later without revisiting the variable
> > +  data in variable store. If pointers in the structure of VariableInfo->Header
> > +  are not NULL, it's supposed that they are buffers passed in to hold a copy of
> > +  data of corresponding data fields in variable data structure. Otherwise, this
> > +  function simply returns pointers pointing to address of those data fields.
> > +
> > +  The variable is specified by either VariableInfo->Index or VariableInfo-
> >Buffer.
> > +  If VariableInfo->Index is given, this function finds the corresponding variable
> > +  first from variable storage according to the Index.
> > +
> > +  If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed
> > +  that VariableInfo->Buffer is a buffer passed in to hold a whole copy of
> > +  requested variable data to be returned.
> > +
> > +  @param[in,out] VariableInfo             Pointer to variable information.
> > +
> > +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL or both
> VariableInfo-
> > >Buffer
> > +                                 and VariableInfo->Index are NULL (0).
> > +  @retval EFI_NOT_FOUND          If given Buffer or Index 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_HEADER      *VariablePtr;
> > +  VARIABLE_HEADER      *VariableHeader;
> > +  VARIABLE_STORE_TYPE  StoreType;
> > +  VARIABLE_STORE_INFO  StoreInfo;
> > +  UINTN                Offset;
> > +
> > +  if ((VariableInfo == NULL) ||
> > +      ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex ==
> > VAR_INDEX_INVALID)))
> > +  {
> > +    ASSERT (VariableInfo != NULL);
> > +    ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo-
> > >Buffer != NULL);
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  StoreInfo.VariableStoreHeader = NULL;
> > +  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> > ++StoreType) {
> > +    GetVariableStore (StoreType, &StoreInfo);
> > +    if (StoreInfo.VariableStoreHeader != NULL) {
> > +      break;
> > +    }
> > +  }
> > +
> > +  ASSERT (StoreInfo.VariableStoreHeader != NULL);
> > +
> > +  //
> > +  // No StoreIndex? Don't retrieve variable information from store but just
> from
> > +  // VariableInfo->Buffer.
> > +  //
> > +  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> > +    VariablePtr    = VariableInfo->Buffer;
> > +    VariableHeader = VariablePtr;
> > +
> > +    return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr,
> > VariableHeader);
> > +  }
> > +
> > +  Offset = (UINTN)VariableInfo->StoreIndex;
> > +  if (  (StoreInfo.FtwLastWriteData != NULL)
> > +     && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> > +                    - (UINTN)StoreInfo.VariableStoreHeader)))
> > +  {
> > +    Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> > +               - (UINTN)StoreInfo.VariableStoreHeader);
> > +    VariablePtr = (VARIABLE_HEADER *)
> > +                  ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> > +  } else {
> > +    VariablePtr = (VARIABLE_HEADER *)
> > +                  ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> > +  }
> > +
> > +  //
> > +  // Note that variable might be in unconsecutive space. Always get a copy
> 
> [JianJW] typo: "unconsecutive" -> "inconsecutive"
> 
> > +  // of its header in consecutive buffer.
> > +  //
> > +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> > VariableHeader);
> > +}
> > +
> > +/**
> > +
> > +  Retrieve details of the variable next to given variable within VariableStore.
> > +
> > +  If VarInfo->Buffer is NULL, the first one in VariableStore is returned.
> > +
> > +  VariableStart and/or VariableEnd can be given optionally for the situation
> > +  in which the valid storage space is smaller than the VariableStore->Size.
> > +  This usually happens when PEI variable services make a compact variable
> > +  cache to save memory, which cannot make use VariableStore->Size to
> > determine
> > +  the correct variable storage range.
> > +
> > +  @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_HEADER      *VariablePtr;
> > +  VARIABLE_HEADER      *VariableHeader;
> > +  VARIABLE_STORE_INFO  StoreInfo;
> > +  VARIABLE_STORE_TYPE  StoreType;
> > +  UINTN                Offset;
> > +
> > +  if (VariableInfo == NULL) {
> > +    ASSERT (VariableInfo != NULL);
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  StoreInfo.VariableStoreHeader = NULL;
> > +  for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax;
> > ++StoreType) {
> > +    GetVariableStore (StoreType, &StoreInfo);
> > +    if (StoreInfo.VariableStoreHeader != NULL) {
> > +      break;
> > +    }
> > +  }
> > +
> > +  ASSERT (StoreInfo.VariableStoreHeader != NULL);
> > +
> > +  //
> > +  // VariableInfo->StoreIndex is supposed to be the index to variable found
> > +  // last time. Use it to get the variable next to it in store. If it's invalid,
> > +  // return the first variable available in store.
> > +  //
> > +  VariableInfo->Flags.Auth = StoreInfo.AuthFlag;
> > +  if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) {
> > +    VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader);
> > +  } else {
> > +    Offset = (UINTN)VariableInfo->StoreIndex;
> > +    if (  (StoreInfo.FtwLastWriteData != NULL)
> > +       && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> > +                      - (UINTN)StoreInfo.VariableStoreHeader)))
> > +    {
> > +      Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> > +                 - (UINTN)StoreInfo.VariableStoreHeader);
> > +      VariablePtr = (VARIABLE_HEADER *)
> > +                    ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset);
> > +    } else {
> > +      VariablePtr = (VARIABLE_HEADER *)
> > +                    ((UINTN)StoreInfo.VariableStoreHeader + Offset);
> > +    }
> > +
> > +    //
> > +    // Note that variable might be in unconsecutive space. Always get a copy
> 
> [JianJW] typo: "unconsecutive" -> "inconsecutive"
> 
> > +    // of its header in consecutive buffer.
> > +    //
> > +    if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> > +      return EFI_NOT_FOUND;
> > +    }
> > +
> > +    VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader);
> > +  }
> > +
> > +  //
> > +  // Get a copy of variable header in consecutive buffer.
> > +  //
> > +  if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) {
> > +    return EFI_NOT_FOUND;
> > +  }
> > +
> > +  //
> > +  // Use the offset to the start of variable store as index of the variable.
> > +  //
> > +  if (  (StoreInfo.FtwLastWriteData == NULL)
> > +     || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData-
> > >TargetAddress))
> > +  {
> > +    VariableInfo->StoreIndex
> > +      = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader);
> > +  } else {
> > +    VariableInfo->StoreIndex
> > +      = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress
> > +                 - (UINTN)StoreInfo.VariableStoreHeader);
> > +    VariableInfo->StoreIndex
> > +      += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData-
> > >SpareAddress);
> > +  }
> > +
> > +  if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL))
> {
> > +    VariableInfo->Buffer = VariablePtr;
> > +  }
> > +
> > +  return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr,
> > VariableHeader);
> > +}
> > diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> > new file mode 100644
> > index 000000000000..75edc3fc5051
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> > @@ -0,0 +1,307 @@
> > +/** @file
> > +  Implement ReadOnly Variable Services required by PEIM and install
> > +  PEI ReadOnly Varaiable2 PPI. These services operates the non volatile
> storage
> > space.
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +
> > +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "VariableParsing.h"
> > +#include "VariableStore.h"
> > +
> > +/**
> > +  Get variable store status.
> > +
> > +  @param[in]  VarStoreHeader  Pointer to the Variable Store Header.
> > +
> > +  @retval  EfiRaw      Variable store is raw
> > +  @retval  EfiValid    Variable store is valid
> > +  @retval  EfiInvalid  Variable store 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;
> > +  }
> > +
> > +  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;
> > +  }
> > +}
> > +
> > +/**
> > +  Reports HOB variable store is available or not.
> > +
> > +  @retval EFI_NOT_READY  HOB variable store info not available.
> > +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> > +  @retval EFI_SUCCESS    HOB variable store is available.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +IsHobVariableStoreAvailable (
> > +  VOID
> > +  )
> > +{
> > +  EFI_HOB_GUID_TYPE  *GuidHob;
> > +  VOID               *VariableStoreInfoHob;
> > +
> > +  //
> > +  // Discover if Variable Store Info Hob has been published by platform driver.
> > +  // It contains information regards to HOB or NV Variable Store availability
> > +  //
> > +  GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid);
> > +  if (GuidHob == NULL) {
> > +    return EFI_NOT_READY;
> > +  }
> > +
> > +  //
> > +  // Check if HOB Variable Store is available
> > +  //
> > +  VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob);
> > +  if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  //
> > +  // This might be NV Variable Store
> > +  //
> > +  return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +  Get HOB variable store.
> > +
> > +  @param[out] StoreInfo             Return the store info.
> > +
> > +**/
> > +VOID
> > +GetHobVariableStore (
> > +  OUT VARIABLE_STORE_INFO  *StoreInfo
> > +  )
> > +{
> > +  EFI_HOB_GUID_TYPE  *GuidHob;
> > +
> > +  //
> > +  // 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 ();
> > +
> > +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> > +  if (GuidHob != NULL) {
> > +    StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> > *)GET_GUID_HOB_DATA (GuidHob);
> > +    StoreInfo->AuthFlag            = TRUE;
> > +  } else {
> > +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> > +    if (GuidHob != NULL) {
> > +      StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER
> > *)GET_GUID_HOB_DATA (GuidHob);
> > +      StoreInfo->AuthFlag            = FALSE;
> > +    }
> > +  }
> > +}
> > +
> > +/**
> > +  Get NV variable store.
> > +
> > +  @param[out] StoreInfo             Return the store info.
> > +  @param[out] VariableFvHeader      Return header of FV containing the store.
> > +
> > +**/
> > +VOID
> > +GetNvVariableStore (
> > +  OUT VARIABLE_STORE_INFO         *StoreInfo,
> > +  OUT EFI_FIRMWARE_VOLUME_HEADER  **VariableFvHeader
> > +  )
> > +{
> > +  EFI_STATUS                            Status;
> > +  EFI_HOB_GUID_TYPE                     *GuidHob;
> > +  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
> > +  VARIABLE_STORE_HEADER                 *StoreHeader;
> > +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *HobData;
> > +  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
> > +  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
> > +  UINT32                                NvStorageSize;
> > +  UINT32                                BackUpOffset;
> > +  UINT64                                NvStorageSize64;
> > +
> > +  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);
> > +
> > +  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;
> > +
> > +  //
> > +  // Check the FTW last write data hob.
> > +  //
> > +  BackUpOffset     = 0;
> > +  FtwLastWriteData = NULL;
> > +  HobData          = NULL;
> > +  GuidHob          = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
> > +
> > +  if (GuidHob != NULL) {
> > +    HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
> > *)GET_GUID_HOB_DATA (GuidHob);
> > +    if (HobData->TargetAddress == NvStorageBase) {
> > +      //
> > +      // Let FvHeader point to spare block.
> > +      //
> > +      DEBUG ((
> > +        EFI_D_INFO,
> > +        "PeiVariable: NV storage is backed up in spare block: 0x%x\n",
> > +        (UINTN)HobData->SpareAddress
> > +        ));
> > +
> > +      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData-
> > >SpareAddress;
> > +      HobData  = NULL;
> > +    } else if ((HobData->TargetAddress > NvStorageBase) &&
> > +               (HobData->TargetAddress < (NvStorageBase + NvStorageSize)))
> > +    {
> > +      //
> > +      // Flash NV storage from the offset is backed up in spare block.
> > +      //
> > +      BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase);
> > +      DEBUG ((
> > +        EFI_D_INFO,
> > +        "PeiVariable: High partial NV storage from offset: %x is backed up in
> spare
> > block: 0x%x\n",
> > +        BackUpOffset,
> > +        (UINTN)FtwLastWriteData->SpareAddress
> > +        ));
> > +      //
> > +      // At least one block data in flash NV storage is still valid, so still
> > +      // leave FvHeader point to NV storage base.
> > +      //
> > +    }
> > +  }
> > +
> > +  if (StoreInfo != NULL) {
> > +    StoreInfo->FtwLastWriteData = HobData;
> > +  }
> > +
> > +  if (VariableFvHeader != NULL) {
> > +    *VariableFvHeader = FvHeader;
> > +  }
> > +
> > +  //
> > +  // Check if the Firmware Volume is not corrupted
> > +  //
> > +  if ((FvHeader->Signature == EFI_FVH_SIGNATURE) &&
> > +      CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))
> > +  {
> > +    StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader +
> FvHeader-
> > >HeaderLength);
> > +  } else {
> > +    StoreHeader = NULL;
> > +    DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is
> > corrupted\n"));
> > +  }
> > +
> > +  if (StoreInfo != NULL) {
> > +    StoreInfo->VariableStoreHeader = StoreHeader;
> > +    if (StoreHeader != NULL) {
> > +      StoreInfo->AuthFlag = CompareGuid (
> > +                              &StoreHeader->Signature,
> > +                              &gEfiAuthenticatedVariableGuid
> > +                              );
> > +    }
> > +  }
> > +}
> > +
> > +/**
> > +  Return the variable store header and the store info based on the Index.
> > +
> > +  @param[in]  Type       The type of the variable store.
> > +  @param[out] StoreInfo  Return the store info.
> > +
> > +  @return  Pointer to the variable store header.
> > +**/
> > +VARIABLE_STORE_HEADER *
> > +GetVariableStore (
> > +  IN VARIABLE_STORE_TYPE   Type,
> > +  OUT VARIABLE_STORE_INFO  *StoreInfo
> > +  )
> > +{
> > +  EFI_HOB_GUID_TYPE  *GuidHob;
> > +
> > +  StoreInfo->VariableStoreHeader = NULL;
> > +  StoreInfo->IndexTable          = NULL;
> > +  StoreInfo->FtwLastWriteData    = NULL;
> > +  StoreInfo->AuthFlag            = FALSE;
> > +  switch (Type) {
> > +    case VariableStoreTypeHob:
> > +      GetHobVariableStore (StoreInfo);
> > +      break;
> > +
> > +    case VariableStoreTypeNv:
> > +      if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
> > +        //
> > +        // Emulated non-volatile variable mode is not enabled.
> > +        //
> > +        GetNvVariableStore (StoreInfo, NULL);
> > +        if (StoreInfo->VariableStoreHeader != NULL) {
> > +          GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
> > +          if (GuidHob != NULL) {
> > +            StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
> > +          } else {
> > +            //
> > +            // If it's the first time to access variable region in flash, create a guid
> hob
> > to record
> > +            // VAR_ADDED type variable info.
> > +            // Note that as the resource of PEI phase is limited, only store the
> > limited number of
> > +            // VAR_ADDED type variables to reduce access time.
> > +            //
> > +            StoreInfo->IndexTable              = (VARIABLE_INDEX_TABLE
> > *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof
> (VARIABLE_INDEX_TABLE));
> > +            StoreInfo->IndexTable->Length      = 0;
> > +            StoreInfo->IndexTable->StartPtr    = GetStartPointer (StoreInfo-
> > >VariableStoreHeader);
> > +            StoreInfo->IndexTable->EndPtr      = GetEndPointer (StoreInfo-
> > >VariableStoreHeader);
> > +            StoreInfo->IndexTable->GoneThrough = 0;
> > +          }
> > +        }
> > +      }
> > +
> > +      break;
> > +
> > +    default:
> > +      ASSERT (FALSE);
> > +      break;
> > +  }
> > +
> > +  return StoreInfo->VariableStoreHeader;
> > +}
> > diff --git a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> > new file mode 100644
> > index 000000000000..106c1dfdc5c0
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> > @@ -0,0 +1,16 @@
> > +// /** @file
> > +// Implements ReadOnly Variable Services required by PEIM and installs PEI
> > ReadOnly Varaiable2 PPI.
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +//
> > +// This module implements ReadOnly Variable Services required by PEIM and
> > installs PEI ReadOnly Varaiable2 PPI.
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +//
> > +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> > +//
> > +// SPDX-License-Identifier: BSD-2-Clause-Patent
> > +//
> > +// **/
> > +
> > +
> > +#string STR_MODULE_ABSTRACT             #language en-US "Implements
> > ReadOnly Variable Services required by PEIM and installs PEI ReadOnly
> > Varaiable2 PPI"
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +
> > +#string STR_MODULE_DESCRIPTION          #language en-US "This module
> > implements ReadOnly Variable Services required by PEIM and installs PEI
> > ReadOnly Varaiable2 PPI."
> 
> [JianJW] typo: "Varaiable2" -> "Variable2"
> 
> > +
> > diff --git
> > a/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> > b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> > new file mode 100644
> > index 000000000000..22dd992be908
> > --- /dev/null
> > +++ b/MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> > @@ -0,0 +1,14 @@
> > +// /** @file
> > +// PeiVariable 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
> > +"Variable Access PEI Module"
> > +
> > +
> > --
> > 2.35.1.windows.2
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
  2022-11-06  7:34 ` [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Judah Vang
@ 2022-11-14  7:14   ` Wang, Jian J
  2022-11-14 17:19     ` Judah Vang
  0 siblings, 1 reply; 37+ messages in thread
From: Wang, Jian J @ 2022-11-14  7:14 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C

Hi Judah,

Just one comment:

For all header files, no need to remove the opening '_' of include guard macro.
Protected variable code are now in different folder than original variable driver.
They won't reference code from each other. Please add the opening '_' for those
macros to confirm to edk2 coding convention.

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
> Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
> 
> 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@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> t/VariableLockRequestToLockUnitTest.inf |   36 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> .inf                                   |  151 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
> |  153 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.inf                                |  119 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> Mm.inf                                 |  143 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphi
> c.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/VariableRuntimeCac
> he.h                                   |   51 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
> |  343 ++
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
> |  504 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> t/VariableLockRequestToLockUnitTest.c   |  607 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierD
> xe.c                                  |   27 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierS
> mm.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/VariableLockReques
> tToLock.c                              |   96 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile
> .c                                    |  537 +++
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
> | 1110 ++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmm
> Dxe.c                                   |  575 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac
> he.c                                   |  158 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
> | 1268 ++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.c                                  | 1895 +++++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> Mm.c                                   |   89 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditional
> Mm.c                                  |  130 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> .uni                                   |   22 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> Extra.uni                              |   14 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
> |   27 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.u
> ni                                     |   14 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.uni                                |   23 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxeExtra.uni                           |   14 +
>  36 files changed, 15676 insertions(+)
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.inf
> new file mode 100644
> index 000000000000..586d877fca90
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/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/VariableRuntimeD
> xe.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.inf
> new file mode 100644
> index 000000000000..6adc2c636e84
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.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/VariableSmmRunt
> imeDxe.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.inf
> new file mode 100644
> index 000000000000..0d169913c9c9
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.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/VariableStandalon
> eMm.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.inf
> new file mode 100644
> index 000000000000..fb5a6c947890
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.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/PrivilegePolymorp
> hic.h
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
> hic.h
> new file mode 100644
> index 000000000000..7f14515b694f
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
> hic.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.

[JianJW] Too long line. Wrap it to within 80 characters for each line.

> +
> +  @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/VariableNonVolat
> ile.h
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.h
> new file mode 100644
> index 000000000000..a84db4877c13
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.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/VariableRuntimeC
> ache.h
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.h
> new file mode 100644
> index 000000000000..77dbce0f907c
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.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/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.c
> new file mode 100644
> index 000000000000..b2bcb97932ba
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/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/SpeculationBarrie
> rDxe.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rDxe.c
> new file mode 100644
> index 000000000000..b219ea9ec074
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rDxe.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/SpeculationBarrie
> rSmm.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rSmm.c
> new file mode 100644
> index 000000000000..7107c042928e
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rSmm.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.Stor
> e != NULL) {
> +      Status =  SynchronizeRuntimeVariableCache (
> +                  &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
> +                  0,
> +                  mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Stor
> e->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/VariableLockRequ
> estToLock.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
> estToLock.c
> new file mode 100644
> index 000000000000..d849ee9ce292
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
> estToLock.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/VariableNonVolat
> ile.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.c
> new file mode 100644
> index 000000000000..32dd9901b260
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.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/VariablePolicySm
> mDxe.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
> mDxe.c
> new file mode 100644
> index 000000000000..b2094fbcd6ea
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
> mDxe.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/VariableRuntimeC
> ache.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.c
> new file mode 100644
> index 000000000000..9bb30bc1e804
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.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/VariableSmmRunt
> imeDxe.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.c
> new file mode 100644
> index 000000000000..b88f75370ad8
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.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/VariableStandalon
> eMm.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.c
> new file mode 100644
> index 000000000000..943993eb6738
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.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/VariableTradition
> alMm.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
> alMm.c
> new file mode 100644
> index 000000000000..0369c3cd01b1
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
> alMm.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/VariableRuntimeD
> xe.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.uni
> new file mode 100644
> index 000000000000..227b8c6fad24
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.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/VariableRuntimeD
> xeExtra.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xeExtra.uni
> new file mode 100644
> index 000000000000..f0976418ff81
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xeExtra.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/VariableSmmExtr
> a.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
> a.uni
> new file mode 100644
> index 000000000000..f724209f3dc2
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
> a.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/VariableSmmRunt
> imeDxe.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.uni
> new file mode 100644
> index 000000000000..9639f00077a0
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.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/VariableSmmRunt
> imeDxeExtra.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxeExtra.uni
> new file mode 100644
> index 000000000000..bbabdf82736b
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxeExtra.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


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
  2022-11-14  7:14   ` Wang, Jian J
@ 2022-11-14 17:19     ` Judah Vang
  2022-11-15  8:49       ` [edk2-devel] " Sami Mujawar
  0 siblings, 1 reply; 37+ messages in thread
From: Judah Vang @ 2022-11-14 17:19 UTC (permalink / raw)
  To: Wang, Jian J, devel@edk2.groups.io
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C

Jian,

That's not the reason why I removed the leading '_' underscore.
When I don't remove it, the EDK2 CI is giving me a fail and telling me it needs to be removed.
I don't know why this is the case but it seems to only happen for new files.

Judah

-----Original Message-----
From: Wang, Jian J <jian.j.wang@intel.com> 
Sent: Sunday, November 13, 2022 11:14 PM
To: Vang, Judah <judah.vang@intel.com>; devel@edk2.groups.io
Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>
Subject: RE: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables

Hi Judah,

Just one comment:

For all header files, no need to remove the opening '_' of include guard macro.
Protected variable code are now in different folder than original variable driver.
They won't reference code from each other. Please add the opening '_' for those
macros to confirm to edk2 coding convention.

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
> Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
> 
> 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@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> t/VariableLockRequestToLockUnitTest.inf |   36 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> .inf                                   |  151 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
> |  153 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.inf                                |  119 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> Mm.inf                                 |  143 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphi
> c.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/VariableRuntimeCac
> he.h                                   |   51 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
> |  343 ++
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
> |  504 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> t/VariableLockRequestToLockUnitTest.c   |  607 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierD
> xe.c                                  |   27 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierS
> mm.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/VariableLockReques
> tToLock.c                              |   96 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile
> .c                                    |  537 +++
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
> | 1110 ++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmm
> Dxe.c                                   |  575 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac
> he.c                                   |  158 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
> | 1268 ++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.c                                  | 1895 +++++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> Mm.c                                   |   89 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditional
> Mm.c                                  |  130 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> .uni                                   |   22 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> Extra.uni                              |   14 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
> |   27 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.u
> ni                                     |   14 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.uni                                |   23 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxeExtra.uni                           |   14 +
>  36 files changed, 15676 insertions(+)
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.inf
> new file mode 100644
> index 000000000000..586d877fca90
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/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/VariableRuntimeD
> xe.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.inf
> new file mode 100644
> index 000000000000..6adc2c636e84
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.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/VariableSmmRunt
> imeDxe.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.inf
> new file mode 100644
> index 000000000000..0d169913c9c9
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.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/VariableStandalon
> eMm.inf
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.inf
> new file mode 100644
> index 000000000000..fb5a6c947890
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.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/PrivilegePolymorp
> hic.h
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
> hic.h
> new file mode 100644
> index 000000000000..7f14515b694f
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
> hic.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.

[JianJW] Too long line. Wrap it to within 80 characters for each line.

> +
> +  @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/VariableNonVolat
> ile.h
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.h
> new file mode 100644
> index 000000000000..a84db4877c13
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.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/VariableRuntimeC
> ache.h
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.h
> new file mode 100644
> index 000000000000..77dbce0f907c
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.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/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/VariableLockRequestToLockUnitTest.c
> new file mode 100644
> index 000000000000..b2bcb97932ba
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> est/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/SpeculationBarrie
> rDxe.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rDxe.c
> new file mode 100644
> index 000000000000..b219ea9ec074
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rDxe.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/SpeculationBarrie
> rSmm.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rSmm.c
> new file mode 100644
> index 000000000000..7107c042928e
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> rSmm.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.Stor
> e != NULL) {
> +      Status =  SynchronizeRuntimeVariableCache (
> +                  &mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
> +                  0,
> +                  mVariableModuleGlobal-
> >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Stor
> e->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/VariableLockRequ
> estToLock.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
> estToLock.c
> new file mode 100644
> index 000000000000..d849ee9ce292
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
> estToLock.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/VariableNonVolat
> ile.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.c
> new file mode 100644
> index 000000000000..32dd9901b260
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> ile.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/VariablePolicySm
> mDxe.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
> mDxe.c
> new file mode 100644
> index 000000000000..b2094fbcd6ea
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
> mDxe.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/VariableRuntimeC
> ache.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.c
> new file mode 100644
> index 000000000000..9bb30bc1e804
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> ache.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/VariableSmmRunt
> imeDxe.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.c
> new file mode 100644
> index 000000000000..b88f75370ad8
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.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/VariableStandalon
> eMm.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.c
> new file mode 100644
> index 000000000000..943993eb6738
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> eMm.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/VariableTradition
> alMm.c
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
> alMm.c
> new file mode 100644
> index 000000000000..0369c3cd01b1
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
> alMm.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/VariableRuntimeD
> xe.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.uni
> new file mode 100644
> index 000000000000..227b8c6fad24
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xe.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/VariableRuntimeD
> xeExtra.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xeExtra.uni
> new file mode 100644
> index 000000000000..f0976418ff81
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> xeExtra.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/VariableSmmExtr
> a.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
> a.uni
> new file mode 100644
> index 000000000000..f724209f3dc2
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
> a.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/VariableSmmRunt
> imeDxe.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.uni
> new file mode 100644
> index 000000000000..9639f00077a0
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxe.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/VariableSmmRunt
> imeDxeExtra.uni
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxeExtra.uni
> new file mode 100644
> index 000000000000..bbabdf82736b
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> imeDxeExtra.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


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
  2022-11-14 17:19     ` Judah Vang
@ 2022-11-15  8:49       ` Sami Mujawar
  2022-11-22  6:26         ` Wang, Jian J
       [not found]         ` <1729D430BF77E016.5511@groups.io>
  0 siblings, 2 replies; 37+ messages in thread
From: Sami Mujawar @ 2022-11-15  8:49 UTC (permalink / raw)
  To: devel@edk2.groups.io, judah.vang@intel.com, Wang, Jian J
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C, nd

Hi All,

I believe the EDKII CI is following the edk2-Coding standard rule 5.3.5 which forbids prefixing file include guard macro names with '_', see https://edk2-docs.gitbook.io/edk-ii-c-coding-standards-specification/v/release-2.20/5_source_files/53_include_files#5.3.5-all-include-file-contents-must-be-protected-by-a-include-guard

If I understand correctly the edk2 CI runs uncrustify on the patch diff. Therefore, unless you touch the macro in an existing file, it would not complain. 

Regards,

Sami Mujawar

On 14/11/2022, 17:20, "devel@edk2.groups.io on behalf of Judah Vang via groups.io" <devel@edk2.groups.io on behalf of judah.vang=intel.com@groups.io> wrote:

    Jian,

    That's not the reason why I removed the leading '_' underscore.
    When I don't remove it, the EDK2 CI is giving me a fail and telling me it needs to be removed.
    I don't know why this is the case but it seems to only happen for new files.

    Judah

    -----Original Message-----
    From: Wang, Jian J <jian.j.wang@intel.com> 
    Sent: Sunday, November 13, 2022 11:14 PM
    To: Vang, Judah <judah.vang@intel.com>; devel@edk2.groups.io
    Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>
    Subject: RE: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables

    Hi Judah,

    Just one comment:

    For all header files, no need to remove the opening '_' of include guard macro.
    Protected variable code are now in different folder than original variable driver.
    They won't reference code from each other. Please add the opening '_' for those
    macros to confirm to edk2 coding convention.

    Regards,
    Jian

    > -----Original Message-----
    > From: Vang, Judah <judah.vang@intel.com>
    > Sent: Sunday, November 06, 2022 3:35 PM
    > To: devel@edk2.groups.io
    > Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
    > <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
    > Nishant C <nishant.c.mistry@intel.com>
    > Subject: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
    > 
    > 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@intel.com>
    > Cc: Liming Gao <gaoliming@byosoft.com.cn>
    > Cc: Hao A Wu <hao.a.wu@intel.com>
    > Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
    > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
    > Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
    > Signed-off-by: Judah Vang <judah.vang@intel.com>
    > ---
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
    > t/VariableLockRequestToLockUnitTest.inf |   36 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
    > .inf                                   |  151 +
    >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
    > |  153 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
    > eDxe.inf                                |  119 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
    > Mm.inf                                 |  143 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphi
    > c.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/VariableRuntimeCac
    > he.h                                   |   51 +
    >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
    > |  343 ++
    >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
    > |  504 +++
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
    > t/VariableLockRequestToLockUnitTest.c   |  607 +++
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierD
    > xe.c                                  |   27 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierS
    > mm.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/VariableLockReques
    > tToLock.c                              |   96 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile
    > .c                                    |  537 +++
    >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
    > | 1110 ++++++
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmm
    > Dxe.c                                   |  575 +++
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac
    > he.c                                   |  158 +
    >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
    > | 1268 ++++++
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
    > eDxe.c                                  | 1895 +++++++++
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
    > Mm.c                                   |   89 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditional
    > Mm.c                                  |  130 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
    > .uni                                   |   22 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
    > Extra.uni                              |   14 +
    >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
    > |   27 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.u
    > ni                                     |   14 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
    > eDxe.uni                                |   23 +
    > 
    > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
    > eDxeExtra.uni                           |   14 +
    >  36 files changed, 15676 insertions(+)
    > 
    > diff --git
    > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
    > est/VariableLockRequestToLockUnitTest.inf
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
    > est/VariableLockRequestToLockUnitTest.inf
    > new file mode 100644
    > index 000000000000..586d877fca90
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
    > est/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/VariableRuntimeD
    > xe.inf
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
    > xe.inf
    > new file mode 100644
    > index 000000000000..6adc2c636e84
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
    > xe.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/VariableSmmRunt
    > imeDxe.inf
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxe.inf
    > new file mode 100644
    > index 000000000000..0d169913c9c9
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxe.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/VariableStandalon
    > eMm.inf
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
    > eMm.inf
    > new file mode 100644
    > index 000000000000..fb5a6c947890
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
    > eMm.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/PrivilegePolymorp
    > hic.h
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
    > hic.h
    > new file mode 100644
    > index 000000000000..7f14515b694f
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
    > hic.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.

    [JianJW] Too long line. Wrap it to within 80 characters for each line.

    > +
    > +  @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/VariableNonVolat
    > ile.h
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
    > ile.h
    > new file mode 100644
    > index 000000000000..a84db4877c13
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
    > ile.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/VariableRuntimeC
    > ache.h
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
    > ache.h
    > new file mode 100644
    > index 000000000000..77dbce0f907c
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
    > ache.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/RuntimeDxeUnitT
    > est/VariableLockRequestToLockUnitTest.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
    > est/VariableLockRequestToLockUnitTest.c
    > new file mode 100644
    > index 000000000000..b2bcb97932ba
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
    > est/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/SpeculationBarrie
    > rDxe.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
    > rDxe.c
    > new file mode 100644
    > index 000000000000..b219ea9ec074
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
    > rDxe.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/SpeculationBarrie
    > rSmm.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
    > rSmm.c
    > new file mode 100644
    > index 000000000000..7107c042928e
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
    > rSmm.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.Stor
    > e != NULL) {
    > +      Status =  SynchronizeRuntimeVariableCache (
    > +                  &mVariableModuleGlobal-
    > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
    > +                  0,
    > +                  mVariableModuleGlobal-
    > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Stor
    > e->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/VariableLockRequ
    > estToLock.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
    > estToLock.c
    > new file mode 100644
    > index 000000000000..d849ee9ce292
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
    > estToLock.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/VariableNonVolat
    > ile.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
    > ile.c
    > new file mode 100644
    > index 000000000000..32dd9901b260
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
    > ile.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/VariablePolicySm
    > mDxe.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
    > mDxe.c
    > new file mode 100644
    > index 000000000000..b2094fbcd6ea
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
    > mDxe.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/VariableRuntimeC
    > ache.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
    > ache.c
    > new file mode 100644
    > index 000000000000..9bb30bc1e804
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
    > ache.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/VariableSmmRunt
    > imeDxe.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxe.c
    > new file mode 100644
    > index 000000000000..b88f75370ad8
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxe.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/VariableStandalon
    > eMm.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
    > eMm.c
    > new file mode 100644
    > index 000000000000..943993eb6738
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
    > eMm.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/VariableTradition
    > alMm.c
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
    > alMm.c
    > new file mode 100644
    > index 000000000000..0369c3cd01b1
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
    > alMm.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/VariableRuntimeD
    > xe.uni
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
    > xe.uni
    > new file mode 100644
    > index 000000000000..227b8c6fad24
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
    > xe.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/VariableRuntimeD
    > xeExtra.uni
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
    > xeExtra.uni
    > new file mode 100644
    > index 000000000000..f0976418ff81
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
    > xeExtra.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/VariableSmmExtr
    > a.uni
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
    > a.uni
    > new file mode 100644
    > index 000000000000..f724209f3dc2
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
    > a.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/VariableSmmRunt
    > imeDxe.uni
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxe.uni
    > new file mode 100644
    > index 000000000000..9639f00077a0
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxe.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/VariableSmmRunt
    > imeDxeExtra.uni
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxeExtra.uni
    > new file mode 100644
    > index 000000000000..bbabdf82736b
    > --- /dev/null
    > +++
    > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
    > imeDxeExtra.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



    




^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
  2022-11-15  8:49       ` [edk2-devel] " Sami Mujawar
@ 2022-11-22  6:26         ` Wang, Jian J
       [not found]         ` <1729D430BF77E016.5511@groups.io>
  1 sibling, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:26 UTC (permalink / raw)
  To: devel@edk2.groups.io, sami.mujawar@arm.com, Vang, Judah
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C, nd

Thanks for sharing the info. It looks that my coding style knowledge needs refresh.

Regards,
Jian

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Sami
> Mujawar
> Sent: Tuesday, November 15, 2022 4:49 PM
> To: devel@edk2.groups.io; Vang, Judah <judah.vang@intel.com>; Wang, Jian J
> <jian.j.wang@intel.com>
> Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A
> <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>; nd
> <nd@arm.com>
> Subject: Re: [edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for
> Protected Variables
> 
> Hi All,
> 
> I believe the EDKII CI is following the edk2-Coding standard rule 5.3.5 which
> forbids prefixing file include guard macro names with '_', see https://edk2-
> docs.gitbook.io/edk-ii-c-coding-standards-specification/v/release-
> 2.20/5_source_files/53_include_files#5.3.5-all-include-file-contents-must-be-
> protected-by-a-include-guard
> 
> If I understand correctly the edk2 CI runs uncrustify on the patch diff. Therefore,
> unless you touch the macro in an existing file, it would not complain.
> 
> Regards,
> 
> Sami Mujawar
> 
> On 14/11/2022, 17:20, "devel@edk2.groups.io on behalf of Judah Vang via
> groups.io" <devel@edk2.groups.io on behalf of
> judah.vang=intel.com@groups.io> wrote:
> 
>     Jian,
> 
>     That's not the reason why I removed the leading '_' underscore.
>     When I don't remove it, the EDK2 CI is giving me a fail and telling me it needs
> to be removed.
>     I don't know why this is the case but it seems to only happen for new files.
> 
>     Judah
> 
>     -----Original Message-----
>     From: Wang, Jian J <jian.j.wang@intel.com>
>     Sent: Sunday, November 13, 2022 11:14 PM
>     To: Vang, Judah <judah.vang@intel.com>; devel@edk2.groups.io
>     Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A
> <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>
>     Subject: RE: [PATCH v5 08/19] MdeModulePkg: Add support for Protected
> Variables
> 
>     Hi Judah,
> 
>     Just one comment:
> 
>     For all header files, no need to remove the opening '_' of include guard macro.
>     Protected variable code are now in different folder than original variable
> driver.
>     They won't reference code from each other. Please add the opening '_' for
> those
>     macros to confirm to edk2 coding convention.
> 
>     Regards,
>     Jian
> 
>     > -----Original Message-----
>     > From: Vang, Judah <judah.vang@intel.com>
>     > Sent: Sunday, November 06, 2022 3:35 PM
>     > To: devel@edk2.groups.io
>     > Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
>     > <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
>     > Nishant C <nishant.c.mistry@intel.com>
>     > Subject: [PATCH v5 08/19] MdeModulePkg: Add support for Protected
> Variables
>     >
>     > 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@intel.com>
>     > Cc: Liming Gao <gaoliming@byosoft.com.cn>
>     > Cc: Hao A Wu <hao.a.wu@intel.com>
>     > Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
>     > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
>     > Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
>     > Signed-off-by: Judah Vang <judah.vang@intel.com>
>     > ---
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
>     > t/VariableLockRequestToLockUnitTest.inf |   36 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
>     > .inf                                   |  151 +
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
>     > |  153 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
>     > eDxe.inf                                |  119 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
>     > Mm.inf                                 |  143 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphi
>     > c.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/VariableRuntimeCac
>     > he.h                                   |   51 +
>     >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
>     > |  343 ++
>     >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
>     > |  504 +++
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
>     > t/VariableLockRequestToLockUnitTest.c   |  607 +++
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierD
>     > xe.c                                  |   27 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierS
>     > mm.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/VariableLockReques
>     > tToLock.c                              |   96 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile
>     > .c                                    |  537 +++
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
>     > | 1110 ++++++
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmm
>     > Dxe.c                                   |  575 +++
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac
>     > he.c                                   |  158 +
>     >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
>     > | 1268 ++++++
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
>     > eDxe.c                                  | 1895 +++++++++
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
>     > Mm.c                                   |   89 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditional
>     > Mm.c                                  |  130 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
>     > .uni                                   |   22 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
>     > Extra.uni                              |   14 +
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
>     > |   27 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.u
>     > ni                                     |   14 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
>     > eDxe.uni                                |   23 +
>     >
>     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
>     > eDxeExtra.uni                           |   14 +
>     >  36 files changed, 15676 insertions(+)
>     >
>     > diff --git
>     >
> a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
>     > est/VariableLockRequestToLockUnitTest.inf
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
>     > est/VariableLockRequestToLockUnitTest.inf
>     > new file mode 100644
>     > index 000000000000..586d877fca90
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
>     > est/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/VariableRuntimeD
>     > xe.inf
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
>     > xe.inf
>     > new file mode 100644
>     > index 000000000000..6adc2c636e84
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
>     > xe.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/VariableSmmRunt
>     > imeDxe.inf
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxe.inf
>     > new file mode 100644
>     > index 000000000000..0d169913c9c9
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxe.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/VariableStandalon
>     > eMm.inf
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
>     > eMm.inf
>     > new file mode 100644
>     > index 000000000000..fb5a6c947890
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
>     > eMm.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/PrivilegePolymorp
>     > hic.h
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
>     > hic.h
>     > new file mode 100644
>     > index 000000000000..7f14515b694f
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
>     > hic.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.
> 
>     [JianJW] Too long line. Wrap it to within 80 characters for each line.
> 
>     > +
>     > +  @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/VariableNonVolat
>     > ile.h
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
>     > ile.h
>     > new file mode 100644
>     > index 000000000000..a84db4877c13
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
>     > ile.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/VariableRuntimeC
>     > ache.h
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
>     > ache.h
>     > new file mode 100644
>     > index 000000000000..77dbce0f907c
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
>     > ache.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.VariableRuntimeVolatileCac
> he,
>     > +                   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/RuntimeDxeUnitT
>     > est/VariableLockRequestToLockUnitTest.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
>     > est/VariableLockRequestToLockUnitTest.c
>     > new file mode 100644
>     > index 000000000000..b2bcb97932ba
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
>     > est/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/SpeculationBarrie
>     > rDxe.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
>     > rDxe.c
>     > new file mode 100644
>     > index 000000000000..b219ea9ec074
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
>     > rDxe.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/SpeculationBarrie
>     > rSmm.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
>     > rSmm.c
>     > new file mode 100644
>     > index 000000000000..7107c042928e
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
>     > rSmm.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.S
> tor
>     > e != NULL) {
>     > +      Status =  SynchronizeRuntimeVariableCache (
>     > +                  &mVariableModuleGlobal-
>     > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
>     > +                  0,
>     > +                  mVariableModuleGlobal-
>     > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.S
> tor
>     > e->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/VariableLockRequ
>     > estToLock.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
>     > estToLock.c
>     > new file mode 100644
>     > index 000000000000..d849ee9ce292
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
>     > estToLock.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/VariableNonVolat
>     > ile.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
>     > ile.c
>     > new file mode 100644
>     > index 000000000000..32dd9901b260
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
>     > ile.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/VariablePolicySm
>     > mDxe.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
>     > mDxe.c
>     > new file mode 100644
>     > index 000000000000..b2094fbcd6ea
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
>     > mDxe.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/VariableRuntimeC
>     > ache.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
>     > ache.c
>     > new file mode 100644
>     > index 000000000000..9bb30bc1e804
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
>     > ache.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/VariableSmmRunt
>     > imeDxe.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxe.c
>     > new file mode 100644
>     > index 000000000000..b88f75370ad8
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxe.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/VariableStandalon
>     > eMm.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
>     > eMm.c
>     > new file mode 100644
>     > index 000000000000..943993eb6738
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
>     > eMm.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/VariableTradition
>     > alMm.c
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
>     > alMm.c
>     > new file mode 100644
>     > index 000000000000..0369c3cd01b1
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
>     > alMm.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/VariableRuntimeD
>     > xe.uni
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
>     > xe.uni
>     > new file mode 100644
>     > index 000000000000..227b8c6fad24
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
>     > xe.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/VariableRuntimeD
>     > xeExtra.uni
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
>     > xeExtra.uni
>     > new file mode 100644
>     > index 000000000000..f0976418ff81
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
>     > xeExtra.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/VariableSmmExtr
>     > a.uni
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
>     > a.uni
>     > new file mode 100644
>     > index 000000000000..f724209f3dc2
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
>     > a.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/VariableSmmRunt
>     > imeDxe.uni
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxe.uni
>     > new file mode 100644
>     > index 000000000000..9639f00077a0
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxe.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/VariableSmmRunt
>     > imeDxeExtra.uni
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxeExtra.uni
>     > new file mode 100644
>     > index 000000000000..bbabdf82736b
>     > --- /dev/null
>     > +++
>     >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
>     > imeDxeExtra.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
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 04/19] MdeModulePkg: Add new include files
  2022-11-06  7:34 ` [PATCH v5 04/19] MdeModulePkg: Add new include files Judah Vang
@ 2022-11-22  6:31   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:31 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C


Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 04/19] MdeModulePkg: Add new include files
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V4: Updated with review comments for misspellings, mismatch
> function prototype, missing function header comments, incorrect
> function description.
> 
> V1: Add EncryptionVariableLib.h for providing encryption and
> decryption services for protected variables.
> Add ProtectedVariableLib.h for providing integrity or
> variables.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  MdeModulePkg/Include/Library/EncryptionVariableLib.h | 165 ++++++
>  MdeModulePkg/Include/Library/ProtectedVariableLib.h  | 607
> ++++++++++++++++++++
>  2 files changed, 772 insertions(+)
> 
> diff --git a/MdeModulePkg/Include/Library/EncryptionVariableLib.h
> b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
> new file mode 100644
> index 000000000000..68981f5aad6a
> --- /dev/null
> +++ b/MdeModulePkg/Include/Library/EncryptionVariableLib.h
> @@ -0,0 +1,165 @@
> +/** @file
> +  Provides services to encrypt/decrypt variables.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef ENCRYPTION_VARIABLE_LIB_H_
> +#define ENCRYPTION_VARIABLE_LIB_H_
> +
> +#include <IndustryStandard/Tpm20.h>
> +
> +#include <Guid/VariableFormat.h>
> +
> +#include <Library/AuthVariableLib.h>
> +
> +#define ENC_TYPE_NULL  0
> +#define ENC_TYPE_AES   TPM_ALG_AES
> +
> +typedef struct  _VARIABLE_ENCRYPTION_FLAGS {
> +  BOOLEAN    Auth;            // Variable is authenticated or not
> +  BOOLEAN    DecryptInPlace;  // Do decryption in place
> +  BOOLEAN    Protected;       // Variable is protected or not
> +} VARIABLE_ENCRYPTION_FLAGS;
> +
> +typedef struct _VARIABLE_ENCRYPTION_INFO {
> +  AUTH_VARIABLE_INFO           Header;            // Authenticated varabile header
> +  VARIABLE_HEADER              *Buffer;           // Pointer to variable buffer
> +  UINT64                       StoreIndex;        // Variable store index
> +  VOID                         *PlainData;        // Pointer to plain data
> +  UINT32                       PlainDataSize;     // Size of plain data
> +  VOID                         *CipherData;       // Pointer to cipher data
> +  UINT32                       CipherDataSize;    // Size of cipher data
> +  UINT32                       CipherHeaderSize;  // Size of cipher header
> +  UINT32                       CipherDataType;    // Type of cipher data
> +  VOID                         *Key;              // Pointer to encrypt/decrypt key
> +  UINT32                       KeySize;           // Size of key
> +  VARIABLE_ENCRYPTION_FLAGS    Flags;             // Encryption flags
> +} VARIABLE_ENCRYPTION_INFO;
> +
> +/**
> +  Encrypt variable data.
> +
> +  @param[in, out]   VarInfo   Pointer to structure containing detailed
> information about a variable.
> +
> +  @retval EFI_SUCCESS               Function successfully executed.
> +  @retval EFI_INVALID_PARAMETER     If ProtectedVarLibContextIn == NULL or
> ProtectedVarLibContextOut == NULL.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process encrypted variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +EncryptVariable (
> +  IN OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
> +  );
> +
> +/**
> +  Decrypt variable data.
> +
> +  If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
> +  decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
> +  VarEncInfo->Header.Data.
> +
> +  If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
> +  back in the same buffer as cipher buffer got above, after encryption header,
> +  which helps to identify later if the data in buffer is decrypted or not. This
> +  can avoid repeat decryption when accessing the same variable more than
> once.
> +
> +  If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
> +  passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
> +  with its size.
> +
> +  Note the VarEncInfo->PlainData is always pointing to the buffer address with
> +  decrypted data without encryption header, and VarEncInfo->PlainDataSize is
> +  always the size of original variable data, if this function returned
> +  successfully.
> +
> +  @param[in, out]   VarInfo   Pointer to structure containing detailed
> +                              information about a variable.
> +
> +  @retval EFI_SUCCESS             Variable was decrypted successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_BUFFER_TOO_SMALL    VarEncInfo->PlainData is not NULL but
> +                                  VarEncInfo->PlainDataSize is too small.
> +  @retval EFI_ABORTED             Unknown error occurred during decrypting.
> +  @retval EFI_OUT_OF_RESOURCES    Fail to allocate enough resource.
> +  @retval EFI_COMPROMISED_DATA    The cipher header is not valid.
> +  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DecryptVariable (
> +  IN OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
> +  );
> +
> +/**
> +  Get cipher information about a variable, including plaindata size,
> +  cipher algorithm type, etc.
> +
> +  For data passed in with VarEncInfo,
> +
> +    VarEncInfo->Header.Data
> +      - The variable data in normal variable structure.
> +    VarEncInfo->Header.DataSize
> +      - The size of variable data.
> +
> +  For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
> +
> +    VarEncInfo->CipherDataType
> +      - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
> +      - ENC_TYPE_AES, if the variable is encrypted.
> +    VarEncInfo->CipherHeaderSize
> +      - Size of cipher header put before encrypted or decrypted data.
> +    VarEncInfo->PlainData
> +      - NULL, if the variable is encrypted; Or
> +      - pointer to original variable data, if the variable has been decrypted.
> +    VarEncInfo->PlainDataSize
> +      - The size of original variable data
> +    VarEncInfo->CipherData
> +      - NULL, if the variable is decrypted; Or
> +      - pointer to start of encrypted variable data, including encryption header;
> +    VarEncInfo->CipherDataSize
> +      - The size of encrypted variable data, including encryption header.
> +
> +  @param[in, out]   VarInfo   Pointer to structure containing detailed
> +                              information about a variable.
> +
> +  @retval EFI_SUCCESS             The information was retrieved successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_NOT_FOUND           No cipher information recognized.
> +  @retval EFI_UNSUPPORTED         Unsupported interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetCipherDataInfo (
> +  IN  OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
> +  );
> +
> +/**
> +  Force set cipher information for a variable, like plaindata size,
> +  cipher algorithm type, cipher data etc.
> +
> +  The destination buffer must be passed via VarEncInfo->Header.Data.
> +
> +  This method is only used to update and/or change plain data information.
> +
> +  @param[in, out]   VarInfo   Pointer to structure containing detailed
> +                              information about a variable.
> +
> +  @retval EFI_SUCCESS             The information was updated successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_UNSUPPORTED         If this method is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetCipherDataInfo (
> +  IN  OUT VARIABLE_ENCRYPTION_INFO  *VarInfo
> +  );
> +
> +#endif //_ENCRYPTION_VARIABLE_LIB_H_
> diff --git a/MdeModulePkg/Include/Library/ProtectedVariableLib.h
> b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
> new file mode 100644
> index 000000000000..d31432a0c2b0
> --- /dev/null
> +++ b/MdeModulePkg/Include/Library/ProtectedVariableLib.h
> @@ -0,0 +1,607 @@
> +/** @file
> +  Defines interfaces of protected variable services for non-volatile variable
> +  storage.
> +
> +Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PROTECTED_VARIABLE_LIB_H_
> +#define PROTECTED_VARIABLE_LIB_H_
> +
> +#include <PiPei.h>
> +#include <PiDxe.h>
> +
> +#include <Guid/VariableFormat.h>
> +
> +#include <Protocol/VarCheck.h>
> +#include <Protocol/FirmwareVolumeBlock.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/EncryptionVariableLib.h>
> +
> +#pragma pack(1)
> +
> +typedef struct _VARIABLE_DIGEST_FLAGS {
> +  BOOLEAN    Auth;                           // Authenticated variable format
> +  BOOLEAN    Valid;                          // Valid variable data in current variable
> +  BOOLEAN    Protected;                      // Protected variable (used in calculating
> HMAC)
> +  BOOLEAN    Encrypted;                      // Encrypted variable
> +  BOOLEAN    Freeable;                       // Memory reserved for current node can
> be freed
> +  BOOLEAN    CacheIndexAhead;                // Indicates if CacheIndex is Ahead
> relative to Global structure
> +  BOOLEAN    Reserved[2];                    // Reserved fields
> +} VARIABLE_DIGEST_FLAGS;
> +
> +typedef struct _VARIABLE_DIGEST {
> +  ///
> +  /// Pointer to digest of next variable in a pre-defined rule of order for
> +  /// integration verification. In other words, the final HMAC of all
> +  /// protected variables is calculated by concatenating digest of each
> +  /// variable in the order of this singly linked list.
> +  ///
> +  EFI_PHYSICAL_ADDRESS     Prev;
> +  EFI_PHYSICAL_ADDRESS     Next;
> +  ///
> +  /// Index to variable in physical store, used to locate the variable directly
> +  /// inside the store (Implementation dependent).
> +  ///
> +  EFI_PHYSICAL_ADDRESS     StoreIndex;
> +  ///
> +  /// Index to variable in memory cache, used to locate the variable directly
> +  /// inside the cache (Implementation dependent).
> +  ///
> +  EFI_PHYSICAL_ADDRESS     CacheIndex;
> +
> +  ///
> +  /// Pointer to Cache offset within Global Structure
> +  ///
> +  UINT32                   CacheOffset;
> +
> +  ///
> +  /// Frequently accessed information relating to the variable.
> +  ///
> +  UINT16                   DigestSize;    // Size of digest value
> +  UINT16                   NameSize;      // Size of variable name
> +  UINT32                   DataSize;      // Size of variable data
> +  UINT32                   PlainDataSize; // Size of plain data of current variable (if
> encrypted)
> +  UINT32                   State;         // State of current variable
> +  UINT32                   Attributes;    // Attributes of current variable
> +
> +  EFI_GUID                 VendorGuid;    // GUID
> +  VARIABLE_DIGEST_FLAGS    Flags;         // Variable digest flags
> +  //
> +  // Data with variable length are put at the end of this structure.
> +  //
> +  // CHAR16                VariableName[NameSize/2];
> +  // UINT8                 DigestValue[DigestSize];
> +} VARIABLE_DIGEST;
> +
> +#pragma pack()
> +
> +#define VAR_DIG_NAMEOFF(VarDig)  (sizeof (VARIABLE_DIGEST))
> +#define VAR_DIG_DIGOFF(VarDig)   (VAR_DIG_NAMEOFF (VarDig) + (VarDig)-
> >NameSize)
> +
> +#define VAR_DIG_END(VarDig)  (VAR_DIG_DIGOFF (VarDig) + (VarDig)-
> >DigestSize)
> +
> +#define VAR_DIG_VALUE(VarDig)  (VOID *)((UINTN)(VarDig) +
> VAR_DIG_DIGOFF (VarDig))
> +#define VAR_DIG_NAME(VarDig)   (CHAR16 *)((UINTN)(VarDig) +
> VAR_DIG_NAMEOFF (VarDig))
> +#define VAR_DIG_GUID(VarDig)   &(VAR_DIG_PTR (VarDig)->VendorGuid)
> +
> +#define VAR_DIG_PTR(Addr)     ((VARIABLE_DIGEST *)(UINTN)(Addr))
> +#define VAR_DIG_ADR(Ptr)      ((EFI_PHYSICAL_ADDRESS)(UINTN)(Ptr))
> +#define VAR_DIG_NEXT(VarDig)  (VAR_DIG_PTR ((VarDig)->Next))
> +#define VAR_DIG_PREV(VarDig)  (VAR_DIG_PTR ((VarDig)->Prev))
> +
> +#define VAR_INDEX_INVALID  ((UINT64)(-1))
> +
> +#define VAR_HDR_PTR(Addr)  ((VARIABLE_HEADER *)(UINTN)(Addr))
> +
> +typedef VARIABLE_ENCRYPTION_INFO PROTECTED_VARIABLE_INFO;
> +
> +/**
> +
> +  This function writes data to the NV variable storage at given position.
> +
> +  Note: Per current variable service architecture, only SMM is allowed to
> +        (directly) change NV variable storage.
> +
> +  @param VariableInfo             Pointer to structure holding details of a variable.
> +  @param Offset                   Offset to the given variable to write from.
> +  @param Size                     Size of data to be written.
> +  @param Buffer                   Pointer to the buffer from which data is written.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid parameters passed in.
> +  @retval EFI_UNSUPPORTED        Updating NV variable storage is not
> supported.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to complete the
> operation.
> +  @retval EFI_SUCCESS            Variable store successfully updated.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE)(
> +  IN  PROTECTED_VARIABLE_INFO     *VariableInfo,
> +  IN  UINTN                       Offset,
> +  IN  UINT32                      Size,
> +  IN  UINT8                       *Buffer
> +  );
> +
> +/**
> +  Update the variable region with Variable information.
> +
> +  @param[in] AuthVariableInfo       Pointer to 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.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_UPDATE_VARIABLE)(
> +  IN AUTH_VARIABLE_INFO     *AuthVariableInfo
> +  );
> +
> +/**
> +
> +  Retrieve details about a variable and return them in VariableInfo->Header.
> +
> +  If VariableInfo->Address 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->Address 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->Address,
> +  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.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_GET_VAR_INFO)(
> +  IN  OUT PROTECTED_VARIABLE_INFO   *VariableInfo
> +  );
> +
> +/**
> +
> +  Retrieve details of the variable next to given variable within VariableStore.
> +
> +  If VarInfo->Address is NULL, the first one in VariableStore is returned.
> +
> +  VariableStart and/or VariableEnd can be given optionally for the situation
> +  in which the valid storage space is smaller than the VariableStore->Size.
> +  This usually happens when PEI variable services make a compact variable
> +  cache to save memory, which cannot make use VariableStore->Size to
> determine
> +  the correct variable storage range.
> +
> +  @param[in,out] VariableInfo             Pointer to variable information.
> +
> +  @retval EFI_INVALID_PARAMETER  VariableInfo is NULL.
> +  @retval EFI_NOT_FOUND          If the end of VariableInfo is reached.
> +  @retval EFI_SUCCESS            The next variable is retrieved successfully.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO)(
> +  IN  OUT PROTECTED_VARIABLE_INFO   *VariableInfo
> +  );
> +
> +/**
> +
> +  Initiate a variable retrieval in SMM environment from non-SMM environment.
> +
> +  This is usually required in BS/RT environment when local cached copy is in
> +  encrypted form. Variable decryption can only be done in SMM environment.
> +
> +  @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.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_FIND_VAR_SMM)(
> +  IN      CHAR16                 *VariableName,
> +  IN      EFI_GUID               *VendorGuid,
> +  OUT UINT32                     *Attributes OPTIONAL,
> +  IN  OUT UINTN                  *DataSize,
> +  OUT VOID                       *Data OPTIONAL
> +  );
> +
> +/**
> +  Check if a HOB variable store is available or not.
> +
> +  @retval EFI_NOT_READY  HOB variable store info not available.
> +  @retval EFI_NOT_FOUND  HOB variable store is NOT available.
> +  @retval EFI_SUCCESS    HOB variable store is available.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE)(
> +  VOID
> +  );
> +
> +typedef enum {
> +  FromPeiModule,
> +  FromBootServiceModule,
> +  FromRuntimeModule,
> +  FromSmmModule
> +} VARIABLE_SERVICE_USER;
> +
> +#pragma pack(1)
> +
> +#define PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION  0x02
> +
> +typedef struct _PROTECTED_VARIABLE_CONTEXT_IN {
> +  UINT32                                     StructVersion;
> +  UINT32                                     StructSize;
> +  UINT32                                     MaxVariableSize;
> +
> +  VARIABLE_SERVICE_USER                      VariableServiceUser;
> +
> +  PROTECTED_VAR_LIB_FIND_VAR_SMM             FindVariableSmm;
> +  PROTECTED_VAR_LIB_GET_VAR_INFO             GetVariableInfo;
> +  PROTECTED_VAR_LIB_GET_NEXT_VAR_INFO        GetNextVariableInfo;
> +  PROTECTED_VAR_LIB_UPDATE_VARIABLE_STORE    UpdateVariableStore;
> +  PROTECTED_VAR_LIB_UPDATE_VARIABLE          UpdateVariable;
> +  PROTECTED_VAR_LIB_HOB_STORE_AVAILABLE
> IsHobVariableStoreAvailable;
> +} PROTECTED_VARIABLE_CONTEXT_IN;
> +
> +#pragma pack()
> +
> +/**
> +
> +  Initialization for protected variable services.
> +
> +  If this initialization failed upon any error, the whole variable services
> +  should not be used.  A system reset might be needed to re-construct NV
> +  variable storage to be the default state.
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected
> variables.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  );
> +
> +/**
> +
> +  An alternative version of ProtectedVariableLibGetData to get plain data, if
> +  encrypted, from given variable, for different use cases.
> +
> +  @param[in,out]      VarInfo     Pointer to structure containing variable
> information.
> +
> +  @retval EFI_SUCCESS               Found the specified variable.
> +  @retval EFI_INVALID_PARAMETER     VarInfo is NULL or both VarInfo-
> >Address and
> +                                    VarInfo->Offset are invalid.
> +  @retval EFI_NOT_FOUND             The specified variable could not be found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  );
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByName (
> +  IN      CONST  CHAR16    *VariableName,
> +  IN      CONST  EFI_GUID  *VariableGuid,
> +  OUT UINT32               *Attributes,
> +  IN  OUT UINTN            *DataSize,
> +  OUT VOID                 *Data OPTIONAL
> +  );
> +
> +/**
> +
> +  Retrieve plain data, if encrypted, of given variable.
> +
> +  If variable encryption is employed, this function will initiate a SMM request
> +  to get the plain data. Due to security consideration, the decryption can only
> +  be done in SMM environment.
> +
> +  @param[in]      Variable           Pointer to header of a Variable.
> +  @param[out]     Data               Pointer to plain data of the given variable.
> +  @param[in, out] DataSize           Size of data returned or data buffer needed.
> +  @param[in]      AuthFlag           Auth-variable indicator.
> +
> +  @retval EFI_SUCCESS                Found the specified variable.
> +  @retval EFI_INVALID_PARAMETER      Invalid parameter.
> +  @retval EFI_NOT_FOUND              The specified variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL       If *DataSize is smaller than needed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByBuffer (
> +  IN      VARIABLE_HEADER  *Variable,
> +  IN  OUT VOID             *Data,
> +  IN  OUT UINT32           *DataSize,
> +  IN      BOOLEAN          AuthFlag
> +  );
> +
> +/**
> +
> +  Prepare for variable update.
> +
> +  This is needed only once during current boot to mitigate replay attack. Its
> +  major job is to advance RPMC (Replay Protected Monotonic Counter).
> +
> +  @retval EFI_SUCCESS             Variable is ready to update hereafter.
> +  @retval EFI_UNSUPPORTED         Updating variable is not supported.
> +  @retval EFI_DEVICE_ERROR        Error in advancing RPMC.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> +  VOID
> +  );
> +
> +/**
> +
> +  Update a variable with protection provided by this library.
> +
> +  If variable encryption is employed, the new variable data will be encrypted
> +  before being written to NV variable storage.
> +
> +  A special variable, called "MetaDataHmacVar", will always be updated along
> +  with variable being updated to reflect the changes (HMAC value) of all
> +  protected valid variables. The only exceptions, currently, are variable
> +  "MetaDataHmacVar" itself and variable "VarErrorLog".
> +
> +  The buffer passed by NewVariable must be double of maximum variable size,
> +  which allows to pass the "MetaDataHmacVar" back to caller along with
> encrypted
> +  new variable data, if any. This can make sure the new variable data and
> +  "MetaDataHmacVar" can be written at almost the same time to reduce the
> chance
> +  of compromising the integrity.
> +
> +  If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
> +  and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
> +  case because of less variables in storage. NewVariable should be always
> passed
> +  in to convey new "MetaDataHmacVar" back.
> +
> +  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
> +                                      adding a new variable.
> +  @param[in,out]  CurrVariableInDel   In-delete-transition copy of updating
> variable.
> +  @param[in]      NewVariable         Buffer of new variable data.
> +  @param[out]     NewVariable         Buffer of "MetaDataHmacVar" and new
> +                                      variable (encrypted).
> +  @param[in]      NewVariableSize     Size of NewVariable.
> +  @param[out]     NewVariableSize     Size of (encrypted) NewVariable and
> +                                      "MetaDataHmacVar".
> +
> +  @retval EFI_SUCCESS             The variable is updated with protection
> successfully.
> +  @retval EFI_INVALID_PARAMETER   NewVariable is NULL.
> +  @retval EFI_NOT_FOUND           Information missing to finish the operation.
> +  @retval EFI_ABORTED             Failed to encrypt variable or calculate HMAC.
> +  @retval EFI_NOT_READY           The RPMC device is not yet initialized.
> +  @retval EFI_DEVICE_ERROR        The RPMC device has error in updating.
> +  @retval EFI_ACCESS_DENIED       The given variable is not allowed to update.
> +                                  Currently this only happens on updating
> +                                  "MetaDataHmacVar" from code outside of this
> +                                  library.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> +  IN  OUT VARIABLE_HEADER  *CurrVariable OPTIONAL,
> +  IN  OUT VARIABLE_HEADER  *CurrVariableInDel OPTIONAL,
> +  IN  OUT VARIABLE_HEADER  *NewVariable,
> +  IN  OUT UINTN            *NewVariableSize
> +  );
> +
> +/**
> +
> +  Finalize a variable updating after it's written to NV variable storage
> +  successfully.
> +
> +  This usually includes works like increasing RPMC, synchronizing local cache,
> +  updating new position of "MetaDataHmacVar", deleting old copy of
> "MetaDataHmacVar"
> +  completely, etc.
> +
> +  @param[in]      NewVariable       Buffer of new variables and
> MetaDataHmacVar.
> +  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
> +  @param[in]      StoreIndex        StoreIndex to NV variable storage from where
> the new
> +                                    variable and MetaDataHmacVar have been written.
> +
> +  @retval EFI_SUCCESS         No problem in winding up the variable write
> operation.
> +  @retval Others              Failed to updating state of old copy of updated
> +                              variable, or failed to increase RPMC, etc.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> +  IN  VARIABLE_HEADER  *NewVariable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex
> +  );
> +
> +/**
> +  Find the request variable.
> +
> +  @param[in, out]  VarInfo      Pointer to variable data.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_INVALID_PARAMETER Variable info is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFind (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  );
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNext (
> +  IN OUT UINTN     *VariableNameSize,
> +  IN OUT CHAR16    *VariableName,
> +  IN OUT EFI_GUID  *VariableGuid
> +  );
> +
> +/**
> +  Find variable via information in data structure PROTECTED_VARIABLE_INFO.
> +
> +   If VarInfo->StoreIndex is given and valid, always used it to search variable
> +   in store. Otherwise, search the variable via variable name and guid pointed
> +   by VarInfo->Header.VariableName and VarInfo->Header.VendorGuid.
> +
> +  @param VarInfo    Pointer to data containing variable information.
> +
> +  @return EFI_SUCCESS           Found the variable.
> +  @return EFI_INVALID_PARAMETER No valid variable information is given.
> +  @return EFI_NOT_FOUND         The given variable was not found or no more
> +                                variables available.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNextEx (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  );
> +
> +/**
> +  Refresh variable information changed by variable service.
> +
> +  @param Variable         Pointer to buffer of the updated variable.
> +  @param VariableSize     Size of variable pointed by Variable.
> +  @param StoreIndex       New index of the variable in store.
> +  @param RefreshData      Flag to indicate if the variable has been updated.
> +
> +  @return EFI_SUCCESS     No error occurred in updating.
> +  @return EFI_NOT_FOUND   The given variable was not found in
> +                          ProtectedVariableLib.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibRefresh (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex,
> +  IN  BOOLEAN          RefreshData
> +  );
> +
> +/**
> +  Get sorted protected variable list.
> +
> +  @param Buffer           Pointer to a pointer of buffer.
> +  @param NumElements      Pointer to number of elements in list.
> +
> +  @return EFI_SUCCESS     Successfully retrieved sorted list.
> +  @return others          Unsuccessful.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetSortedList (
> +  IN  OUT  EFI_PHYSICAL_ADDRESS  **Buffer,
> +  IN  OUT  UINTN                 *NumElements
> +  );
> +
> +/**
> +
> +  Determine if the variable is the HMAC variable
> +
> +  @param VariableName   Pointer to variable name.
> +
> +  @return TRUE      Variable is HMAC variable
> +  @return FALSE     Variable is not HMAC variable
> +
> +**/
> +BOOLEAN
> +ProtectedVariableLibIsHmac (
> +  IN CHAR16  *VariableName
> +  );
> +
> +#endif
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library
  2022-11-06  7:34 ` [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
@ 2022-11-22  6:39   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:39 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C

Judah,

Just some typos. See inline comments starting with "[JianJW]".
With them addressed,

   Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V4: Applied code review comments - removed APIs that are not being
> used.
> 
> V1: Add Null versions of the ProtectedVariable Library.
> This will be the default libraries for platforms that
> do not support ProtectedVariable.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
> |  34 ++
>  MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c          |
> 336 ++++++++++++++++++++
>  2 files changed, 370 insertions(+)
> 
> diff --git
> a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.in
> f
> b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.in
> f
> new file mode 100644
> index 000000000000..6a17191c4e1e
> --- /dev/null
> +++
> b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.in
> f
> @@ -0,0 +1,34 @@
> +## @file
> +#  Provides null version of protected variable services.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010029
> +  BASE_NAME                      = ProtectedVariableLibNull
> +  FILE_GUID                      = 352C6A1B-403A-4E37-8517-FAA50BC45251
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 0.1
> +  LIBRARY_CLASS                  = ProtectedVariableLib
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  ProtectedVariable.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +
> diff --git
> a/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> new file mode 100644
> index 000000000000..074559f84f52
> --- /dev/null
> +++ b/MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> @@ -0,0 +1,336 @@
> +/** @file
> +  NULL version of ProtectedVariableLib used to disable protected variable
> services.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Uefi.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/ProtectedVariableLib.h>
> +
> +/**
> +
> +  Initialization for protected varibale services.

[JianJW] typo: " varibale" -> "variable"

> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Prepare for variable update.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> +  VOID
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Update a variable with protection provided by this library.
> +
> +  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
> +                                      adding a new variable.
> +  @param[in]      CurrVariableInDel   In-delete-transiion copy of updating
> variable.

[JianJW] typo: " transiion" -> "transition"

> +  @param[in,out]  NewVariable         Buffer of new variable data.
> +                                      Buffer of "MetaDataHmacVar" and new
> +                                      variable (encrypted).
> +  @param[in,out]  NewVariableSize     Size of NewVariable.
> +                                      Size of (encrypted) NewVariable and
> +                                      "MetaDataHmacVar".
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> +  IN  OUT VARIABLE_HEADER  *CurrVariable,
> +  IN      VARIABLE_HEADER  *CurrVariableInDel,
> +  IN  OUT VARIABLE_HEADER  *NewVariable,
> +  IN  OUT UINTN            *NewVariableSize
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Finalize a variable updating after it's written to NV variable storage
> +  successfully.
> +
> +  @param[in]      NewVariable       Buffer of new variables and
> MetaDataHmacVar.
> +  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
> +  @param[in]      StoreIndex        New index of the variable in store.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> +  IN  VARIABLE_HEADER  *NewVariable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Retrieve plain data, if encrypted, of given variable.
> +
> +  @param[in]      Variable           Pointer to header of a Variable.
> +  @param[in,out]  Data               Pointer to plain data of the given variable.
> +  @param[in,out]  DataSize           Size of data returned or data buffer needed.
> +  @param[in]      AuthFlag           Auth-variable indicator.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetData (
> +  IN      VARIABLE_HEADER  *Variable,
> +  IN  OUT VOID             *Data,
> +  IN  OUT UINT32           *DataSize,
> +  IN      BOOLEAN          AuthFlag
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Get the specified protected variable.
> +
> +  @param[in]      VariableName      Pointer to variable name.
> +  @param[in]      VariableGuid      Pointer to vairable GUID.

[JianJW] typo: " vairable" -> "variable"

> +  @param[out]     Attributes        Pointer to attributes.
> +  @param[in,out]  DataSize          Pointer to data size.
> +  @param[out]     Data              Pointer to data.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGet (
> +  IN      CONST  CHAR16    *VariableName,
> +  IN      CONST  EFI_GUID  *VariableGuid,
> +  OUT UINT32               *Attributes,
> +  IN  OUT UINTN            *DataSize,
> +  OUT VOID                 *Data OPTIONAL
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Find the protected variable.
> +
> +  @param[in,out]      VarInfo     Pointer to structure containing variable
> information.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFind (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Find next protected variable.
> +
> +  @param[in,out]      VariableNameSize    Pointer to size of variable name.
> +  @param[in,out]      VariableName        Pointer to variable name.
> +  @param[in,out]      VariableGuid        Pointer to vairable GUID.

[JianJW] typo: " vairable" -> "variable"

> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNext (
> +  IN OUT UINTN     *VariableNameSize,
> +  IN OUT CHAR16    *VariableName,
> +  IN OUT EFI_GUID  *VariableGuid
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Find next protected variable stub.
> +
> +  @param[in,out]      VarInfo     Pointer to structure containing variable
> information.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNextEx (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Get protected variable by information.
> +
> +  @param[in,out]      VarInfo     Pointer to structure containing variable
> information.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Get protected variable by name.
> +
> +  @param[in]      VariableName      Pointer to variable name.
> +  @param[in]      VariableGuid      Pointer to vairable GUID.

[JianJW] typo: " vairable" -> "variable"

> +  @param[out]     Attributes        Pointer to attributes.
> +  @param[in,out]  DataSize          Pointer to data size.
> +  @param[out]     Data              Pointer to data.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByName (
> +  IN      CONST  CHAR16    *VariableName,
> +  IN      CONST  EFI_GUID  *VariableGuid,
> +  OUT UINT32               *Attributes,
> +  IN  OUT UINTN            *DataSize,
> +  OUT VOID                 *Data OPTIONAL
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Get protected variable by name.
> +
> +  @param[in]      Variable      Pointer to variable name.
> +  @param[in,out]  Data          Pointer to variable data.
> +  @param[in,out]  DataSize      Pointer to data size.
> +  @param[in]      AuthFlag      Authenticate flag.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByBuffer (
> +  IN      VARIABLE_HEADER  *Variable,
> +  IN  OUT VOID             *Data,
> +  IN  OUT UINT32           *DataSize,
> +  IN      BOOLEAN          AuthFlag
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Refresh variable information changed by variable service.
> +
> +  @param[in]  Variable         Pointer to buffer of the updated variable.
> +  @param[in]  VariableSize     Size of variable pointed by Variable.
> +  @param[in]  StoreIndex       New index of the variable in store.
> +  @param[in]  RefreshData      Flag to indicate if the variable has been updated.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibRefresh (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex,
> +  IN  BOOLEAN          RefreshData
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Get sorted protected variable list.
> +
> +  @param[in,out]  Buffer        Pointer to buffer.
> +  @param[in,out]  NumElements   Pointer to number of elements.
> +
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetSortedList (
> +  IN  OUT  EFI_PHYSICAL_ADDRESS  **Buffer,
> +  IN  OUT  UINTN                 *NumElements
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Determine if the variable is the HMAC variable.
> +
> +  @param[in]  VariableName   Pointer to variable name.
> +
> +  @return FALSE     Variable is not HMAC variable
> +
> +**/
> +BOOLEAN
> +ProtectedVariableLibIsHmac (
> +  IN CHAR16  *VariableName
> +  )
> +{
> +  return FALSE;
> +}
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables
       [not found]         ` <1729D430BF77E016.5511@groups.io>
@ 2022-11-22  6:42           ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:42 UTC (permalink / raw)
  To: devel@edk2.groups.io, Wang, Jian J, sami.mujawar@arm.com,
	Vang, Judah
  Cc: Gao, Liming, Wu, Hao A, Mistry, Nishant C, nd

So please ignore similar comments for other patches.

For this patch,

   Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Wang, Jian
> J
> Sent: Tuesday, November 22, 2022 2:27 PM
> To: devel@edk2.groups.io; sami.mujawar@arm.com; Vang, Judah
> <judah.vang@intel.com>
> Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A
> <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>; nd
> <nd@arm.com>
> Subject: Re: [edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for
> Protected Variables
> 
> Thanks for sharing the info. It looks that my coding style knowledge needs
> refresh.
> 
> Regards,
> Jian
> 
> > -----Original Message-----
> > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Sami
> > Mujawar
> > Sent: Tuesday, November 15, 2022 4:49 PM
> > To: devel@edk2.groups.io; Vang, Judah <judah.vang@intel.com>; Wang, Jian J
> > <jian.j.wang@intel.com>
> > Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A
> > <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>; nd
> > <nd@arm.com>
> > Subject: Re: [edk2-devel] [PATCH v5 08/19] MdeModulePkg: Add support for
> > Protected Variables
> >
> > Hi All,
> >
> > I believe the EDKII CI is following the edk2-Coding standard rule 5.3.5 which
> > forbids prefixing file include guard macro names with '_', see https://edk2-
> > docs.gitbook.io/edk-ii-c-coding-standards-specification/v/release-
> > 2.20/5_source_files/53_include_files#5.3.5-all-include-file-contents-must-be-
> > protected-by-a-include-guard
> >
> > If I understand correctly the edk2 CI runs uncrustify on the patch diff.
> Therefore,
> > unless you touch the macro in an existing file, it would not complain.
> >
> > Regards,
> >
> > Sami Mujawar
> >
> > On 14/11/2022, 17:20, "devel@edk2.groups.io on behalf of Judah Vang via
> > groups.io" <devel@edk2.groups.io on behalf of
> > judah.vang=intel.com@groups.io> wrote:
> >
> >     Jian,
> >
> >     That's not the reason why I removed the leading '_' underscore.
> >     When I don't remove it, the EDK2 CI is giving me a fail and telling me it needs
> > to be removed.
> >     I don't know why this is the case but it seems to only happen for new files.
> >
> >     Judah
> >
> >     -----Original Message-----
> >     From: Wang, Jian J <jian.j.wang@intel.com>
> >     Sent: Sunday, November 13, 2022 11:14 PM
> >     To: Vang, Judah <judah.vang@intel.com>; devel@edk2.groups.io
> >     Cc: Gao, Liming <gaoliming@byosoft.com.cn>; Wu, Hao A
> > <hao.a.wu@intel.com>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> >     Subject: RE: [PATCH v5 08/19] MdeModulePkg: Add support for Protected
> > Variables
> >
> >     Hi Judah,
> >
> >     Just one comment:
> >
> >     For all header files, no need to remove the opening '_' of include guard
> macro.
> >     Protected variable code are now in different folder than original variable
> > driver.
> >     They won't reference code from each other. Please add the opening '_' for
> > those
> >     macros to confirm to edk2 coding convention.
> >
> >     Regards,
> >     Jian
> >
> >     > -----Original Message-----
> >     > From: Vang, Judah <judah.vang@intel.com>
> >     > Sent: Sunday, November 06, 2022 3:35 PM
> >     > To: devel@edk2.groups.io
> >     > Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> >     > <gaoliming@byosoft.com.cn>; Wu, Hao A <hao.a.wu@intel.com>; Mistry,
> >     > Nishant C <nishant.c.mistry@intel.com>
> >     > Subject: [PATCH v5 08/19] MdeModulePkg: Add support for Protected
> > Variables
> >     >
> >     > 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@intel.com>
> >     > Cc: Liming Gao <gaoliming@byosoft.com.cn>
> >     > Cc: Hao A Wu <hao.a.wu@intel.com>
> >     > Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> >     > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> >     > Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> >     > Signed-off-by: Judah Vang <judah.vang@intel.com>
> >     > ---
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> >     > t/VariableLockRequestToLockUnitTest.inf |   36 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> >     > .inf                                   |  151 +
> >     >
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf
> >     > |  153 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> >     > eDxe.inf                                |  119 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> >     > Mm.inf                                 |  143 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphi
> >     > c.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/VariableRuntimeCac
> >     > he.h                                   |   51 +
> >     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
> >     > |  343 ++
> >     >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
> >     > |  504 +++
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> >     > t/VariableLockRequestToLockUnitTest.c   |  607 +++
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierD
> >     > xe.c                                  |   27 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierS
> >     > mm.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/VariableLockReques
> >     > tToLock.c                              |   96 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile
> >     > .c                                    |  537 +++
> >     >
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c
> >     > | 1110 ++++++
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmm
> >     > Dxe.c                                   |  575 +++
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac
> >     > he.c                                   |  158 +
> >     >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
> >     > | 1268 ++++++
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> >     > eDxe.c                                  | 1895 +++++++++
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> >     > Mm.c                                   |   89 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditional
> >     > Mm.c                                  |  130 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> >     > .uni                                   |   22 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> >     > Extra.uni                              |   14 +
> >     >
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni
> >     > |   27 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.u
> >     > ni                                     |   14 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> >     > eDxe.uni                                |   23 +
> >     >
> >     >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> >     > eDxeExtra.uni                           |   14 +
> >     >  36 files changed, 15676 insertions(+)
> >     >
> >     > diff --git
> >     >
> >
> a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> >     > est/VariableLockRequestToLockUnitTest.inf
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> >     > est/VariableLockRequestToLockUnitTest.inf
> >     > new file mode 100644
> >     > index 000000000000..586d877fca90
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> >     > est/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/VariableRuntimeD
> >     > xe.inf
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> >     > xe.inf
> >     > new file mode 100644
> >     > index 000000000000..6adc2c636e84
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> >     > xe.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/VariableSmmRunt
> >     > imeDxe.inf
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxe.inf
> >     > new file mode 100644
> >     > index 000000000000..0d169913c9c9
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxe.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/VariableStandalon
> >     > eMm.inf
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> >     > eMm.inf
> >     > new file mode 100644
> >     > index 000000000000..fb5a6c947890
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> >     > eMm.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/PrivilegePolymorp
> >     > hic.h
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
> >     > hic.h
> >     > new file mode 100644
> >     > index 000000000000..7f14515b694f
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp
> >     > hic.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.
> >
> >     [JianJW] Too long line. Wrap it to within 80 characters for each line.
> >
> >     > +
> >     > +  @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/VariableNonVolat
> >     > ile.h
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> >     > ile.h
> >     > new file mode 100644
> >     > index 000000000000..a84db4877c13
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> >     > ile.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/VariableRuntimeC
> >     > ache.h
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> >     > ache.h
> >     > new file mode 100644
> >     > index 000000000000..77dbce0f907c
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> >     > ache.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.VariableRuntimeVolatileCa
> c
> > he,
> >     > +                   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/RuntimeDxeUnitT
> >     > est/VariableLockRequestToLockUnitTest.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> >     > est/VariableLockRequestToLockUnitTest.c
> >     > new file mode 100644
> >     > index 000000000000..b2bcb97932ba
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT
> >     > est/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/SpeculationBarrie
> >     > rDxe.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> >     > rDxe.c
> >     > new file mode 100644
> >     > index 000000000000..b219ea9ec074
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> >     > rDxe.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/SpeculationBarrie
> >     > rSmm.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> >     > rSmm.c
> >     > new file mode 100644
> >     > index 000000000000..7107c042928e
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie
> >     > rSmm.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
> .S
> > tor
> >     > e != NULL) {
> >     > +      Status =  SynchronizeRuntimeVariableCache (
> >     > +                  &mVariableModuleGlobal-
> >     > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
> >     > +                  0,
> >     > +                  mVariableModuleGlobal-
> >     > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache
> .S
> > tor
> >     > e->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/VariableLockRequ
> >     > estToLock.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
> >     > estToLock.c
> >     > new file mode 100644
> >     > index 000000000000..d849ee9ce292
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ
> >     > estToLock.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/VariableNonVolat
> >     > ile.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> >     > ile.c
> >     > new file mode 100644
> >     > index 000000000000..32dd9901b260
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat
> >     > ile.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/VariablePolicySm
> >     > mDxe.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
> >     > mDxe.c
> >     > new file mode 100644
> >     > index 000000000000..b2094fbcd6ea
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm
> >     > mDxe.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/VariableRuntimeC
> >     > ache.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> >     > ache.c
> >     > new file mode 100644
> >     > index 000000000000..9bb30bc1e804
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC
> >     > ache.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/VariableSmmRunt
> >     > imeDxe.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxe.c
> >     > new file mode 100644
> >     > index 000000000000..b88f75370ad8
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxe.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/VariableStandalon
> >     > eMm.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> >     > eMm.c
> >     > new file mode 100644
> >     > index 000000000000..943993eb6738
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon
> >     > eMm.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/VariableTradition
> >     > alMm.c
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
> >     > alMm.c
> >     > new file mode 100644
> >     > index 000000000000..0369c3cd01b1
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition
> >     > alMm.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/VariableRuntimeD
> >     > xe.uni
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> >     > xe.uni
> >     > new file mode 100644
> >     > index 000000000000..227b8c6fad24
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> >     > xe.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/VariableRuntimeD
> >     > xeExtra.uni
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> >     > xeExtra.uni
> >     > new file mode 100644
> >     > index 000000000000..f0976418ff81
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD
> >     > xeExtra.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/VariableSmmExtr
> >     > a.uni
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
> >     > a.uni
> >     > new file mode 100644
> >     > index 000000000000..f724209f3dc2
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr
> >     > a.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/VariableSmmRunt
> >     > imeDxe.uni
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxe.uni
> >     > new file mode 100644
> >     > index 000000000000..9639f00077a0
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxe.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/VariableSmmRunt
> >     > imeDxeExtra.uni
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxeExtra.uni
> >     > new file mode 100644
> >     > index 000000000000..bbabdf82736b
> >     > --- /dev/null
> >     > +++
> >     >
> >
> b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt
> >     > imeDxeExtra.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
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib
  2022-11-06  7:34 ` [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
@ 2022-11-22  6:44   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:44 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io; +Cc: Gao, Liming, Mistry, Nishant C


Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V5: Add reference to new Protected Variable libs.
> 
> V1: Make reference to new Null ProtectVariableLib.
> The null ProtectedVariableLib is used by default.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  MdeModulePkg/MdeModulePkg.dsc              | 20 +++++++++++++++++++-
>  MdeModulePkg/Test/MdeModulePkgHostTest.dsc |  8 ++++++++
>  2 files changed, 27 insertions(+), 1 deletion(-)
> 
> diff --git a/MdeModulePkg/MdeModulePkg.dsc
> b/MdeModulePkg/MdeModulePkg.dsc
> index 659482ab737f..65ec6d1e0918 100644
> --- a/MdeModulePkg/MdeModulePkg.dsc
> +++ b/MdeModulePkg/MdeModulePkg.dsc
> @@ -2,7 +2,7 @@
>  # EFI/PI Reference Module Package for All Architectures
>  #
>  # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
> -# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.<BR>
>  # Copyright (c) Microsoft Corporation.
>  #
>  #    SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -104,6 +104,7 @@ [LibraryClasses]
> 
> VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/Variab
> lePolicyHelperLib.inf
> 
> MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockM
> emoryLibNull.inf
> 
> VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVar
> iableFlashInfoLib.inf
> +
> ProtectedVariableLib|MdeModulePkg/Library/ProtectedVariableLibNull/Protect
> edVariableLibNull.inf
> 
>  [LibraryClasses.EBC.PEIM]
>    IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
> @@ -318,6 +319,7 @@ [Components]
> 
> MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLi
> bNull.inf
>    MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
> 
> MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
> +
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull.inf
>    MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
>    MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
>    MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
> @@ -397,6 +399,7 @@ [Components]
>    MdeModulePkg/Application/VariableInfo/VariableInfo.inf
>    MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>    MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> +  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
>    MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
>    MdeModulePkg/Universal/TimestampDxe/TimestampDxe.inf
>    MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> @@ -461,6 +464,7 @@ [Components.IA32, Components.X64,
> Components.ARM, Components.AARCH64]
>  !if $(TOOL_CHAIN_TAG) != "XCODE5"
> 
> MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandalon
> eMm.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
> +
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone
> Mm.inf
>  !endif
> 
>  [Components.IA32, Components.X64]
> @@ -475,13 +479,27 @@ [Components.IA32, Components.X64]
>        NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
>        NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
>    }
> +  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf {
> +    <LibraryClasses>
> +      NULL|MdeModulePkg/Library/VarCheckPolicyLib/VarCheckPolicyLib.inf
> +      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
> +      NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
> +      NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
> +  }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
>      <LibraryClasses>
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>        NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
>        NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
>    }
> +
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe
> .inf {
> +    <LibraryClasses>
> +      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
> +      NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
> +      NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
> +  }
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
> +
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim
> eDxe.inf
> 
> MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.in
> f
> 
> MdeModulePkg/Library/SmmReportStatusCodeLib/StandaloneMmReportStatus
> CodeLib.inf
> 
> MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf
> diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
> b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
> index c9ec835df65d..c0ca9be71e8c 100644
> --- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
> +++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
> @@ -42,6 +42,14 @@ [Components]
> 
> gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable
> |TRUE
>    }
> 
> +
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes
> t/VariableLockRequestToLockUnitTest.inf {
> +    <LibraryClasses>
> +
> VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.in
> f
> +
> VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/Variab
> lePolicyHelperLib.inf
> +    <PcdsFixedAtBuild>
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable
> |TRUE
> +  }
> +
>    MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf {
>      <LibraryClasses>
>        UefiSortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines
  2022-11-06  7:35 ` [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines Judah Vang
@ 2022-11-22  6:46   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:46 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C


Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V4: revert copyright date change.
> 
> V1: Add new KeyService types and defines.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  SecurityPkg/Include/Ppi/KeyServicePpi.h | 57 ++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/SecurityPkg/Include/Ppi/KeyServicePpi.h
> b/SecurityPkg/Include/Ppi/KeyServicePpi.h
> new file mode 100644
> index 000000000000..8cfec04f96e5
> --- /dev/null
> +++ b/SecurityPkg/Include/Ppi/KeyServicePpi.h
> @@ -0,0 +1,57 @@
> +/** @file
> +  Provides Key Services.
> +
> +Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +@par Specification Reference:
> +**/
> +
> +#ifndef PEI_KEY_SERVICE_PPI_H_
> +#define PEI_KEY_SERVICE_PPI_H_
> +///
> +/// KEY SERVICE PPI GUID
> +///
> +extern EFI_GUID  gKeyServicePpiGuid;
> +
> +/**
> +  Generate a new key from root key.
> +
> +  @param[in]   Salt                     Pointer to the salt(non-secret) value.
> +  @param[in]   SaltSize                 Salt size in bytes.
> +  @param[out]  NewKey                   Pointer to buffer to receive new key.
> +  @param[in]   NewKeySize               Size of new key bytes to generate.
> +
> +  @retval EFI_SUCCESS                   The function completed successfully
> +  @retval OTHER                         The function completed with failure.
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *KEY_SERVICE_GEN_KEY)(
> +  IN   UINT8        *Salt,
> +  IN   UINTN        SaltSize,
> +  OUT  UINT8        *NewKey,
> +  IN   UINTN        NewKeySize
> +  );
> +
> +#define KEY_SERVICE_PPI_REVISION  1
> +#define ROOT_KEY_LEN              64
> +#define SALT_SIZE_MIN_LEN         64
> +#define KEY_SERVICE_KEY_NAME      L"KEY_SERVICE_KEY"
> +
> +typedef struct {
> +  UINT8    RootKey[ROOT_KEY_LEN];
> +  UINT8    PreviousRootKey[ROOT_KEY_LEN];
> +} KEY_SERVICE_DATA;
> +
> +typedef struct _KEY_SERVICE_PPI KEY_SERVICE_PPI;
> +
> +///
> +/// KEY SERVICE PPI
> +/// The interface functions are for Key Service in PEI Phase
> +///
> +struct _KEY_SERVICE_PPI {
> +  KEY_SERVICE_GEN_KEY    GenerateKey; /// Generate Key
> +};
> +
> +#endif
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs
  2022-11-06  7:35 ` [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs Judah Vang
@ 2022-11-22  6:55   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  6:55 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C

Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V4: Applied code review - Remove empty Guids section
> from .inf file. Update description in *.c. Remove *.uni file
> and reference to it.
> 
> V1: Provide null ecryption variable libraries.
> These will be used by default for platforms that don't
> support protected variable encryption.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf |
> 34 ++++++++
>  SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c          | 92
> ++++++++++++++++++++
>  2 files changed, 126 insertions(+)
> 
> diff --git
> a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> new file mode 100644
> index 000000000000..185b6f9bedf7
> --- /dev/null
> +++
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> @@ -0,0 +1,34 @@
> +## @file
> +#  Provides NULL version of encryption variable services.
> +#
> +#  Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = EncryptionVariableLibNull
> +  FILE_GUID                      = 3972E6FE-74D5-45C3-A9FB-DB9E5E5C9C17
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = EncryptionVariableLib
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  EncryptionVariable.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  DebugLib
> diff --git a/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> new file mode 100644
> index 000000000000..52ee8a7b5aae
> --- /dev/null
> +++ b/SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> @@ -0,0 +1,92 @@
> +/** @file
> +  NULL implementation of EncryptionVariableLib.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/EncryptionVariableLib.h>
> +#include <Library/DebugLib.h>
> +
> +/**
> +  Encrypt variable data.
> +
> +  Null version.
> +
> +  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
> +                                 information about a variable.
> +
> +  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +EncryptVariable (
> +  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Decrypt variable data.
> +
> +  Null version.
> +
> +  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
> +                                 information about a variable.
> +
> +  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DecryptVariable (
> +  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Get cipher information.
> +
> +  Null version.
> +
> +  @param[in]   VarEncInfo   Pointer to structure containing detailed
> +                            information about a variable.
> +
> +  @retval EFI_UNSUPPORTED         Unsupported interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetCipherDataInfo (
> +  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Set cipher information for a variable.
> +
> +  Null version.
> +
> +  @param[in]   VarEncInfo   Pointer to structure containing detailed
> +                            information about a variable.
> +
> +  @retval EFI_UNSUPPORTED         If this method is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetCipherDataInfo (
> +  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES
  2022-11-06  7:35 ` [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
@ 2022-11-22  7:15   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  7:15 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io
  Cc: Yao, Jiewen, Xu, Min M, Mistry, Nishant C

Judah,

Just some typos found. See inline comments below starting with "[JianJW]".
With them addressed,

    Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Xu, Min M <min.m.xu@intel.com>; Mistry, Nishant C
> <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V3: Change AllocateZeroPool() with AllocatePages() and FreePool()
> with FreePages(). FreePool() is not supported in PEI phase so this was
> causing a memory leak. Reverse the order of the FreePages() call.
> 
> V1: Add encryption/decryption of protected variable functionality.
> Add functions to get/set cipher data of a protected variable.
> This is use for supporting confidentiality for protected
> variables.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Min Xu <min.m.xu@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf |  43 ++
>  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h      |  49 ++
>  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c      | 734
> ++++++++++++++++++++
>  3 files changed, 826 insertions(+)
> 
> diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> new file mode 100644
> index 000000000000..7ece52f2fb58
> --- /dev/null
> +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> @@ -0,0 +1,43 @@
> +## @file
> +#  Provides variable encryption/decryption services.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010029
> +  BASE_NAME                      = EncryptionVariableLib
> +  FILE_GUID                      = 459E2CB0-AF4B-4415-B6A1-335E71FD8B85
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = EncryptionVariableLib
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  EncryptionVariable.c
> +  EncryptionVariable.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  BaseCryptLib
> +
> +[Guids]
> +  gEfiVariableGuid
> +  gEfiAuthenticatedVariableGuid
> diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> new file mode 100644
> index 000000000000..f35f9f9e3ad7
> --- /dev/null
> +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> @@ -0,0 +1,49 @@
> +/** @file
> +  Definitions used by this library implementation.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef ENCRYPTION_VARIABLE_H_
> +#define ENCRYPTION_VARIABLE_H_
> +
> +#define ENC_KEY_SEP        L":"
> +#define ENC_KEY_SEP_SIZE   2
> +#define ENC_KEY_NAME       L"VAR_ENC_KEY"
> +#define ENC_KEY_NAME_SIZE  22
> +
> +#define ENC_KEY_SIZE    (256/8)
> +#define ENC_BLOCK_SIZE  AES_BLOCK_SIZE
> +#define ENC_IVEC_SIZE   ENC_BLOCK_SIZE
> +
> +#define ENC_PADDING_BYTE  0x0F
> +
> +//
> +// PKCS#5 padding
> +//
> +// #define AES_CIPHER_DATA_SIZE(PlainDataSize)
> +//  (AES_BLOCK_SIZE + (PlainDataSize)) & (~(AES_BLOCK_SIZE - 1))
> +//
> +#define AES_CIPHER_DATA_SIZE(PlainDataSize)  ALIGN_VALUE (PlainDataSize,
> AES_BLOCK_SIZE)
> +
> +#define FREE_POOL(Address)      \
> +    if ((Address) != NULL) {    \
> +      FreePool (Address);       \
> +      (Address) = NULL;         \
> +    }
> +
> +#pragma pack(1)
> +
> +typedef struct {
> +  UINT32    DataType;         // SYM_TYPE_AES
> +  UINT32    HeaderSize;       // sizeof(VARIABLE_ENCRYPTION_HEADER)
> +  UINT32    PlainDataSize;    // Plain data size
> +  UINT32    CipherDataSize;   // Cipher data size
> +  UINT8     KeyIvec[ENC_IVEC_SIZE];
> +} VARIABLE_ENCRYPTION_HEADER;
> +
> +#pragma pack()
> +
> +#endif // _ENCRYPTION_VARIABLE_H_
> diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> new file mode 100644
> index 000000000000..d128b32f93e0
> --- /dev/null
> +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> @@ -0,0 +1,734 @@
> +/** @file
> +  Implementation of EncryptionVariableLib with AES algorithm support.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Guid/VariableFormat.h>
> +#include <Library/EncryptionVariableLib.h>
> +#include <Library/BaseCryptLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +
> +#include "EncryptionVariable.h"
> +
> +/**
> +  Derive encryption key for given variable from variable root key.
> +
> +  The derivation algorithm is depicted below
> +
> +    HKDF_Expand(SHA256, RootKey,
> Name||':'||Guid||':'||Attr||"VAR_ENC_KEY")
> +
> +  @param[in]    VarEncInfo    Pointer to structure containing detailed
> +                              information about a variable.
> +  @param[in]    EncKeySize    Size of key requested.
> +  @param[out]   EncKey        Buffer of key.
> +
> +  @retval TRUE    The key was derived successfully.
> +  @retval FALSE   Failed to generate encryption key.
> +
> +**/
> +STATIC
> +BOOLEAN
> +EncVarLibGenEncKey (
> +  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo,
> +  IN UINTN                     EncKeySize,
> +  OUT UINT8                    *EncKey
> +  )
> +{
> +  BOOLEAN  Status;
> +
> +  struct {
> +    VOID     *Data;
> +    UINTN    Size;
> +  }                 InfoGroup[6];
> +  UINT8  *Info;
> +  UINTN  InfoSize;
> +  UINTN  Index;
> +  UINT8  Salt[16];
> +
> +  //
> +  // info: Name||':'||Guid||':'||Attr||"VAR_ENC_KEY"
> +  //
> +  InfoGroup[0].Size = VarEncInfo->Header.NameSize;
> +  InfoGroup[0].Data = VarEncInfo->Header.VariableName;
> +
> +  InfoGroup[1].Size = ENC_KEY_SEP_SIZE;
> +  InfoGroup[1].Data = ENC_KEY_SEP;
> +
> +  InfoGroup[2].Size = sizeof (*VarEncInfo->Header.VendorGuid);
> +  InfoGroup[2].Data = VarEncInfo->Header.VendorGuid;
> +
> +  InfoGroup[3].Size = ENC_KEY_SEP_SIZE;
> +  InfoGroup[3].Data = ENC_KEY_SEP;
> +
> +  InfoGroup[4].Size = sizeof (VarEncInfo->Header.Attributes);
> +  InfoGroup[4].Data = &VarEncInfo->Header.Attributes;
> +
> +  InfoGroup[5].Size = ENC_KEY_NAME_SIZE;
> +  InfoGroup[5].Data = ENC_KEY_NAME;
> +
> +  for (InfoSize = 0, Index = 0; Index < ARRAY_SIZE (InfoGroup); ++Index) {
> +    InfoSize += InfoGroup[Index].Size;
> +  }
> +
> +  Info = AllocatePages (EFI_SIZE_TO_PAGES (InfoSize));
> +  if (Info == NULL) {
> +    ASSERT (Info != NULL);
> +    return FALSE;
> +  }
> +
> +  for (InfoSize = 0, Index = 0; Index < ARRAY_SIZE (InfoGroup); ++Index) {
> +    CopyMem (Info + InfoSize, InfoGroup[Index].Data, InfoGroup[Index].Size);
> +    InfoSize += InfoGroup[Index].Size;
> +  }
> +
> +  Status = HkdfSha256ExtractAndExpand (
> +             VarEncInfo->Key,
> +             VarEncInfo->KeySize,
> +             Salt,
> +             0,
> +             Info,
> +             InfoSize,
> +             EncKey,
> +             EncKeySize
> +             );
> +
> +  FreePages (Info, EFI_SIZE_TO_PAGES (InfoSize));
> +
> +  return Status;
> +}
> +
> +/**
> +  Generate init-vector for AES encryption.
> +
> +  @param[out]   InitVector  IVEC buffer.
> +  @param[in]    Size        Size of IVEC requested.
> +
> +  @retval TRUE    IVEC was generated successfully.
> +  @retval FALSE   Failed to generate IVEC.
> +
> +**/
> +STATIC
> +BOOLEAN
> +EncVarLibGenIvec (
> +  OUT UINT8  *InitVector,
> +  IN  UINTN  Size
> +  )
> +{
> +  return RandomBytes (InitVector, Size);
> +}
> +
> +/**
> +  Check if there's valid variable information needed by encrypting or decrypting.
> +
> +  @param[in]    VarEncInfo    Buffer conveying details about a variable.
> +  @param[in]    CheckForEnc   Flag indicating check for encrypting (TRUE) or
> +                              decrypting (FALSE).
> +
> +  @retval TRUE    VarEncInfo is valid.
> +  @retval FALSE   VarEncInfo is invalid.
> +
> +**/
> +STATIC
> +BOOLEAN
> +IsValidVariableInfo (
> +  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo,
> +  IN BOOLEAN                   CheckForEnc
> +  )
> +{
> +  BOOLEAN  Valid;
> +
> +  if (CheckForEnc) {
> +    Valid = (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize >
> 0)
> +            || (VarEncInfo->PlainData != NULL && VarEncInfo->PlainDataSize > 0);
> +    if (!Valid) {
> +      ASSERT (
> +        (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
> +             || (VarEncInfo->PlainData != NULL && VarEncInfo->PlainDataSize > 0)
> +        );
> +    }
> +  } else {
> +    Valid = (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize >
> 0)
> +            || (VarEncInfo->CipherData != NULL && VarEncInfo->CipherDataSize >
> 0);
> +    if (!Valid) {
> +      ASSERT (
> +        (VarEncInfo->Header.Data != NULL && VarEncInfo->Header.DataSize > 0)
> +             || (VarEncInfo->CipherData != NULL && VarEncInfo->CipherDataSize >
> 0)
> +        );
> +    }
> +  }
> +
> +  Valid = Valid
> +          && VarEncInfo->Header.VariableName != NULL
> +          && VarEncInfo->Header.NameSize > 0
> +          && VarEncInfo->Header.VendorGuid != NULL
> +          && VarEncInfo->Key != NULL
> +          && VarEncInfo->KeySize > 0;
> +  if (!Valid) {
> +    ASSERT (VarEncInfo->Header.VariableName != NULL);
> +    ASSERT (VarEncInfo->Header.NameSize != 0);
> +    ASSERT (VarEncInfo->Header.VendorGuid != NULL);
> +    ASSERT (VarEncInfo->Key != NULL);
> +    ASSERT (VarEncInfo->KeySize > 0);
> +  }
> +
> +  return Valid;
> +}
> +
> +/**
> +  Sanity check of encrption header prefixed to encrypted data.

[JianJW] typo: " encrption" -> "encryption"

> +
> +  @param[in]    EncHeader   Pointer to VARIABLE_ENCRYPTION_HEADER.
> +  @param[in]    DataSize    Size of variable data payload.
> +
> +  @retval TRUE    EncHeader is valid.
> +  @retval FALSE   EncHeader is invalid.
> +
> +**/
> +STATIC
> +BOOLEAN
> +IsValidEncrptionHeader (

[JianJW] "IsValidEncrptionHeader" -> " IsValidEncryptionHeader"

> +  IN VARIABLE_ENCRYPTION_HEADER  *EncHeader,
> +  IN UINT32                      DataSize
> +  )
> +{
> +  if (  (DataSize > sizeof (VARIABLE_ENCRYPTION_HEADER))
> +     && ((EncHeader->DataType == ENC_TYPE_AES) || (EncHeader->DataType
> == ENC_TYPE_NULL))
> +     && (EncHeader->HeaderSize >= sizeof (VARIABLE_ENCRYPTION_HEADER))
> +     && (EncHeader->CipherDataSize > 0)
> +     && ((EncHeader->CipherDataSize % ENC_BLOCK_SIZE) == 0)
> +     && (EncHeader->PlainDataSize > 0)
> +     && (EncHeader->PlainDataSize <= EncHeader->CipherDataSize)
> +     && ((EncHeader->CipherDataSize + EncHeader->HeaderSize) <= DataSize))
> +  {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Encrypt variable data.
> +
> +  If VarEncInfo->PlainData is not NULL, VarEncInfo->PlainData holds the plain
> +  data. Otherwise, VarEncInfo->Headr.Data is supposed to be the plain data.

[JianJW] "Headr" -> "Header"

> +
> +  If VarEncInfo->CipherData is not NULL, The encrypted data is stored in
> +  VarEncInfo->CipherData. Otherwise, the encrypted data is stored directly
> +  in variable data buffer, i.e. VarEncInfo->Headr.Data.

[JianJW] "Headr" -> "Header"

> +
> +  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
> +                                 information about a variable.
> +
> +  @retval EFI_SUCCESS             Variable was encrypted successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_BUFFER_TOO_SMALL    VarEncInfo->CipherData is not NULL but
> +                                  VarEncInfo->CipherDataSize is too small.
> +  @retval EFI_ABORTED             Uknown error occurred during encrypting.
> +  @retval EFI_OUT_OF_RESOURCES    Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +EncryptVariable (
> +  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  VOID                        *AesContext;
> +  UINT8                       EncKey[ENC_KEY_SIZE];
> +  UINT8                       Ivec[ENC_IVEC_SIZE];
> +  UINT8                       *PlainBuffer;
> +  UINT8                       *CipherBuffer;
> +  UINT8                       *PlainData;
> +  UINT32                      PlainDataSize;
> +  VARIABLE_ENCRYPTION_HEADER  *CipherData;
> +  UINT32                      CipherDataSize;
> +  UINT32                      PaddingBytes;
> +
> +  Status       = EFI_ABORTED;
> +  AesContext   = NULL;
> +  PlainBuffer  = NULL;
> +  CipherBuffer = NULL;
> +
> +  if (!IsValidVariableInfo (VarEncInfo, TRUE)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (VarEncInfo->PlainData != NULL) {
> +    PlainData     = VarEncInfo->PlainData;
> +    PlainDataSize = VarEncInfo->PlainDataSize;
> +  } else {
> +    PlainData     = VarEncInfo->Header.Data;
> +    PlainDataSize = (UINT32)VarEncInfo->Header.DataSize;
> +  }
> +
> +  CipherDataSize = AES_CIPHER_DATA_SIZE (PlainDataSize);
> +  if (VarEncInfo->CipherData != NULL) {
> +    if (VarEncInfo->CipherDataSize
> +        < (CipherDataSize + sizeof (VARIABLE_ENCRYPTION_HEADER)))
> +    {
> +      VarEncInfo->CipherDataSize = CipherDataSize
> +                                   + sizeof (VARIABLE_ENCRYPTION_HEADER);
> +      return EFI_BUFFER_TOO_SMALL;
> +    }
> +
> +    CipherData = VarEncInfo->CipherData;
> +  } else {
> +    CipherData = VarEncInfo->Header.Data;
> +  }
> +
> +  //
> +  // Prepare buffer for encrypted data.
> +  //
> +  if ((UINTN)CipherData == (UINTN)PlainData) {
> +    //
> +    // Need buffer to store the encrypted data temporarily.
> +    //
> +    CipherBuffer = (UINT8 *)AllocateZeroPool (
> +                              CipherDataSize
> +                              + sizeof (VARIABLE_ENCRYPTION_HEADER)
> +                              );
> +    if (CipherBuffer == NULL) {
> +      ASSERT (CipherBuffer != NULL);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +  } else {
> +    CipherBuffer = (UINT8 *)CipherData;
> +  }
> +
> +  //
> +  // Plain variable data must also be multiple of ENC_BLOCK_SIZE.
> +  //
> +  PaddingBytes = ALIGN_VALUE (PlainDataSize, ENC_BLOCK_SIZE) -
> PlainDataSize;
> +  if (PaddingBytes != 0) {
> +    //
> +    // Since the plain data size will be saved in the
> VARIABLE_ENCRYPTION_HEADER,
> +    // there's no need to do PKCS way of padding. To save space, just padding
> +    // the plain data to be of the nearest n*ENC_BLOCK_SIZE.
> +    //
> +    PlainBuffer = AllocateZeroPool (PlainDataSize + PaddingBytes);
> +    if (PlainBuffer == NULL) {
> +      ASSERT (PlainBuffer != NULL);
> +      goto Done;
> +    }
> +
> +    CopyMem (PlainBuffer, PlainData, PlainDataSize);
> +    SetMem (PlainBuffer + PlainDataSize, PaddingBytes, ENC_PADDING_BYTE);
> +  } else {
> +    PlainBuffer = PlainData;
> +  }
> +
> +  //
> +  // Skip EFI_VARIABLE_APPEND_WRITE bit in generating encryption key.
> +  //
> +  VarEncInfo->Header.Attributes &= (~EFI_VARIABLE_APPEND_WRITE);
> +  if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) {
> +    ASSERT (FALSE);
> +    return EFI_ABORTED;
> +  }
> +
> +  if (!EncVarLibGenIvec (Ivec, ENC_IVEC_SIZE)) {
> +    ASSERT (FALSE);
> +    return EFI_ABORTED;
> +  }
> +
> +  AesContext = AllocateZeroPool (AesGetContextSize ());
> +  if (AesContext == NULL) {
> +    ASSERT (AesContext != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) {
> +    ASSERT (FALSE);
> +    goto Done;
> +  }
> +
> +  if (AesCbcEncrypt (
> +        AesContext,
> +        PlainBuffer,
> +        PlainDataSize + PaddingBytes,
> +        Ivec,
> +        CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER)
> +        ))
> +  {
> +    //
> +    // Keep the IV for decryption.
> +    //
> +    CopyMem (CipherData->KeyIvec, Ivec, ENC_BLOCK_SIZE);
> +
> +    if ((UINTN)CipherBuffer != (UINTN)CipherData) {
> +      CopyMem (
> +        CipherData + 1,
> +        CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER),
> +        CipherDataSize
> +        );
> +    }
> +
> +    CipherData->CipherDataSize = CipherDataSize;
> +    CipherData->PlainDataSize  = PlainDataSize;
> +    CipherData->DataType       = ENC_TYPE_AES;
> +    CipherData->HeaderSize     = sizeof (VARIABLE_ENCRYPTION_HEADER);
> +
> +    VarEncInfo->CipherData       = CipherData;
> +    VarEncInfo->CipherDataSize   = CipherDataSize + sizeof
> (VARIABLE_ENCRYPTION_HEADER);
> +    VarEncInfo->CipherHeaderSize = sizeof (VARIABLE_ENCRYPTION_HEADER);
> +    VarEncInfo->CipherDataType   = ENC_TYPE_AES;
> +
> +    Status = EFI_SUCCESS;
> +  } else {
> +    VarEncInfo->CipherData       = NULL;
> +    VarEncInfo->CipherDataSize   = 0;
> +    VarEncInfo->CipherHeaderSize = 0;
> +    VarEncInfo->CipherDataType   = ENC_TYPE_NULL;
> +
> +    ASSERT (FALSE);
> +  }
> +
> +Done:
> +  FREE_POOL (AesContext);
> +  if (PlainBuffer != PlainData) {
> +    FREE_POOL (PlainBuffer);
> +  }
> +
> +  if (CipherBuffer != (UINT8 *)CipherData) {
> +    FREE_POOL (CipherBuffer);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Decrypt variable data.
> +
> +  If VarEncInfo->CipherData is not NULL, it must holds the cipher data to be
> +  decrypted. Otherwise, assume the cipher data from variable data buffer, i.e.
> +  VarEncInfo->Header.Data.
> +
> +  If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be put
> +  back in the same buffer as cipher buffer got above, after encryption header,
> +  which helps to identify later if the data in buffer is decrypted or not. This
> +  can avoid repeat decryption when accessing the same variable more than
> once.
> +
> +  If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must be
> +  passed in with a valid buffer with VarEncInfo->PlainDataSize set correctly
> +  with its size.
> +
> +  Note the VarEncInfo->PlainData is always pointing to the buffer address with
> +  decrypted data without encryption header, and VarEncInfo->PlainDataSize is
> +  always the size of original variable data, if this function returned
> +  successfully.
> +
> +  @param[in, out]   VarEncInfo   Pointer to structure containing detailed
> +                                 information about a variable.
> +
> +  @retval EFI_SUCCESS             Variable was decrypted successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_BUFFER_TOO_SMALL    VarEncInfo->PlainData is not NULL but
> +                                  VarEncInfo->PlainDataSize is too small.
> +  @retval EFI_ABORTED             Uknown error occurred during decrypting.
> +  @retval EFI_OUT_OF_RESOURCES    Fail to allocate enough resource.
> +  @retval EFI_COMPROMISED_DATA    The cipher header is not valid.
> +  @retval EFI_UNSUPPORTED         Unsupported to encrypt variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DecryptVariable (
> +  IN OUT VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  VOID                        *AesContext;
> +  UINT8                       EncKey[ENC_KEY_SIZE];
> +  UINT8                       *PlainBuffer;
> +  UINT8                       *PlainData;
> +  VARIABLE_ENCRYPTION_HEADER  *CipherData;
> +  UINT32                      CipherDataSize;
> +  EFI_STATUS                  Status;
> +
> +  Status      = EFI_ABORTED;
> +  AesContext  = NULL;
> +  PlainBuffer = NULL;
> +
> +  if (!IsValidVariableInfo (VarEncInfo, FALSE)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (VarEncInfo->CipherData != NULL) {
> +    CipherData     = VarEncInfo->CipherData;
> +    CipherDataSize = VarEncInfo->CipherDataSize;
> +  } else {
> +    CipherData     = VarEncInfo->Header.Data;
> +    CipherDataSize = (UINT32)VarEncInfo->Header.DataSize;
> +  }
> +
> +  //
> +  // Sanity check of cipher header.
> +  //
> +  if (!IsValidEncrptionHeader (CipherData, CipherDataSize)) {
> +    return EFI_COMPROMISED_DATA;
> +  }
> +
> +  if (  (VarEncInfo->PlainData != NULL)
> +     && (VarEncInfo->PlainDataSize < CipherData->PlainDataSize))
> +  {
> +    VarEncInfo->PlainDataSize = CipherData->PlainDataSize;
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  if (CipherData->DataType == ENC_TYPE_AES) {
> +    if (VarEncInfo->Flags.DecryptInPlace) {
> +      //
> +      // Reusing cipher data buffer needs to keep the encryption header.
> +      //
> +      PlainData = (UINT8 *)CipherData + CipherData->HeaderSize;
> +    } else {
> +      PlainData = VarEncInfo->PlainData;
> +    }
> +
> +    if (PlainData == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    //
> +    // Always need buffer to store the decrypted data temporarily, due to
> +    // padding bytes or buffer reuse. Then the buffer must be larger than
> +    // CipherData->PlainDataSize.
> +    //
> +    PlainBuffer = AllocatePages (EFI_SIZE_TO_PAGES (CipherDataSize));
> +    if (PlainBuffer == NULL) {
> +      ASSERT (PlainBuffer != NULL);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) {
> +      ASSERT (FALSE);
> +      goto Done;
> +    }
> +
> +    AesContext = AllocatePages (EFI_SIZE_TO_PAGES (AesGetContextSize ()));
> +    if (AesContext == NULL) {
> +      ASSERT (AesContext != NULL);
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto Done;
> +    }
> +
> +    if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) {
> +      ASSERT (FALSE);
> +      goto Done;
> +    }
> +
> +    if (AesCbcDecrypt (
> +          AesContext,
> +          (UINT8 *)CipherData + CipherData->HeaderSize,
> +          CipherDataSize - CipherData->HeaderSize,
> +          CipherData->KeyIvec,
> +          PlainBuffer
> +          ))
> +    {
> +      Status = EFI_SUCCESS;
> +    } else {
> +      Status = EFI_COMPROMISED_DATA;
> +    }
> +  } else {
> +    //
> +    // The data has been decrypted already.
> +    //
> +    PlainBuffer = (UINT8 *)CipherData + CipherData->HeaderSize;
> +
> +    if (VarEncInfo->PlainData != NULL) {
> +      PlainData = VarEncInfo->PlainData;
> +    } else {
> +      PlainData = PlainBuffer;
> +    }
> +
> +    Status = EFI_SUCCESS;
> +  }
> +
> +  if (!EFI_ERROR (Status)) {
> +    if (PlainBuffer != PlainData) {
> +      CopyMem (PlainData, PlainBuffer, CipherData->PlainDataSize);
> +    }
> +
> +    if (VarEncInfo->PlainData != NULL) {
> +      if (VarEncInfo->PlainData != PlainBuffer) {
> +        CopyMem (VarEncInfo->PlainData, PlainBuffer, CipherData-
> >PlainDataSize);
> +      }
> +    } else {
> +      VarEncInfo->PlainData = PlainData;
> +    }
> +
> +    VarEncInfo->PlainDataSize    = CipherData->PlainDataSize;
> +    VarEncInfo->CipherHeaderSize = CipherData->HeaderSize;
> +    VarEncInfo->CipherDataType   = CipherData->DataType;
> +
> +    if (VarEncInfo->Flags.DecryptInPlace) {
> +      CipherData->DataType = ENC_TYPE_NULL;
> +    }
> +  }
> +
> +Done:
> +  if (AesContext != NULL) {
> +    FreePages (AesContext, EFI_SIZE_TO_PAGES (AesGetContextSize ()));
> +  }
> +
> +  if (PlainBuffer != NULL) {
> +    FreePages (PlainBuffer, EFI_SIZE_TO_PAGES ((CipherDataSize)));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Get cipher information about a variable, including plaindata size,
> +  cipher algorithm type, etc.
> +
> +  For data passed in with VarEncInfo,
> +
> +    VarEncInfo->Header.Data
> +      - The variable data in normal variable structure.
> +    VarEncInfo->Header.DataSize
> +      - The size of variable data.
> +
> +  For data passed out with VarEncInfo (valid only if EFI_SUCCESS is returned),
> +
> +    VarEncInfo->CipherDataType
> +      - ENC_TYPE_NULL, if the variable is not encrypted or has been decrypted;
> +      - ENC_TYPE_AES, if the variable is encrypted.
> +    VarEncInfo->CipherHeaderSize
> +      - Size of cipher header put before encrypted or decrypted data.
> +    VarEncInfo->PlainData
> +      - NULL, if the variable is encrypted; Or
> +      - pointer to original variable data, if the variable has been decrypted.
> +    VarEncInfo->PlainDataSize
> +      - The size of original variable data
> +    VarEncInfo->CipherData
> +      - NULL, if the variable is decrypted; Or
> +      - pointer to start of encrypted variable data, including encryption header;
> +    VarEncInfo->CipherDataSize
> +      - The size of encrypted variable data, including encryption header.
> +
> +  @param[in]   VarEncInfo   Pointer to structure containing detailed
> +                            information about a variable.
> +
> +  @retval EFI_SUCCESS             The information was retrieved successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_NOT_FOUND           No cipher information recognized.
> +  @retval EFI_UNSUPPORTED         Unsupported interface.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetCipherDataInfo (
> +  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  VARIABLE_ENCRYPTION_HEADER  *EncHeader;
> +
> +  if ((VarEncInfo->Header.Data == NULL) || (VarEncInfo->Header.DataSize == 0))
> {
> +    ASSERT (VarEncInfo->Header.Data != NULL);
> +    ASSERT (VarEncInfo->Header.DataSize != 0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Validate encryption header.
> +  //
> +  EncHeader = (VARIABLE_ENCRYPTION_HEADER *)VarEncInfo->Header.Data;
> +  if (!IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo-
> >Header.DataSize)) {
> +    //
> +    // Not an encrypted variable.
> +    //
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (EncHeader->DataType == ENC_TYPE_NULL) {
> +    //
> +    // The data must have been decrypted.
> +    //
> +    VarEncInfo->PlainData            = (UINT8 *)VarEncInfo->Header.Data +
> EncHeader->HeaderSize;
> +    VarEncInfo->CipherData           = NULL;
> +    VarEncInfo->Flags.DecryptInPlace = TRUE;
> +  } else {
> +    //
> +    // The data is encrypted.
> +    //
> +    VarEncInfo->CipherData           = VarEncInfo->Header.Data;
> +    VarEncInfo->PlainData            = NULL;
> +    VarEncInfo->Flags.DecryptInPlace = FALSE;
> +  }
> +
> +  VarEncInfo->PlainDataSize    = EncHeader->PlainDataSize;
> +  VarEncInfo->CipherDataSize   = EncHeader->CipherDataSize + EncHeader-
> >HeaderSize;
> +  VarEncInfo->CipherDataType   = EncHeader->DataType;
> +  VarEncInfo->CipherHeaderSize = EncHeader->HeaderSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Force set cipher information for a variable, like plaindata size,
> +  cipher algorithm type, cipher data etc.
> +
> +  The destination buffer must be passed via VarEncInfo->Header.Data.
> +
> +  This method is only used to update and/or change plain data information.
> +
> +  @param[in]   VarEncInfo   Pointer to structure containing detailed
> +                            information about a variable.
> +
> +  @retval EFI_SUCCESS             The information was updated successfully.
> +  @retval EFI_INVALID_PARAMETER   Variable information in VarEncInfo is
> invalid.
> +  @retval EFI_UNSUPPORTED         If this method is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SetCipherDataInfo (
> +  IN VARIABLE_ENCRYPTION_INFO  *VarEncInfo
> +  )
> +{
> +  VARIABLE_ENCRYPTION_HEADER  *EncHeader;
> +  UINT8                       *Data;
> +
> +  if (  (VarEncInfo->Header.Data == NULL)
> +     || (VarEncInfo->Header.DataSize < sizeof
> (VARIABLE_ENCRYPTION_HEADER))
> +     || (VarEncInfo->CipherDataType != ENC_TYPE_NULL))
> +  {
> +    ASSERT (VarEncInfo->Header.Data != NULL);
> +    ASSERT (VarEncInfo->Header.DataSize >= sizeof
> (VARIABLE_ENCRYPTION_HEADER));
> +    ASSERT (VarEncInfo->CipherDataType == ENC_TYPE_NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Data      = VarEncInfo->Header.Data;
> +  EncHeader = (VARIABLE_ENCRYPTION_HEADER *)Data;
> +
> +  if (  !IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo-
> >Header.DataSize)
> +     || (VarEncInfo->PlainDataSize > EncHeader->CipherDataSize))
> +  {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((VarEncInfo->PlainData != NULL) && (VarEncInfo->PlainDataSize > 0)) {
> +    CopyMem (
> +      Data + EncHeader->HeaderSize,
> +      VarEncInfo->PlainData,
> +      VarEncInfo->PlainDataSize
> +      );
> +  }
> +
> +  EncHeader->DataType = VarEncInfo->CipherDataType;
> +  if (VarEncInfo->PlainDataSize != 0) {
> +    EncHeader->PlainDataSize = VarEncInfo->PlainDataSize;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services
  2022-11-06  7:35 ` [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services Judah Vang
@ 2022-11-22  7:59   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  7:59 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io
  Cc: Yao, Jiewen, Xu, Min M, Mistry, Nishant C

Judah,

Several format issues. See inline comments starting with "[JianJW]".
With them addressed,

    Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Xu, Min M <min.m.xu@intel.com>; Mistry, Nishant C
> <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> V5: Applied code review comments. Remove unused API.
> V3: Change placement of buffer used for confidentiality crypto
> operation to fix an issue when enabling confidentiality. Remove
> un-needed increment of monotonic counter.
> 
> V1: Add Protected Variable Services across the different UEFI phases.
> Functions includes creating variable digest, performing integrity
> check, initializing protected variables, updating protected
> variables, and verifying the MetaDataHmacVar variable.
> This module prevents UEFI variable tampering.  It provides
> variable integrity and confidentiality.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Min Xu <min.m.xu@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf        |   64
> +
>  SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf        |   68
> +
>  SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf        |
> 67 +
>  SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
> |   62 +
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h        |
> 589 ++++++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c          |
> 2103 ++++++++++++++++++++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c             |  163
> ++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c             | 1327
> ++++++++++++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c             |  209
> ++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c
> |  967 +++++++++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c      |
> 233 +++
>  11 files changed, 5852 insertions(+)
> 
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> new file mode 100644
> index 000000000000..74a0285af7ef
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> @@ -0,0 +1,64 @@
> +## @file
> +#  Provides protected variable services for EmulatorPkg.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010029
> +  BASE_NAME                      = DxeProtectedVariableLib
> +  MODULE_UNI_FILE                = ProtectedVariableLib.uni
> +  FILE_GUID                      = 6F424E10-0F75-4716-9F97-58C2E1C643AD
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
> +  VERSION_STRING                 = 0.1
> +  LIBRARY_CLASS                  = ProtectedVariableLib|DXE_RUNTIME_DRIVER
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  ProtectedVariableDxe.c
> +  ProtectedVariableCommon.c
> +  ProtectedVariableSmmDxeCommon.c
> +  ProtectedVariableInternal.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  HobLib
> +  BaseCryptLib
> +  EncryptionVariableLib
> +  RpmcLib
> +  HashApiLib
> +  SortLib
> +
> +[Protocols]
> +  gEfiVariableWriteArchProtocolGuid
> +
> +[Guids]
> +  gEdkiiMetaDataHmacVariableGuid
> +  gEdkiiProtectedVariableGlobalGuid
> +  gEdkiiVarErrorFlagGuid
> +  gEdkiiProtectedVariableContextGuid
> +
> +[Pcd]
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
> diff --git a/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> new file mode 100644
> index 000000000000..44c959a94ca3
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> @@ -0,0 +1,68 @@
> +## @file
> +#  Provides protected variable services.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010029
> +  BASE_NAME                      = PeiProtectedVariableLib
> +  MODULE_UNI_FILE                = ProtectedVariableLib.uni
> +  FILE_GUID                      = 76FBFBCE-ACBB-4084-A348-8FCC97AAEB9D
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 0.1
> +  LIBRARY_CLASS                  = ProtectedVariableLib|PEIM
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 AARCH64
> +#
> +
> +[Sources]
> +  ProtectedVariablePei.c
> +  ProtectedVariableCommon.c
> +  ProtectedVariableInternal.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  HobLib
> +  BaseCryptLib
> +  RpmcLib
> +  VariableKeyLib
> +  EncryptionVariableLib
> +  ReportStatusCodeLib
> +  PeiServicesLib
> +  HashApiLib
> +  SortLib
> +
> +[Guids]
> +  gEdkiiMetaDataHmacVariableGuid
> +  gEdkiiProtectedVariableGlobalGuid
> +  gEdkiiVarErrorFlagGuid
> +  gEdkiiProtectedVariableContextGuid
> +
> +[Ppis]
> +  gEfiPeiMemoryDiscoveredPpiGuid
> +  gEfiPeiVariableStoreDiscoveredPpiGuid
> +
> +[Pcd]
> +  gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> new file mode 100644
> index 000000000000..ecf0b1a43d30
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> @@ -0,0 +1,67 @@
> +## @file
> +#  Provides protected variable services.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010029
> +  BASE_NAME                      = SmmProtectedVariableLib
> +  MODULE_UNI_FILE                = ProtectedVariableLib.uni
> +  FILE_GUID                      = 2BEE71E5-259B-4057-A2C1-2115DF43C76A
> +  MODULE_TYPE                    = DXE_SMM_DRIVER
> +  VERSION_STRING                 = 0.1
> +  LIBRARY_CLASS                  = ProtectedVariableLib|DXE_SMM_DRIVER
> MM_STANDALONE
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  ProtectedVariableSmm.c
> +  ProtectedVariableCommon.c
> +  ProtectedVariableSmmDxeCommon.c
> +  ProtectedVariableInternal.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  HobLib
> +  BaseCryptLib
> +  EncryptionVariableLib
> +  RpmcLib
> +  VariableKeyLib
> +  HashApiLib
> +  SortLib
> +
> +[Protocols]
> +  gEfiMmEndOfDxeProtocolGuid
> +
> +[Guids]
> +  gSmmVariableWriteGuid
> +  gEdkiiMetaDataHmacVariableGuid
> +  gEdkiiProtectedVariableGlobalGuid
> +  gEdkiiVarErrorFlagGuid
> +  gEdkiiProtectedVariableContextGuid
> +
> +[Pcd]
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
> +
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.i
> nf
> b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.i
> nf
> new file mode 100644
> index 000000000000..011ccdce2db8
> --- /dev/null
> +++
> b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.i
> nf
> @@ -0,0 +1,62 @@
> +## @file
> +#  Provides protected variable services.
> +#
> +#  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010029
> +  BASE_NAME                      = SmmRuntimeProtectedVariableLib
> +  MODULE_UNI_FILE                = ProtectedVariableLib.uni
> +  FILE_GUID                      = 99A623DE-1AD3-4AB3-909D-E3AADD7845EF
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
> +  VERSION_STRING                 = 0.1
> +  LIBRARY_CLASS                  = ProtectedVariableLib|DXE_DRIVER
> DXE_RUNTIME_DRIVER
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  ProtectedVariableSmmRuntime.c
> +  ProtectedVariableCommon.c
> +  ProtectedVariableInternal.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  HobLib
> +  BaseCryptLib
> +  EncryptionVariableLib
> +  RpmcLib
> +  HashApiLib
> +  SortLib
> +
> +[Guids]
> +  gEfiEventVirtualAddressChangeGuid
> +  gEdkiiMetaDataHmacVariableGuid
> +  gEdkiiProtectedVariableGlobalGuid
> +  gEdkiiVarErrorFlagGuid
> +  gEdkiiProtectedVariableContextGuid
> +
> +[Pcd]
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName
> +  gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity
> +  gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
> +
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> new file mode 100644
> index 000000000000..7948649b21bd
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> @@ -0,0 +1,589 @@
> +/** @file
> +  Definitions shared among different implementation of ProtectedVariableLib.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PROTECTED_VARIABLE_INTERNAL_H_
> +#define PROTECTED_VARIABLE_INTERNAL_H_
> +
> +#include <Guid/VariableFormat.h>
> +#include <Guid/ProtectedVariable.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/BaseCryptLib.h>
> +#include <Library/RpmcLib.h>
> +#include <Library/VariableKeyLib.h>
> +#include <Library/EncryptionVariableLib.h>
> +#include <Library/ProtectedVariableLib.h>
> +#include <Library/HashApiLib.h>
> +
> +#define VARIABLE_KEY_SIZE  (256/8)
> +
> +#define METADATA_HMAC_SIZE           (256/8)
> +#define METADATA_HMAC_KEY_NAME       L"HMAC_KEY"
> +#define METADATA_HMAC_KEY_NAME_SIZE  0x10
> +
> +#define METADATA_HMAC_SEP       L":"
> +#define METADATA_HMAC_SEP_SIZE  2
> +
> +#define METADATA_HMAC_VARIABLE_NAME       L"MetaDataHmacVar"
> +#define METADATA_HMAC_VARIABLE_NAME_SIZE  sizeof
> (METADATA_HMAC_VARIABLE_NAME)
> +#define METADATA_HMAC_VARIABLE_GUID
> gEdkiiMetaDataHmacVariableGuid
> +#define METADATA_HMAC_VARIABLE_ATTR
> VARIABLE_ATTRIBUTE_NV_BS_RT
> +
> +#define DIGEST_CONTEXT_SIZE  (HashApiGetContextSize())
> +
> +#define MAX_VARIABLE_SIZE                                                       \
> +  MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32
> (PcdMaxAuthVariableSize)),  \
> +       PcdGet32 (PcdMaxHardwareErrorVariableSize))
> +
> +#define IS_VARIABLE(Var, Name, Guid)          \
> +  (StrCmp ((Var)->VariableName, (Name)) == 0  \
> +   && CompareGuid ((CONST EFI_GUID *)(Var)->VendorGuid, (CONST EFI_GUID
> *)(Guid)))
> +
> +#define VARIABLE_SIZE(VarInfo)                                  \
> +  (((UINTN)(VarInfo)->Header.Data - (UINTN)(VarInfo)->Buffer)   \
> +   + (VarInfo)->Header.DataSize                                 \
> +   + GET_PAD_SIZE ((VarInfo)->Header.DataSize))
> +
> +#define VARIABLE_HEADER_SIZE(AuthFlag)                    \
> +  ((AuthFlag) ? sizeof (AUTHENTICATED_VARIABLE_HEADER)    \
> +              : sizeof (VARIABLE_HEADER))
> +
> +#define VARIABLE_NAME(Var, AuthFlag)                    \
> +  ((CHAR16 *)((UINTN)(Var) + VARIABLE_HEADER_SIZE(AuthFlag)))
> +
> +#define VARIABLE_START(VarStore)  \
> +   ((VARIABLE_HEADER *)HEADER_ALIGN ((VARIABLE_STORE_HEADER
> *)(VarStore) + 1))
> +
> +#define VARIABLE_END(VarStore)                         \
> +   ((VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)(VarStore) \
> +     + ((VARIABLE_STORE_HEADER *)(VarStore))->Size))
> +
> +#define SET_VARIABLE_DATA_SIZE(VarInfo, Size)                                 \
> +  if ((VarInfo)->Flags.Auth) {                                                \
> +    ((AUTHENTICATED_VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize =
> Size;  \
> +    (VarInfo)->Header.DataSize = Size;                                        \
> +  } else {                                                                    \
> +    ((VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize = Size;                \
> +      (VarInfo)->Header.DataSize = Size;                                      \
> +  }
> +
> +#define IS_KNOWN_UNPROTECTED_VARIABLE(Global, VarInfo)  \
> +  (CheckKnownUnprotectedVariable ((Global), (VarInfo)) <
> UnprotectedVarIndexMax)
> +
> +#define GET_CNTX(Global)   ((PROTECTED_VARIABLE_CONTEXT_IN
> *)(UINTN)((Global)->ContextIn))
> +#define GET_BUFR(Address)  ((VOID *)(UINTN)(Address))
> +#define GET_ADRS(Buffer)   ((EFI_PHYSICAL_ADDRESS)(UINTN)(Buffer))
> +
> +typedef struct _VARIABLE_IDENTIFIER {
> +  CHAR16      *VariableName;
> +  EFI_GUID    *VendorGuid;
> +  UINT8       State;
> +} VARIABLE_IDENTIFIER;
> +
> +typedef enum {
> +  IndexHmacInDel = 0,     /// MetaDataHmacVar with state
> VAR_IN_DELETED_TRANSITION
> +  IndexHmacAdded,         /// MetaDataHmacVar with state VAR_ADDED
> +  IndexErrorFlag,         /// VarErrorFlag
> +  IndexPlatformVar,       /// Platform Variable
> +  UnprotectedVarIndexMax
> +} UNPROTECTED_VARIABLE_INDEX;
> +
> +#pragma pack(1)
> +
> +#define PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION  0x02
> +
> +typedef struct _PROTECTED_VARIABLE_FLAG {
> +  BOOLEAN    Auth;          // Authenticated variable format
> +  BOOLEAN    WriteInit;     // Write-init-done
> +  BOOLEAN    WriteReady;    // Ready-to-write
> +  BOOLEAN    RecoveryMode;  // Variable storage recovery or provisioning
> +  BOOLEAN    CacheReady;    // Indicates Cache is available
> +  BOOLEAN    Reserved;      // reserved
> +} PROTECTED_VARIABLE_FLAG;
> +
> +typedef struct _PROTECTED_VARIABLE_GLOBAL {
> +  UINT32                     StructVersion;
> +  UINT32                     StructSize;
> +
> +  ///
> +  /// Variable root key used to derive Encryption key and HMAC key.
> +  ///
> +  UINT8                      RootKey[VARIABLE_KEY_SIZE];
> +  ///
> +  /// HMAC key derived from RootKey.
> +  ///
> +  UINT8                      MetaDataHmacKey[VARIABLE_KEY_SIZE];
> +  ///
> +  /// Number of variables in linked list pointed by VariableDigests.
> +  ///
> +  UINT32                     VariableNumber;
> +  ///
> +  /// Size of memory reserved by VariableCache.
> +  ///
> +  UINT32                     VariableCacheSize;
> +  ///
> +  /// Memory reserved to temporarily hold data of one variable, for integrity
> +  /// validation purpose.
> +  ///
> +  EFI_PHYSICAL_ADDRESS       VariableCache;
> +  ///
> +  /// Pointer to linked list, in which each node holds the digest value of each
> +  /// variable.
> +  ///
> +  EFI_PHYSICAL_ADDRESS       VariableDigests;
> +  ///
> +  /// Memory reserved for Context used in hash API to avoid repeat alloc/free.
> +  ///
> +  EFI_PHYSICAL_ADDRESS       DigestContext;
> +  ///
> +  /// Pointer to one of node in linked list pointed by VariableDigests, which
> +  /// has been just accessed. This is mainly used to facilitate the two calls
> +  /// use case of GetVariable().
> +  ///
> +  EFI_PHYSICAL_ADDRESS       LastAccessedVariable;
> +  ///
> +  /// Cached copy of pointers to nodes of unprotected variables in the linked
> +  /// list pointed by VariableDigests.
> +  ///
> +  EFI_PHYSICAL_ADDRESS       Unprotected[UnprotectedVarIndexMax];
> +  ///
> +  /// Pointer to data structure holding helper functions passed by user of
> +  /// ProtectedVariableLib, most of which are used to complete operations on
> +  /// variable storage.
> +  ///
> +  EFI_PHYSICAL_ADDRESS       ContextIn;
> +
> +  ///
> +  /// Pointer to Global data structure. This is to hold pre-mem address value.
> +  /// Later to be used to identify pre-mem to post-mem transition.
> +  ///
> +  EFI_PHYSICAL_ADDRESS       GlobalSelf;
> +
> +  PROTECTED_VARIABLE_FLAG    Flags;
> +} PROTECTED_VARIABLE_GLOBAL;
> +
> +#pragma pack()
> +
> +/* Sort method function pointer taking two parameters */
> +typedef
> +INTN
> +(*SORT_METHOD) (
> +  IN VARIABLE_DIGEST  *Variable1,
> +  IN VARIABLE_DIGEST  *Variable2
> +  );
> +
> +/* Update variable digest data function pointer */
> +typedef
> +BOOLEAN
> +(*DIGEST_UPDATE) (
> +  IN OUT  VOID   *Context,
> +  IN      VOID   *Data,
> +  IN      UINTN  DataSize
> +  );
> +
> +/**
> +
> +  Print variable information
> +
> +  @param[in]   Data8      Pointer to data
> +  @param[out]  DataSize   Size of data
> +
> +**/
> +VOID
> +PrintVariableData (
> +  IN UINT8  *Data8,
> +  IN UINTN  DataSize
> +  );
> +
> +/**
> +
> +  Derive HMAC key from given variable root key.
> +
> +  @param[in]  RootKey       Pointer to root key to derive from.
> +  @param[in]  RootKeySize   Size of root key.
> +  @param[out] HmacKey       Pointer to generated HMAC key.
> +  @param[in]  HmacKeySize   Size of HMAC key.
> +
> +  @retval TRUE      The HMAC key is derived successfully.
> +  @retval FALSE     Failed to generate HMAC key from given root key.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +GenerateMetaDataHmacKey (
> +  IN   CONST UINT8  *RootKey,
> +  IN   UINTN        RootKeySize,
> +  OUT  UINT8        *HmacKey,
> +  IN   UINTN        HmacKeySize
> +  );
> +
> +/**
> +
> +  Digests the given variable data and updates HMAC context.
> +
> +  @param[in,out]  Context   Pointer to initialized HMAC context.
> +  @param[in]      VarInfo   Pointer to variable data.
> +
> +  @retval TRUE    HMAC context was updated successfully.
> +  @retval FALSE   Failed to update HMAC context.
> +
> +**/
> +BOOLEAN
> +UpdateVariableMetadataHmac (
> +  IN  VOID                     *Context,
> +  IN  PROTECTED_VARIABLE_INFO  *VarInfo
> +  );
> +
> +/**
> +
> +  Re-calculate HMAC based on new variable data and re-generate
> MetaDataHmacVar.
> +
> +  @param[in]      Global          Pointer to global configuration data.
> +  @param[in]      NewVarInfo      Pointer to buffer of new variable data.
> +  @param[in,out]  NewHmacVarInfo  Pointer to buffer of new
> MetaDataHmacVar.
> +
> +  @return EFI_SUCCESS           The HMAC value was updated successfully.
> +  @return EFI_ABORTED           Failed to calculate the HMAC value.
> +  @return EFI_OUT_OF_RESOURCES  Not enough resource to calculate HMC
> value.
> +  @return EFI_NOT_FOUND         The MetaDataHmacVar was not found in
> storage.
> +
> +**/
> +EFI_STATUS
> +RefreshVariableMetadataHmac (
> +  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN      PROTECTED_VARIABLE_INFO    *NewVarInfo,
> +  IN  OUT PROTECTED_VARIABLE_INFO    *NewHmacVarInfo
> +  );
> +
> +/**
> +
> +  Retrieve the context and global configuration data structure from HOB.
> +
> +  Once protected NV variable storage is cached and verified in PEI phase,
> +  all related information are stored in a HOB which can be used by PEI variable
> +  service itself and passed to SMM along with the boot flow, which can avoid
> +  many duplicate works, like generating HMAC key, verifying NV variable
> storage,
> +  etc.
> +
> +  The HOB can be identified by gEdkiiProtectedVariableGlobalGuid.
> +
> +  @param[out]   Global      Pointer to global configuration data from PEI phase.
> +
> +  @retval EFI_SUCCESS     The HOB was found, and Context and Global are
> retrieved.
> +  @retval EFI_NOT_FOUND   The HOB was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableGlobalFromHob (
> +  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
> +  );
> +
> +/**
> +
> +  Get context and/or global data structure used to process protected variable.
> +
> +  @param[out]   Global      Pointer to global configuration data.
> +
> +  @retval EFI_SUCCESS         Get requested structure successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableGlobal (
> +  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
> +  );
> +
> +/**
> +
> +  Get context data structure used to process protected variable.
> +
> +  @param[out]   ContextIn   Pointer to context provided by variable runtime
> services.
> +
> +  @retval EFI_SUCCESS         Get requested structure successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableContext (
> +  PROTECTED_VARIABLE_CONTEXT_IN  **ContextIn  OPTIONAL
> +  );
> +
> +/**
> +
> +  Check if a given variable is unprotected variable specified in advance
> +  and return its index ID.
> +
> +  @param[in] Global     Pointer to global configuration data.
> +  @param[in] VarInfo    Pointer to variable information data.
> +
> +  @retval IndexHmacInDel    Variable is MetaDataHmacVar in delete-transition
> state.
> +  @retval IndexHmacAdded    Variable is MetaDataHmacVar in valid state.
> +  @retval IndexErrorFlag    Variable is VarErrorLog.
> +  @retval Others            Variable is not any known unprotected variables.
> +
> +**/
> +UNPROTECTED_VARIABLE_INDEX
> +CheckKnownUnprotectedVariable (
> +  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  PROTECTED_VARIABLE_INFO    *VarInfo
> +  );
> +
> +/**
> +
> +  Return the size of variable MetaDataHmacVar.
> +
> +  @param[in] AuthFlag         Auth-variable indicator.
> +
> +  @retval size of variable MetaDataHmacVar.
> +
> +**/
> +UINTN
> +GetMetaDataHmacVarSize (
> +  IN      BOOLEAN  AuthFlag
> +  );
> +
> +/**
> +
> +  Fix state of MetaDataHmacVar on NV variable storage, if there's failure at
> +  last boot during updating variable.
> +
> +  This must be done before the first writing of variable in current boot,
> +  including storage reclaim.
> +
> +  @retval EFI_UNSUPPORTED        Updating NV variable storage is not
> supported.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to complete the
> operation.
> +  @retval EFI_SUCCESS            Variable store was successfully updated.
> +
> +**/
> +EFI_STATUS
> +FixupHmacVariable (
> +  VOID
> +  );
> +
> +/**
> +
> +  Verify the variable digest.
> +
> +  @param[in]  Global      Pointer to global configuration data.
> +  @param[in]  VarInfo     Pointer to verified copy of protected variables.
> +  @param[in]  VarDig      Pointer to variable digest data.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
> +  @retval EFI_ABORTED            An error was encountered.
> +  @retval EFI_COMPROMISED_DATA   The data was compromised.
> +  @retval EFI_SUCCESS            Variable digest was successfully verified.
> +
> +**/
> +EFI_STATUS
> +VerifyVariableDigest (
> +  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  PROTECTED_VARIABLE_INFO    *VarInfo,
> +  IN  VARIABLE_DIGEST            *VarDig
> +  );
> +
> +/**
> +
> +  Get the variable digest.
> +
> +  @param[in]      Global        Pointer to global configuration data.
> +  @param[in]      VarInfo       Pointer to verified copy of protected variables.
> +  @param[in,out]  DigestValue   Pointer to variable digest value.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
> +  @retval EFI_ABORTED            An error was encountered.
> +  @retval EFI_COMPROMISED_DATA   The data was compromised.
> +  @retval EFI_SUCCESS            Variable digest was successfully verified.
> +
> +**/
> +EFI_STATUS
> +GetVariableDigest (
> +  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN      PROTECTED_VARIABLE_INFO    *VarInfo,
> +  IN  OUT UINT8                      *DigestValue
> +  );
> +
> +/**
> +
> +  Compare variable name and Guid
> +
> +  @param[in]  Name1      Name of first variable.
> +  @param[in]  Name1Size  Size of first variable.
> +  @param[in]  Name2      Name of second variable.
> +  @param[in]  Name2Size  Size of second variable.
> +  @param[in]  Guid1      Guid for first variable.
> +  @param[in]  Guid2      Guid for second variable.
> +
> +  @retval 0         First name is identical to Second name.
> +  @return others    First name is not identical to Second name.
> +
> +**/
> +INTN
> +CompareVariableNameAndGuid (
> +  IN CONST CHAR16  *Name1,
> +  IN UINTN         Name1Size,
> +  IN CONST CHAR16  *Name2,
> +  IN UINTN         Name2Size,
> +  IN EFI_GUID      *Guid1,
> +  IN EFI_GUID      *Guid2
> +  );
> +
> +/**
> +
> +  Compare variable digest.
> +
> +  @param[in]  Variable1     Pointer to first variable digest.
> +  @param[in]  Variable2     Pointer to second variable digest.
> +
> +  @retval 0         Variables are identical.
> +  @return others    Variables are not identical.
> +
> +**/
> +INTN
> +CompareVariableDigestInfo (
> +  IN  VARIABLE_DIGEST  *Variable1,
> +  IN  VARIABLE_DIGEST  *Variable2
> +  );
> +
> +/**
> +
> +  Move a node backward in the order controlled by SortMethod.
> +
> +  @param[in]  Node          Pointer to node to be moved.
> +  @param[in]  SortMethod    Method used to compare node in list.
> +
> +**/
> +VOID
> +MoveNodeBackward (
> +  IN  OUT VARIABLE_DIGEST  *Node,
> +  IN  SORT_METHOD          SortMethod
> +  );
> +
> +/**
> +
> +  Remove variable digest node.
> +
> +  @param[in,out]  Global        Pointer to global configuration data.
> +  @param[in,out]  VarDig        Pointer to variable digest value.
> +  @param[in]      FreeResource  Flag to indicate whether to free resource.
> +
> +**/
> +VOID
> +RemoveVariableDigestNode (
> +  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  OUT VARIABLE_DIGEST            *VarDig,
> +  IN      BOOLEAN                    FreeResource
> +  );
> +
> +/**
> +
> +  Insert variable digest node.
> +
> +  @param[in,out]  Global        Pointer to global configuration data.
> +  @param[in]      VarDig        Pointer to variable digest value.
> +  @param[in]      SortMethod    Method for sorting.
> +
> +**/
> +VOID
> +InsertVariableDigestNode (
> +  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN      VARIABLE_DIGEST            *VarDig,
> +  IN      SORT_METHOD                SortMethod
> +  );
> +
> +/**
> +
> +  Create variable digest node.
> +
> +  @param[in]  VariableName      Name of variable.
> +  @param[in]  VendorGuid        Guid of variable.
> +  @param[in]  NameSize          Size of variable name.
> +  @param[in]  DataSize          Size of variable data.
> +  @param[in]  AuthVar           Authenticated variable flag.
> +  @param[in]  Global            Pointer to global configuration data.
> +
> +  @retval Ptr   Pointer to variable digest
> +
> +**/
> +VARIABLE_DIGEST *
> +CreateVariableDigestNode (
> +  IN CHAR16                     *VariableName,
> +  IN EFI_GUID                   *VendorGuid,
> +  IN UINT16                     NameSize,
> +  IN UINT32                     DataSize,
> +  IN BOOLEAN                    AuthVar,
> +  IN PROTECTED_VARIABLE_GLOBAL  *Global
> +  );
> +
> +/**
> +
> +  Find the specified variable digest
> +
> +  @param[in]  Global        Pointer to global configuration data.
> +  @param[in]  VarInfo       Pointer to variable data.
> +  @param[in]  FindNext      Flag to continue looking for variable.
> +
> +**/
> +VARIABLE_DIGEST *
> +FindVariableInternal (
> +  IN PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN PROTECTED_VARIABLE_INFO    *VarInfo,
> +  IN BOOLEAN                    FindNext
> +  );
> +
> +/**
> +
> +  Synchronize the RPMC counters
> +
> +  @param[in]  Global      Pointer to global configuration data.
> +  @param[in]  VarInfo     Pointer to variable data.
> +  @param[in]  FindNext    Flag to continue looking for variable.
> +
> +  @retval EFI_SUCCESS     Successfully sync RPMC counters.
> +  @return others          Failed to sync RPMC counters.
> +
> +**/
> +EFI_STATUS
> +SyncRpmcCounter (
> +  VOID
> +  );
> +
> +/**
> +
> +  Perform for protected variable integrity check.
> +
> +  If this initialization failed upon any error, the whole variable services
> +  should not be used.  A system reset might be needed to re-construct NV
> +  variable storage to be the default state.
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected
> variables.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PerformVariableIntegrityCheck (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  );
> +
> +extern EFI_TIME                       mDefaultTimeStamp;
> +extern VARIABLE_IDENTIFIER
> mUnprotectedVariables[UnprotectedVarIndexMax];
> +extern PROTECTED_VARIABLE_CONTEXT_IN  mVariableContextIn;
> +extern PROTECTED_VARIABLE_GLOBAL      mProtectedVariableGlobal;
> +
> +#endif
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> new file mode 100644
> index 000000000000..456c871a4561
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> @@ -0,0 +1,2103 @@
> +/** @file
> +  The common protected variable operation routines.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Uefi.h>
> +#include <PiPei.h>
> +
> +#include <Guid/VariableFormat.h>
> +#include <Guid/VarErrorFlag.h>
> +
> +#include <Library/HobLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/HashApiLib.h>
> +#include <Library/SortLib.h>
> +
> +#include "ProtectedVariableInternal.h"
> +
> +EFI_TIME             mDefaultTimeStamp       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> +VARIABLE_IDENTIFIER  mUnprotectedVariables[] = {
> +  {
> +    METADATA_HMAC_VARIABLE_NAME,
> +    &METADATA_HMAC_VARIABLE_GUID,
> +    VAR_ADDED & VAR_IN_DELETED_TRANSITION
> +  },
> +  {
> +    METADATA_HMAC_VARIABLE_NAME,
> +    &METADATA_HMAC_VARIABLE_GUID,
> +    VAR_ADDED
> +  },
> +  {
> +    VAR_ERROR_FLAG_NAME,
> +    &gEdkiiVarErrorFlagGuid,
> +    VAR_ADDED
> +  },
> +  {
> +    (CHAR16 *)PcdGetPtr (PcdPlatformVariableName),
> +    (EFI_GUID *)PcdGetPtr (PcdPlatformVariableGuid),
> +    VAR_ADDED
> +  }
> +};
> +
> +/**
> +  Print variable information.
> +
> +  @param[in]   Data8      Pointer to data.
> +  @param[in]   DataSize   Size of data.
> +
> +**/
> +VOID
> +PrintVariableData (
> +  IN UINT8  *Data8,
> +  IN UINTN  DataSize
> +  )
> +{
> +  UINTN  Index;
> +
> +  for (Index = 0; Index < DataSize; Index++) {
> +    if (Index % 0x10 == 0) {
> +      DEBUG ((DEBUG_INFO, "\n%08X:", Index));
> +    }
> +
> +    DEBUG ((DEBUG_INFO, " %02X", *Data8++));
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "\n"));
> +}
> +
> +/**
> +
> +  Retrieve the context and global configuration data structure from HOB.
> +
> +  Once protected NV variable storage is cached and verified in PEI phase,
> +  all related information are stored in a HOB which can be used by PEI variable
> +  service itself and passed to SMM along with the boot flow, which can avoid
> +  many duplicate works, like generating HMAC key, verifying NV variable
> storage,
> +  etc.
> +
> +  The HOB can be identified by gEdkiiProtectedVariableGlobalGuid.
> +
> +  @param[out]   Global      Pointer to global configuration data from PEI phase.
> +
> +  @retval EFI_SUCCESS     The HOB was found, and Context and Global are
> retrieved.
> +  @retval EFI_NOT_FOUND   The HOB was not found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableGlobalFromHob (
> +  OUT PROTECTED_VARIABLE_GLOBAL  **Global
> +  )
> +{
> +  VOID                           *Data;
> +  EFI_PEI_HOB_POINTERS           Hob;
> +  EFI_HOB_MEMORY_ALLOCATION      *MemoryAllocationHob;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  EFI_PHYSICAL_ADDRESS           OldStart;
> +  VARIABLE_DIGEST                *VarDig;
> +  EFI_HOB_GUID_TYPE              *GuidHob;
> +  UINTN                          Index;
> +
> +  Hob.Raw = GetFirstGuidHob (&gEdkiiProtectedVariableGlobalGuid);
> +  if (Hob.Raw != NULL) {
> +    Data = GET_GUID_HOB_DATA (Hob);
> +  } else {
> +    //
> +    // Search the global from allocated memory blob.
> +    //
> +    Data                = NULL;
> +    MemoryAllocationHob = NULL;
> +
> +    Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
> +    while (Hob.Raw != NULL) {
> +      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
> +      if (CompareGuid (
> +            &MemoryAllocationHob->AllocDescriptor.Name,
> +            &gEdkiiProtectedVariableGlobalGuid
> +            ))
> +      {
> +        Data = (VOID *)(UINTN)
> +               MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress;
> +        break;
> +      }
> +
> +      Hob.Raw = GET_NEXT_HOB (Hob);
> +      Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION,
> Hob.Raw);
> +    }
> +  }
> +
> +  if (Data == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (Global != NULL) {
> +    GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
> +    if (GuidHob != NULL) {
> +      ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA
> (GuidHob);
> +    } else {
> +      ASSERT (GuidHob == NULL);
> +    }
> +
> +    *Global = (PROTECTED_VARIABLE_GLOBAL *)((UINT8 *)Data);
> +    //
> +    // Fix pointers in the HOB (due to physical memory readiness)
> +    //
> +    if ((*Global)->GlobalSelf != (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global)) {
> +      OldStart             = (*Global)->GlobalSelf;
> +      (*Global)->ContextIn = GET_ADRS (ContextIn);
> +
> +      //
> +      // Mark Memory caching is available
> +      //
> +      (*Global)->Flags.CacheReady = TRUE;
> +
> +      //
> +      // Re-allocate new minimum cache
> +      //
> +      (*Global)->VariableCache = GET_ADRS (Data)
> +                                 + ((*Global)->VariableCache - OldStart);
> +
> +      (*Global)->DigestContext = GET_ADRS (((*Global) + 1));
> +      for (Index = 0; Index < UnprotectedVarIndexMax; Index++) {
> +        if ((*Global)->Unprotected[Index] != VAR_INDEX_INVALID) {
> +          (*Global)->Unprotected[Index] = GET_ADRS (Data)
> +                                          + ((*Global)->Unprotected[Index] - OldStart);
> +        }
> +      }
> +
> +      (*Global)->LastAccessedVariable = GET_ADRS (Data)
> +                                        + ((*Global)->LastAccessedVariable - OldStart);
> +
> +      //
> +      // Fix all linked-list pointers inside VARIABLE_SIGNATURE.
> +      //
> +      (*Global)->VariableDigests = GET_ADRS (Data)
> +                                   + ((*Global)->VariableDigests - OldStart);
> +      VarDig = VAR_DIG_PTR ((*Global)->VariableDigests);
> +      while (VarDig != NULL) {
> +        if (VarDig->Prev != 0) {
> +          VarDig->Prev = GET_ADRS (Data) + (VarDig->Prev - OldStart);
> +        }
> +
> +        if (VarDig->Next != 0) {
> +          VarDig->Next = GET_ADRS (Data) + (VarDig->Next - OldStart);
> +        }
> +
> +        VarDig = VAR_DIG_NEXT (VarDig);
> +      }
> +
> +      (*Global)->GlobalSelf = (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global);
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Derive HMAC key from given variable root key.
> +
> +  @param[in]  RootKey       Pointer to root key to derive from.
> +  @param[in]  RootKeySize   Size of root key.
> +  @param[out] HmacKey       Pointer to generated HMAC key.
> +  @param[in]  HmacKeySize   Size of HMAC key.
> +
> +  @retval TRUE      The HMAC key is derived successfully.
> +  @retval FALSE     Failed to generate HMAC key from given root key.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +GenerateMetaDataHmacKey (
> +  IN   CONST UINT8  *RootKey,
> +  IN   UINTN        RootKeySize,
> +  OUT  UINT8        *HmacKey,
> +  IN   UINTN        HmacKeySize
> +  )
> +{
> +  UINT8  Salt[AES_BLOCK_SIZE];
> +
> +  return HkdfSha256ExtractAndExpand (
> +           RootKey,
> +           RootKeySize,
> +           Salt,
> +           0,
> +           (UINT8 *)METADATA_HMAC_KEY_NAME,
> +           METADATA_HMAC_KEY_NAME_SIZE,
> +           HmacKey,
> +           HmacKeySize
> +           );
> +}
> +
> +/**
> +
> +  Return the size of variable MetaDataHmacVar.
> +
> +  @param[in] AuthFlag         Auth-variable indicator.
> +
> +  @retval size of variable MetaDataHmacVar.
> +
> +**/
> +UINTN
> +GetMetaDataHmacVarSize (
> +  IN      BOOLEAN  AuthFlag
> +  )
> +{
> +  UINTN  Size;
> +
> +  if (AuthFlag) {
> +    Size = sizeof (AUTHENTICATED_VARIABLE_HEADER);
> +  } else {
> +    Size = sizeof (VARIABLE_HEADER);
> +  }
> +
> +  Size += METADATA_HMAC_VARIABLE_NAME_SIZE;
> +  Size += GET_PAD_SIZE (Size);
> +  Size += METADATA_HMAC_SIZE;
> +  Size += GET_PAD_SIZE (Size);
> +
> +  return Size;
> +}
> +
> +/**
> +
> +  Digests the given variable data and updates HMAC context.
> +
> +  @param[in]      Context        Pointer to initialized HMAC context.
> +  @param[in]      VarInfo        Pointer to variable data.
> +  @param[in]      UpdateMethod   Function to run when updating variable digest.
> +
> +  @retval TRUE    HMAC context was updated successfully.
> +  @retval FALSE   Failed to update HMAC context.
> +
> +**/
> +STATIC
> +BOOLEAN
> +UpdateVariableDigestData (
> +  IN  VOID                     *Context,
> +  IN  PROTECTED_VARIABLE_INFO  *VarInfo,
> +  IN  DIGEST_UPDATE            UpdateMethod
> +  )
> +{
> +  VOID     *Buffer[12];
> +  UINT32   BufferSize[12];
> +  UINTN    Index;
> +  BOOLEAN  Status;
> +
> +  //
> +  // Empty variable is legal here (e.g. variable deletion case or write-init case).
> +  //
> +  if ((VarInfo == NULL) ||
> +      (VarInfo->CipherData == NULL) ||
> +      (VarInfo->CipherDataSize == 0))
> +  {
> +    return TRUE;
> +  }
> +
> +  //
> +  // HMAC (":" || VariableName)
> +  //
> +  Buffer[0]     = METADATA_HMAC_SEP;
> +  BufferSize[0] = METADATA_HMAC_SEP_SIZE;
> +
> +  Buffer[1]     = VarInfo->Header.VariableName;
> +  BufferSize[1] = (UINT32)VarInfo->Header.NameSize;
> +
> +  //
> +  // HMAC (":" || VendorGuid || Attributes || DataSize)
> +  //
> +  Buffer[2]     = METADATA_HMAC_SEP;
> +  BufferSize[2] = METADATA_HMAC_SEP_SIZE;
> +
> +  Buffer[3]     = VarInfo->Header.VendorGuid;
> +  BufferSize[3] = sizeof (EFI_GUID);
> +
> +  Buffer[4]     = &VarInfo->Header.Attributes;
> +  BufferSize[4] = sizeof (VarInfo->Header.Attributes);
> +
> +  Buffer[5]     = &VarInfo->CipherDataSize;
> +  BufferSize[5] = sizeof (VarInfo->CipherDataSize);
> +
> +  //
> +  // HMAC (":" || CipherData)
> +  //
> +  Buffer[6]     = METADATA_HMAC_SEP;
> +  BufferSize[6] = METADATA_HMAC_SEP_SIZE;
> +
> +  Buffer[7]     = VarInfo->CipherData;
> +  BufferSize[7] = VarInfo->CipherDataSize;
> +
> +  //
> +  // HMAC (":" || PubKeyIndex || AuthMonotonicCount || TimeStamp)
> +  //
> +  Buffer[8]     = METADATA_HMAC_SEP;
> +  BufferSize[8] = METADATA_HMAC_SEP_SIZE;
> +
> +  Buffer[9]     = &VarInfo->Header.PubKeyIndex;
> +  BufferSize[9] = sizeof (VarInfo->Header.PubKeyIndex);
> +
> +  Buffer[10]     = &VarInfo->Header.MonotonicCount;
> +  BufferSize[10] = sizeof (VarInfo->Header.MonotonicCount);
> +
> +  Buffer[11] = (VarInfo->Header.TimeStamp != NULL) ?
> +               VarInfo->Header.TimeStamp : &mDefaultTimeStamp;
> +  BufferSize[11] = sizeof (EFI_TIME);
> +
> +  for (Index = 0; Index < ARRAY_SIZE (Buffer); ++Index) {
> +    Status = UpdateMethod (Context, Buffer[Index], BufferSize[Index]);
> +    if (!Status) {
> +      ASSERT (FALSE);
> +      return FALSE;
> +    }
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +
> +  Digests the given variable data and updates HMAC context.
> +
> +  @param[in]      Context   Pointer to initialized HMAC context.
> +  @param[in]      VarInfo   Pointer to variable data.
> +
> +  @retval TRUE    HMAC context was updated successfully.
> +  @retval FALSE   Failed to update HMAC context.
> +
> +**/
> +BOOLEAN
> +UpdateVariableMetadataHmac (
> +  IN  VOID                     *Context,
> +  IN  PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  return UpdateVariableDigestData (Context, VarInfo,
> (DIGEST_UPDATE)HmacSha256Update);
> +}
> +
> +/**
> +
> +  Get the variable digest.
> +
> +  @param[in]      Global        Pointer to global configuration data.
> +  @param[in]      VarInfo       Pointer to verified copy of protected variables.
> +  @param[in,out]  DigestValue   Pointer to variable digest value.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
> +  @retval EFI_ABORTED            An error was encountered.
> +  @retval EFI_COMPROMISED_DATA   The data was compromised.
> +  @retval EFI_SUCCESS            Variable digest was successfully verified.
> +
> +**/
> +EFI_STATUS
> +GetVariableDigest (
> +  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN      PROTECTED_VARIABLE_INFO    *VarInfo,
> +  IN  OUT UINT8                      *DigestValue
> +  )
> +{
> +  EFI_STATUS  Status;
> +  VOID        *Context;
> +
> +  if ((Global == NULL) || (VarInfo == NULL) || (DigestValue == NULL)) {
> +    ASSERT (Global != NULL);
> +    ASSERT (VarInfo != NULL);
> +    ASSERT (DigestValue != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Context = GET_BUFR (Global->DigestContext);
> +  if (!HashApiInit (Context)) {
> +    ASSERT (Context != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  if (VarInfo->CipherData == NULL) {
> +    VarInfo->CipherData     = VarInfo->Header.Data;
> +    VarInfo->CipherDataSize = (UINT32)VarInfo->Header.DataSize;
> +  }
> +
> +  if (  !UpdateVariableDigestData (Context, VarInfo,
> (DIGEST_UPDATE)HashApiUpdate)
> +     || !HashApiFinal (Context, DigestValue))
> +  {
> +    ASSERT (FALSE);
> +    Status = EFI_ABORTED;
> +  } else {
> +    Status = EFI_SUCCESS;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Verify the variable digest.
> +
> +  @param[in]  Global      Pointer to global configuration data.
> +  @param[in]  VarInfo     Pointer to verified copy of protected variables.
> +  @param[in]  VarDig      Pointer to variable digest data.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid parameter was passed in.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to calculate hash.
> +  @retval EFI_ABORTED            An error was encountered.
> +  @retval EFI_COMPROMISED_DATA   The data was compromised.
> +  @retval EFI_SUCCESS            Variable digest was successfully verified.
> +
> +**/
> +EFI_STATUS
> +VerifyVariableDigest (
> +  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  PROTECTED_VARIABLE_INFO    *VarInfo,
> +  IN  VARIABLE_DIGEST            *VarDig
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       NewDigest[METADATA_HMAC_SIZE];
> +
> +  if (Global->Flags.RecoveryMode || !VarDig->Flags.Protected) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  ASSERT (VarDig->DigestSize == sizeof (NewDigest));
> +
> +  Status = GetVariableDigest (Global, VarInfo, NewDigest);
> +  if (!EFI_ERROR (Status)) {
> +    if (CompareMem (VAR_DIG_VALUE (VarDig), NewDigest, VarDig-
> >DigestSize) != 0) {
> +      Status = EFI_COMPROMISED_DATA;
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Initialize variable MetaDataHmacVar.
> +
> +  @param[in,out]  Variable      Pointer to buffer of MetaDataHmacVar.
> +  @param[in]      AuthFlag      Variable format flag.
> +
> +**/
> +VOID
> +InitMetadataHmacVariable (
> +  IN  OUT VARIABLE_HEADER  *Variable,
> +  IN      BOOLEAN          AuthFlag
> +  )
> +{
> +  UINT8                          *NamePtr;
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +
> +  Variable->StartId    = VARIABLE_DATA;
> +  Variable->State      = VAR_ADDED;
> +  Variable->Reserved   = 0;
> +  Variable->Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT;
> +
> +  if (AuthFlag) {
> +    AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +
> +    AuthVariable->NameSize       = METADATA_HMAC_VARIABLE_NAME_SIZE;
> +    AuthVariable->DataSize       = METADATA_HMAC_SIZE;
> +    AuthVariable->PubKeyIndex    = 0;
> +    AuthVariable->MonotonicCount = 0;
> +
> +    ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
> +    CopyMem (&AuthVariable->VendorGuid,
> &METADATA_HMAC_VARIABLE_GUID, sizeof (EFI_GUID));
> +
> +    NamePtr = (UINT8 *)AuthVariable + sizeof
> (AUTHENTICATED_VARIABLE_HEADER);
> +  } else {
> +    Variable->NameSize = METADATA_HMAC_VARIABLE_NAME_SIZE;
> +    Variable->DataSize = METADATA_HMAC_SIZE;
> +
> +    CopyMem (&Variable->VendorGuid, &METADATA_HMAC_VARIABLE_GUID,
> sizeof (EFI_GUID));
> +
> +    NamePtr = (UINT8 *)Variable + sizeof (VARIABLE_HEADER);
> +  }
> +
> +  CopyMem (NamePtr, METADATA_HMAC_VARIABLE_NAME,
> METADATA_HMAC_VARIABLE_NAME_SIZE);
> +}
> +
> +/**
> +  Re-calculate HMAC based on new variable data and re-generate
> MetaDataHmacVar.
> +
> +  @param[in]      Global          Pointer to global configuration data.
> +  @param[in]      NewVarInfo      Pointer to buffer of new variable data.
> +  @param[in,out]  NewHmacVarInfo  Pointer to buffer of new
> MetaDataHmacVar.
> +
> +  @return EFI_SUCCESS           The HMAC value was updated successfully.
> +  @return EFI_ABORTED           Failed to calculate the HMAC value.
> +  @return EFI_OUT_OF_RESOURCES  Not enough resource to calculate HMC
> value.
> +  @return EFI_NOT_FOUND         The MetaDataHmacVar was not found in
> storage.
> +
> +**/
> +EFI_STATUS
> +RefreshVariableMetadataHmac (
> +  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN      PROTECTED_VARIABLE_INFO    *NewVarInfo,
> +  IN  OUT PROTECTED_VARIABLE_INFO    *NewHmacVarInfo
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  VOID                           *Context;
> +  UINT32                         Counter;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +  PROTECTED_VARIABLE_INFO        CurrHmacVarInfo;
> +  UINT8                          *HmacValue;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  VARIABLE_DIGEST                *VarDig;
> +  VARIABLE_DIGEST                *HmacVarDig;
> +
> +  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
> +  ZeroMem ((VOID *)&CurrHmacVarInfo, sizeof (CurrHmacVarInfo));
> +
> +  Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  Counter  += 1;
> +  ContextIn = GET_CNTX (Global);
> +
> +  //
> +  // Delete current MetaDataHmacVariable first, if any.
> +  //
> +  if (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID) {
> +    HmacVarDig = VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded]);
> +
> +    CurrHmacVarInfo.Header.NameSize     = HmacVarDig->NameSize;
> +    CurrHmacVarInfo.Header.VariableName = VAR_DIG_NAME (HmacVarDig);
> +    CurrHmacVarInfo.Header.VendorGuid   = VAR_DIG_GUID (HmacVarDig);
> +
> +    CurrHmacVarInfo.Buffer     = VAR_HDR_PTR (HmacVarDig->CacheIndex);
> +    CurrHmacVarInfo.StoreIndex = HmacVarDig->StoreIndex;
> +    CurrHmacVarInfo.Flags.Auth = HmacVarDig->Flags.Auth;
> +    //
> +    // Force marking current MetaDataHmacVariable as
> VAR_IN_DELETED_TRANSITION.
> +    //
> +    CurrHmacVarInfo.Buffer->State &= VAR_IN_DELETED_TRANSITION;
> +    HmacVarDig->State             &= VAR_IN_DELETED_TRANSITION;
> +    Status                         = ContextIn->UpdateVariableStore (
> +                                                  &CurrHmacVarInfo,
> +                                                  OFFSET_OF (VARIABLE_HEADER, State),
> +                                                  sizeof (CurrHmacVarInfo.Buffer->State),
> +                                                  &CurrHmacVarInfo.Buffer->State
> +                                                  );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return Status;
> +    }
> +  } else if (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID) {
> +    HmacVarDig = VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel]);
> +  } else {
> +    //
> +    // No MetaDataHmacVar. Allocate space to cache its value.
> +    //
> +    HmacVarDig = CreateVariableDigestNode (
> +                   METADATA_HMAC_VARIABLE_NAME,
> +                   &METADATA_HMAC_VARIABLE_GUID,
> +                   METADATA_HMAC_VARIABLE_NAME_SIZE,
> +                   METADATA_HMAC_SIZE,
> +                   Global->Flags.Auth,
> +                   Global
> +                   );
> +    if (HmacVarDig == NULL) {
> +      ASSERT (HmacVarDig != NULL);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    HmacVarDig->Flags.Protected = FALSE;
> +  }
> +
> +  if (HmacVarDig->CacheIndex == VAR_INDEX_INVALID) {
> +    HmacVarDig->CacheIndex = (GET_ADRS (Global)) + (Global->StructSize -
> GetMetaDataHmacVarSize (Global->Flags.Auth));
> +  }
> +
> +  //
> +  // Construct new MetaDataHmacVar.
> +  //
> +  if (NewHmacVarInfo == NULL) {
> +    NewHmacVarInfo         = &VarInfo;
> +    NewHmacVarInfo->Buffer = GET_BUFR (HmacVarDig->CacheIndex);
> +  }
> +
> +  InitMetadataHmacVariable (NewHmacVarInfo->Buffer, Global->Flags.Auth);
> +
> +  NewHmacVarInfo->StoreIndex = VAR_INDEX_INVALID;     // Skip calculating
> offset
> +  NewHmacVarInfo->Flags.Auth = Global->Flags.Auth;
> +  Status                     = ContextIn->GetVariableInfo (NewHmacVarInfo);
> +  ASSERT_EFI_ERROR (Status);
> +  HmacValue = NewHmacVarInfo->Header.Data;
> +
> +  //
> +  // Re-calculate HMAC for all valid variables
> +  //
> +  Context = HmacSha256New ();
> +  if (Context == NULL) {
> +    ASSERT (Context != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = EFI_ABORTED;
> +  if (!HmacSha256SetKey (
> +         Context,
> +         Global->MetaDataHmacKey,
> +         sizeof (Global->MetaDataHmacKey)
> +         ))
> +  {
> +    ASSERT (FALSE);
> +    goto Done;
> +  }
> +
> +  //
> +  // HMAC (|| hash(Var1) || hash(Var2) || ... || hash(VarN))
> +  //
> +  VarDig = VAR_DIG_PTR (Global->VariableDigests);
> +  while (VarDig != NULL) {
> +    if (VarDig->Flags.Valid && VarDig->Flags.Protected) {
> +      HmacSha256Update (Context, VAR_DIG_VALUE (VarDig), VarDig-
> >DigestSize);
> +    }
> +
> +    VarDig = VAR_DIG_NEXT (VarDig);
> +  }
> +
> +  //
> +  // HMAC (RpmcMonotonicCounter)
> +  //
> +  if (!HmacSha256Update (Context, &Counter, sizeof (Counter))) {
> +    ASSERT (FALSE);
> +    goto Done;
> +  }
> +
> +  if (!HmacSha256Final (Context, HmacValue)) {
> +    ASSERT (FALSE);
> +    goto Done;
> +  }
> +
> +  //
> +  // Update HMAC value in cache.
> +  //
> +  CopyMem (VAR_DIG_VALUE (HmacVarDig), HmacValue, HmacVarDig-
> >DataSize);
> +  if ((HmacVarDig->Prev == 0) && (HmacVarDig->Next == 0)) {
> +    InsertVariableDigestNode (Global, HmacVarDig, NULL);
> +  }
> +
> +  //
> +  // Just one MetaDataHmacVar is needed for normal operation.
> +  //
> +  Global->Unprotected[IndexHmacAdded] = VAR_DIG_ADR (HmacVarDig);
> +  Global->Unprotected[IndexHmacInDel] = VAR_INDEX_INVALID;
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +  if (Context != NULL) {
> +    HmacSha256Free (Context);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Check if a given variable is unprotected variable specified in advance
> +  and return its index ID.
> +
> +  @param[in] Global     Pointer to global configuration data.
> +  @param[in] VarInfo    Pointer to variable information data.
> +
> +  @retval IndexHmacInDel    Variable is MetaDataHmacVar in delete-transition
> state.
> +  @retval IndexHmacAdded    Variable is MetaDataHmacVar in valid state.
> +  @retval IndexErrorFlag    Variable is VarErrorLog.
> +  @retval Others            Variable is not any known unprotected variables.
> +
> +**/
> +UNPROTECTED_VARIABLE_INDEX
> +CheckKnownUnprotectedVariable (
> +  IN  PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  PROTECTED_VARIABLE_INFO    *VarInfo
> +  )
> +{
> +  UNPROTECTED_VARIABLE_INDEX  Index;
> +
> +  if ((VarInfo == NULL) || (  (VarInfo->StoreIndex == VAR_INDEX_INVALID)
> +                           && (  (VarInfo->Header.VariableName == NULL)
> +                              || (VarInfo->Header.VendorGuid == NULL))))
> +  {
> +    ASSERT (VarInfo != NULL);
> +    ASSERT (VarInfo->StoreIndex != VAR_INDEX_INVALID);
> +    ASSERT (VarInfo->Header.VariableName != NULL);
> +    ASSERT (VarInfo->Header.VendorGuid != NULL);
> +    return UnprotectedVarIndexMax;
> +  }
> +
> +  for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
> +    if (  (Global->Unprotected[Index] != VAR_INDEX_INVALID)
> +       && (VarInfo->StoreIndex != VAR_INDEX_INVALID))
> +    {
> +      if (VarInfo->StoreIndex == VAR_DIG_PTR (Global->Unprotected[Index])-
> >StoreIndex) {
> +        break;
> +      }
> +    } else if (IS_VARIABLE (
> +                 &VarInfo->Header,
> +                 mUnprotectedVariables[Index].VariableName,
> +                 mUnprotectedVariables[Index].VendorGuid
> +                 ) && (VarInfo->Header.State == mUnprotectedVariables[Index].State))
> +    {
> +      break;
> +    }
> +  }
> +
> +  return Index;
> +}
> +
> +/**
> +
> +  Compare variable name and Guid
> +
> +  @param[in]  Name1      Name of first variable.
> +  @param[in]  Name1Size  Size of first variable.
> +  @param[in]  Name2      Name of second variable.
> +  @param[in]  Name2Size  Size of second variable.
> +  @param[in]  Guid1      Guid for first variable.
> +  @param[in]  Guid2      Guid for second variable.
> +
> +  @retval 0         First name is identical to Second name.
> +  @return others    First name is not identical to Second name.
> +
> +**/
> +INTN
> +CompareVariableNameAndGuid (
> +  IN CONST CHAR16  *Name1,
> +  IN UINTN         Name1Size,
> +  IN CONST CHAR16  *Name2,
> +  IN UINTN         Name2Size,
> +  IN EFI_GUID      *Guid1,
> +  IN EFI_GUID      *Guid2
> +  )
> +{
> +  INTN  Result;
> +
> +  Result = StrnCmp (
> +             Name1,
> +             Name2,
> +             MIN (Name1Size, Name2Size) / sizeof (CHAR16)
> +             );
> +  if (Result == 0) {
> +    if (Name1Size != Name2Size) {
> +      //
> +      // Longer name is 'bigger' than shorter one.
> +      //
> +      Result = (INTN)Name1Size - (INTN)Name2Size;
> +    } else {
> +      //
> +      // The variable name is the same. Compare the GUID.
> +      //
> +      Result = CompareMem ((VOID *)Guid1, (VOID *)Guid2, sizeof (EFI_GUID));
> +    }
> +  }
> +
> +  return Result;
> +}
> +
> +/**
> +
> +  Compare variable digest.
> +
> +  @param[in]  Variable1     Pointer to first variable digest.
> +  @param[in]  Variable2     Pointer to second variable digest.
> +
> +  @retval 0         Variables are identical.
> +  @return others    Variables are not identical.
> +
> +**/
> +INTN
> +CompareVariableDigestInfo (
> +  IN  VARIABLE_DIGEST  *Variable1,
> +  IN  VARIABLE_DIGEST  *Variable2
> +  )
> +{
> +  return CompareVariableNameAndGuid (
> +           VAR_DIG_NAME (Variable1),
> +           Variable1->NameSize,
> +           VAR_DIG_NAME (Variable2),
> +           Variable2->NameSize,
> +           &Variable1->VendorGuid,
> +           &Variable2->VendorGuid
> +           );
> +}
> +
> +/**
> +
> +  Move a node backward in the order controlled by SortMethod.
> +
> +  @param[in,out]  Node          Pointer to node to be moved.
> +  @param[in]      SortMethod    Method used to compare node in list.
> +
> +**/
> +VOID
> +MoveNodeBackward (
> +  IN  OUT VARIABLE_DIGEST  *Node,
> +  IN      SORT_METHOD      SortMethod
> +  )
> +{
> +  VARIABLE_DIGEST  *Curr;
> +  VARIABLE_DIGEST  *Prev;
> +  INTN             Result;
> +
> +  Curr = Node;
> +  while (Curr != NULL) {
> +    Prev = VAR_DIG_PREV (Curr);
> +    if (Prev == NULL) {
> +      Result = -1;
> +    } else {
> +      Result = SortMethod (Prev, Node);
> +    }
> +
> +    //
> +    // 'Result > 0' means the 'Prev' is 'bigger' than 'Node'. Continue to check
> +    // previous node til a node 'smaller' than 'Node' found.
> +    //
> +    if (Result > 0) {
> +      Curr = Prev;
> +      continue;
> +    }
> +
> +    if (Curr != Node) {
> +      //
> +      // Remove Node first
> +      //
> +      if (VAR_DIG_PREV (Node) != NULL) {
> +        VAR_DIG_PREV (Node)->Next = Node->Next;
> +      }
> +
> +      if (VAR_DIG_NEXT (Node) != NULL) {
> +        VAR_DIG_NEXT (Node)->Prev = Node->Prev;
> +      }
> +
> +      //
> +      // Insert Node before Curr.
> +      //
> +      Node->Prev = Curr->Prev;
> +      Node->Next = VAR_DIG_ADR (Curr);
> +
> +      if (Curr->Prev != 0) {
> +        VAR_DIG_PREV (Curr)->Next = VAR_DIG_ADR (Node);
> +      }
> +
> +      Curr->Prev = VAR_DIG_ADR (Node);
> +    }
> +
> +    //
> +    // If there're two identical variables in storage, one of them must be
> +    // "in-delete-transition" state. Mark it as "deleted" anyway.
> +    //
> +    if (Result == 0) {
> +      if (Curr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
> +        Curr->State &= VAR_DELETED;
> +      }
> +
> +      if (Prev->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
> +        Prev->State &= VAR_DELETED;
> +      }
> +    }
> +
> +    break;
> +  }
> +}
> +
> +/**
> +
> +  Create variable digest node.
> +
> +  @param[in]  VariableName      Name of variable.
> +  @param[in]  VendorGuid        Guid of variable.
> +  @param[in]  NameSize          Size of variable name.
> +  @param[in]  DataSize          Size of variable data.
> +  @param[in]  AuthVar           Authenticated variable flag.
> +  @param[in]  Global            Pointer to global configuration data.
> +
> +  @retval Ptr   Pointer to variable digest
> +
> +**/
> +VARIABLE_DIGEST *
> +CreateVariableDigestNode (
> +  IN CHAR16                     *VariableName,
> +  IN EFI_GUID                   *VendorGuid,
> +  IN UINT16                     NameSize,
> +  IN UINT32                     DataSize,
> +  IN BOOLEAN                    AuthVar,
> +  IN PROTECTED_VARIABLE_GLOBAL  *Global
> +  )
> +{
> +  VARIABLE_DIGEST  *VarDig;
> +  VOID             *Buffer;
> +  UINTN            VarSize;
> +
> +  VarDig = (VARIABLE_DIGEST *)AllocateZeroPool (
> +                                sizeof (VARIABLE_DIGEST) + NameSize +
> METADATA_HMAC_SIZE
> +                                );
> +  if ((VarDig == NULL) || (Global == NULL)) {
> +    ASSERT (VarDig != NULL);
> +    ASSERT (Global != NULL);
> +    return NULL;
> +  }
> +
> +  VarDig->DataSize        = DataSize;
> +  VarDig->NameSize        = NameSize;
> +  VarDig->DigestSize      = METADATA_HMAC_SIZE;
> +  VarDig->State           = VAR_ADDED;
> +  VarDig->Attributes      = VARIABLE_ATTRIBUTE_NV_BS_RT;
> +  VarDig->Flags.Auth      = AuthVar;
> +  VarDig->Flags.Valid     = TRUE;
> +  VarDig->Flags.Freeable  = TRUE;
> +  VarDig->Flags.Protected = PcdGetBool (PcdProtectedVariableIntegrity);
> +  VarDig->Flags.Encrypted = PcdGetBool (PcdProtectedVariableConfidentiality);
> +  VarDig->StoreIndex      = VAR_INDEX_INVALID;
> +  VarDig->CacheIndex      = VAR_INDEX_INVALID;
> +
> +  if (Global->Flags.CacheReady == TRUE) {
> +    VarSize  =  VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
> +    VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
> +    VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
> +    VarSize  = HEADER_ALIGN (VarSize);
> +
> +    Buffer = AllocateZeroPool (VarSize);
> +    if (Buffer != NULL) {
> +      VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
> +    }
> +  }
> +
> +  CopyMem (VAR_DIG_NAME (VarDig), VariableName, NameSize);
> +  CopyMem (VAR_DIG_GUID (VarDig), VendorGuid, sizeof (EFI_GUID));
> +
> +  return VarDig;
> +}
> +
> +/**
> +
> +  Remove variable digest node.
> +
> +  @param[in,out]  Global        Pointer to global configuration data.
> +  @param[in,out]  VarDig        Pointer to variable digest value.
> +  @param[in]      FreeResource  Flag to indicate whether to free resource.
> +
> +**/
> +VOID
> +RemoveVariableDigestNode (
> +  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  OUT VARIABLE_DIGEST            *VarDig,
> +  IN      BOOLEAN                    FreeResource
> +  )
> +{
> +  VARIABLE_DIGEST  *Prev;
> +  VARIABLE_DIGEST  *Next;
> +
> +  Prev = VAR_DIG_PREV (VarDig);
> +  Next = VAR_DIG_NEXT (VarDig);
> +
> +  if (Global->VariableDigests == VAR_DIG_ADR (VarDig)) {
> +    Global->VariableDigests = VAR_DIG_ADR (Next);
> +  }
> +
> +  if (Prev != NULL) {
> +    Prev->Next = VAR_DIG_ADR (Next);
> +  }
> +
> +  if (Next != NULL) {
> +    Next->Prev = VAR_DIG_ADR (Prev);
> +  }
> +
> +  VarDig->Prev        = 0;
> +  VarDig->Next        = 0;
> +  VarDig->Flags.Valid = FALSE;
> +
> +  if (FreeResource && VarDig->Flags.Freeable) {
> +    if ((VarDig->CacheIndex != 0) && (VarDig->CacheIndex !=
> VAR_INDEX_INVALID)) {
> +      VarDig->CacheIndex = VAR_INDEX_INVALID;
> +    }
> +  }
> +}
> +
> +/**
> +
> +  Insert variable digest node.
> +
> +  @param[in,out]  Global        Pointer to global configuration data.
> +  @param[in]      VarDig        Pointer to variable digest value.
> +  @param[in]      SortMethod    Method for sorting.
> +
> +**/
> +VOID
> +InsertVariableDigestNode (
> +  IN  OUT PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN      VARIABLE_DIGEST            *VarDig,
> +  IN      SORT_METHOD                SortMethod
> +  )
> +{
> +  VARIABLE_DIGEST  *Curr;
> +  VARIABLE_DIGEST  *Prev;
> +  BOOLEAN          DoReplace;
> +  INTN             Result;
> +
> +  if (SortMethod == NULL) {
> +    SortMethod = CompareVariableDigestInfo;
> +  }
> +
> +  DoReplace = FALSE;
> +  Curr      = VAR_DIG_PTR (Global->VariableDigests);
> +  if (Curr == NULL) {
> +    //
> +    // First one.
> +    //
> +    VarDig->Prev            = 0;
> +    VarDig->Next            = 0;
> +    Global->VariableDigests = VAR_DIG_ADR (VarDig);
> +    return;
> +  }
> +
> +  while (Curr != NULL && Curr != VarDig) {
> +    Result = SortMethod (VarDig, Curr);
> +
> +    if (Result <= 0) {
> +      ASSERT (VarDig->StoreIndex != Curr->StoreIndex);
> +
> +      //
> +      // The same variable already in list?
> +      //
> +      if (Result == 0) {
> +        //
> +        // Keep only the same new one, unless states are different. In such
> +        // situation, the one with no VAR_ADDED will be deleted.
> +        //
> +        if (VarDig->State >= Curr->State) {
> +          DoReplace         = TRUE;
> +          Curr->Flags.Valid = FALSE;    // to-be-deleted
> +        } else {
> +          DoReplace           = FALSE;
> +          VarDig->Flags.Valid = FALSE;  // to-be-deleted
> +        }
> +      }
> +
> +      //
> +      // Put VarDig before Curr
> +      //
> +      VarDig->Next = VAR_DIG_ADR (Curr);
> +      VarDig->Prev = Curr->Prev;
> +
> +      if (VAR_DIG_PREV (Curr) != NULL) {
> +        VAR_DIG_PREV (Curr)->Next = VAR_DIG_ADR (VarDig);
> +      }
> +
> +      Curr->Prev = VAR_DIG_ADR (VarDig);
> +
> +      if (DoReplace) {
> +        RemoveVariableDigestNode (Global, Curr, TRUE);
> +      }
> +
> +      break;
> +    }
> +
> +    Prev = Curr;
> +    Curr = VAR_DIG_NEXT (Curr);
> +    if (Curr == NULL) {
> +      Prev->Next = VAR_DIG_ADR (VarDig);
> +
> +      VarDig->Prev = VAR_DIG_ADR (Prev);
> +      VarDig->Next = 0;
> +    }
> +  }
> +
> +  //
> +  // Update the head node if necessary.
> +  //
> +  if (VAR_DIG_PTR (VarDig->Prev) == NULL) {
> +    Global->VariableDigests = VAR_DIG_ADR (VarDig);
> +  }
> +}
> +
> +/**
> +
> +  Find the specified variable digest
> +
> +  @param[in]  Global        Pointer to global configuration data.
> +  @param[in]  VarInfo       Pointer to variable data.
> +  @param[in]  FindNext      Flag to continue looking for variable.
> +
> +**/
> +VARIABLE_DIGEST *
> +FindVariableInternal (
> +  IN PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN PROTECTED_VARIABLE_INFO    *VarInfo,
> +  IN BOOLEAN                    FindNext
> +  )
> +{
> +  VARIABLE_DIGEST  *VarDig;
> +  VARIABLE_DIGEST  *Found;
> +  VARIABLE_DIGEST  *FirstStoreIndexVar;
> +  BOOLEAN          ByIndex;
> +  INTN             FwdOrBwd;
> +
> +  //
> +  // If VarInfo->StoreIndex is valid, use it to find the variable. Otherwise,
> +  // use the variable name and guid instead, if given. If no clue at all, return
> +  // the variable with lowest StoreIndex.
> +  //
> +  if (  (VarInfo->StoreIndex != VAR_INDEX_INVALID)
> +     || (VarInfo->Header.VariableName == NULL)
> +     || (VarInfo->Header.VendorGuid == NULL))
> +  {
> +    ByIndex = TRUE;
> +  } else {
> +    ByIndex = FALSE;
> +  }
> +
> +  Found              = NULL;
> +  VarDig             = VAR_DIG_PTR (Global->VariableDigests);
> +  FirstStoreIndexVar = VarDig;
> +  FwdOrBwd           = 1;
> +
> +  //
> +  // Discover variable with first/smallest store index
> +  //
> +  while (VarDig != NULL) {
> +    if (VarDig->StoreIndex < FirstStoreIndexVar->StoreIndex) {
> +      FirstStoreIndexVar = VAR_DIG_PTR (VarDig);
> +    }
> +
> +    VarDig = VAR_DIG_NEXT (VarDig);
> +  }
> +
> +  //
> +  // Input variable is NULL than return first variable
> +  // with smallest store index from the variable digest list.
> +  //
> +  if (((VarInfo->Header.VariableName == NULL) ||
> +       (VarInfo->Header.VendorGuid == NULL)) &&
> +      (ByIndex == FALSE))
> +  {
> +    return FirstStoreIndexVar;
> +  }
> +
> +  //
> +  // Start with first entry
> +  //
> +  VarDig = VAR_DIG_PTR (Global->VariableDigests);
> +  while (VarDig != NULL) {
> +    if (ByIndex) {
> +      if (FindNext) {
> +        if (VarDig->StoreIndex == VarInfo->StoreIndex) {
> +          Found = VarDig = VAR_DIG_NEXT (VarDig);
> +          break;
> +        }
> +      } else if (VarDig->StoreIndex == VarInfo->StoreIndex) {
> +        Found = VarDig;
> +        break;
> +      }
> +    } else {
> +      //
> +      // Match given variable name and vendor guid.
> +      //
> +      if (IS_VARIABLE (&VarInfo->Header, VAR_DIG_NAME (VarDig),
> VAR_DIG_GUID (VarDig))) {
> +        Found = (FindNext) ? VAR_DIG_NEXT (VarDig) : VarDig;
> +        break;
> +      }
> +    }
> +
> +    VarDig = (FwdOrBwd > 0) ? VAR_DIG_NEXT (VarDig) : VAR_DIG_PREV
> (VarDig);
> +    if (VarDig == NULL) {
> +    }
> +  }
> +
> +  return Found;
> +}
> +
> +/**
> +
> +  Synchronize the RPMC counters
> +
> +  @param[in]  Global      Pointer to global configuration data.
> +  @param[in]  VarInfo     Pointer to variable data.
> +  @param[in]  FindNext    Flag to continue looking for variable.
> +
> +  @retval EFI_SUCCESS     Successfully sync RPMC counters.
> +  @return others          Failed to sync RPMC counters.
> +
> +**/
> +EFI_STATUS
> +SyncRpmcCounter (
> +  VOID
> +  )
> +{
> +  UINT32      Counter1;
> +  UINT32      Counter2;
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Sync RPMC1 & RPMC2.
> +  //
> +  Status = RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  while (Counter1 < Counter2) {
> +    Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return Status;
> +    }
> +
> +    ++Counter1;
> +  }
> +
> +  while (Counter2 < Counter1) {
> +    Status = IncrementMonotonicCounter (RPMC_COUNTER_2);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return Status;
> +    }
> +
> +    ++Counter2;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  An alternative version of ProtectedVariableLibGetData to get plain data from
> +  given variable, if encrypted.
> +
> +  @param[in]          Global        Pointer to global configuration data.
> +  @param[in,out]      VarInfo       Pointer to structure containing variable
> +                                    information. VarInfo->Header.Data must point
> +                                    to the original variable data.
> +
> +  @retval EFI_SUCCESS               Found the specified variable.
> +  @retval EFI_INVALID_PARAMETER     VarInfo is NULL or both VarInfo->Buffer
> and
> +                                    VarInfo->Offset are invalid.
> +  @retval EFI_NOT_FOUND             The specified variable could not be found.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +ProtectedVariableLibGetDataInternal (
> +  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  OUT PROTECTED_VARIABLE_INFO    *VarInfo
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  VOID                           *Buffer;
> +  UINTN                          BufferSize;
> +
> +  if ((Global == NULL) || (VarInfo == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ContextIn = GET_CNTX (Global);
> +
> +  //
> +  // Check if the data has been decrypted or not.
> +  //
> +  BufferSize              = VarInfo->PlainDataSize;
> +  VarInfo->CipherData     = NULL;
> +  VarInfo->CipherDataSize = 0;
> +  VarInfo->PlainData      = NULL;
> +  VarInfo->PlainDataSize  = 0;
> +  Status                  = GetCipherDataInfo (VarInfo);
> +
> +  if ((Status == EFI_UNSUPPORTED) || (Status == EFI_NOT_FOUND)) {
> +    VarInfo->Flags.DecryptInPlace = TRUE;
> +    VarInfo->PlainDataSize        = (UINT32)VarInfo->Header.DataSize;
> +    VarInfo->PlainData            = VarInfo->Header.Data;
> +    VarInfo->CipherDataType       = 0;
> +    VarInfo->CipherHeaderSize     = 0;
> +    Status                        = EFI_SUCCESS;
> +  } else if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  //
> +  // Don't do decryption if the caller provided buffer is too small
> +  // Simply return the real Plain Data Size via VarInfo->PlainDataSize
> +  //
> +  if (BufferSize < VarInfo->PlainDataSize) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  //
> +  // If the variable data is cipher data, decrypt it inplace if possible.
> +  //
> +  if ((VarInfo->PlainData == NULL) && (VarInfo->CipherData != NULL)) {
> +    VarInfo->Key     = Global->RootKey;
> +    VarInfo->KeySize = sizeof (Global->RootKey);
> +
> +    switch (ContextIn->VariableServiceUser) {
> +      case FromPeiModule:
> +        VarInfo->Flags.DecryptInPlace = FALSE;
> +        //
> +        // In PEI VariableCache holds Cipher header + Cipher data
> +        // Do not override Cipher header data during decrypt operation
> +        //
> +        VarInfo->PlainData = GET_BUFR (Global->VariableCache + VarInfo-
> >CipherHeaderSize);
> +
> +        Status = DecryptVariable (VarInfo);
> +        if (Status == EFI_UNSUPPORTED) {
> +          VarInfo->PlainData        = VarInfo->Header.Data;
> +          VarInfo->PlainDataSize    = (UINT32)VarInfo->Header.DataSize;
> +          VarInfo->CipherDataType   = 0;
> +          VarInfo->CipherHeaderSize = 0;
> +
> +          Status = EFI_SUCCESS;
> +        }
> +
> +        break;
> +
> +      case FromSmmModule:
> +        VarInfo->Flags.DecryptInPlace = FALSE;
> +        VarInfo->PlainData            = GET_BUFR (Global->VariableCache);
> +
> +        Status = DecryptVariable (VarInfo);
> +        if (Status == EFI_UNSUPPORTED) {
> +          VarInfo->PlainData        = VarInfo->Header.Data;
> +          VarInfo->PlainDataSize    = (UINT32)VarInfo->Header.DataSize;
> +          VarInfo->CipherDataType   = 0;
> +          VarInfo->CipherHeaderSize = 0;
> +
> +          Status = EFI_SUCCESS;
> +        }
> +
> +        break;
> +
> +      case FromBootServiceModule:
> +      case FromRuntimeModule:
> +        //
> +        // The SMM passes back only decrypted data. We re-use the original cipher
> +        // data buffer to keep the plain data along with the cipher header.
> +        //
> +        VarInfo->Flags.DecryptInPlace = TRUE;
> +        Buffer                        = (VOID *)((UINTN)VarInfo->CipherData + VarInfo-
> >CipherHeaderSize);
> +        BufferSize                    = VarInfo->PlainDataSize;
> +        Status                        = ContextIn->FindVariableSmm (
> +                                                     VarInfo->Header.VariableName,
> +                                                     VarInfo->Header.VendorGuid,
> +                                                     &VarInfo->Header.Attributes,
> +                                                     &BufferSize,
> +                                                     Buffer
> +                                                     );
> +        if (!EFI_ERROR (Status)) {
> +          //
> +          // Flag the payload as plain data to avoid re-decrypting.
> +          //
> +          VarInfo->CipherDataType = ENC_TYPE_NULL;
> +          VarInfo->PlainDataSize  = (UINT32)BufferSize;
> +          VarInfo->PlainData      = Buffer;
> +
> +          Status = SetCipherDataInfo (VarInfo);
> +          if (Status == EFI_UNSUPPORTED) {
> +            Status = EFI_SUCCESS;
> +          }
> +        }
> +
> +        break;
> +
> +      default:
> +        Status = EFI_UNSUPPORTED;
> +        break;
> +    }
> +
> +    VarInfo->CipherData     = NULL;
> +    VarInfo->CipherDataSize = 0;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  An alternative version of ProtectedVariableLibGetData to get plain data, if
> +  encrypted, from given variable, for different use cases.
> +
> +  @param[in,out]      VarInfo     Pointer to structure containing variable
> information.
> +
> +  @retval EFI_SUCCESS               Found the specified variable.
> +  @retval EFI_INVALID_PARAMETER     VarInfo is NULL or both VarInfo->Buffer
> and
> +                                    VarInfo->Offset are invalid.
> +  @retval EFI_NOT_FOUND             The specified variable could not be found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByInfo (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VOID                       **Buffer;
> +  UINT32                     BufferSize;
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  //
> +  // Save the output data buffer because below call
> +  // call will use this struct field internally.

[JianJW] "call" here is duplicated

> +  //
> +  Buffer     = VarInfo->PlainData;
> +  BufferSize = VarInfo->PlainDataSize;
> +
> +  Status = ProtectedVariableLibGetDataInternal (Global, VarInfo);
> +  if (EFI_ERROR (Status) || ((BufferSize) < VarInfo->PlainDataSize)) {
> +    //
> +    // Return with caller provided buffer with zero DataSize
> +    //
> +    VarInfo->PlainData = Buffer;
> +    return Status;
> +  }
> +
> +  //
> +  // Copy Plain data to ouput data buffer

[JianJW] typo: "ouput" -> "output", "Plain" -> "plain"

> +  //
> +  CopyMem (Buffer, VarInfo->PlainData, VarInfo->PlainDataSize);
> +  VarInfo->PlainData = Buffer;
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Retrieve plain data, if encrypted, of given variable.
> +
> +  If variable encryption is employed, this function will initiate a SMM request
> +  to get the plain data. Due to security consideration, the decryption can only
> +  be done in SMM environment.
> +
> +  @param[in]      Variable           Pointer to header of a Variable.
> +  @param[in,out]  Data               Pointer to plain data of the given variable.
> +  @param[in,out]  DataSize           Size of data returned or data buffer needed.
> +  @param[in]      AuthFlag           Auth-variable indicator.
> +
> +  @retval EFI_SUCCESS                Found the specified variable.
> +  @retval EFI_INVALID_PARAMETER      Invalid parameter.
> +  @retval EFI_NOT_FOUND              The specified variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL       If *DataSize is smaller than needed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByBuffer (
> +  IN      VARIABLE_HEADER  *Variable,
> +  IN  OUT VOID             *Data,
> +  IN  OUT UINT32           *DataSize,
> +  IN      BOOLEAN          AuthFlag
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  AUTHENTICATED_VARIABLE_HEADER  *AuthVariable;
> +  VOID                           *Buffer;
> +
> +  if ((Variable == NULL) || (DataSize == NULL)) {
> +    ASSERT (Variable != NULL);
> +    ASSERT (DataSize != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  ZeroMem (&VarInfo, sizeof (VarInfo));
> +
> +  VarInfo.Buffer        = Variable;
> +  VarInfo.Flags.Auth    = AuthFlag;
> +  VarInfo.PlainDataSize = *DataSize;
> +
> +  if (VarInfo.Flags.Auth == TRUE) {
> +    AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;
> +
> +    VarInfo.Header.VariableName = (CHAR16 *)((UINTN)Variable + sizeof
> (AUTHENTICATED_VARIABLE_HEADER));
> +    VarInfo.Header.NameSize     = AuthVariable->NameSize;
> +    VarInfo.Header.VendorGuid   = &AuthVariable->VendorGuid;
> +    VarInfo.Header.Attributes   = AuthVariable->Attributes;
> +    VarInfo.Header.DataSize     = AuthVariable->DataSize;
> +  } else {
> +    VarInfo.Header.VariableName = (CHAR16 *)((UINTN)Variable + sizeof
> (VARIABLE_HEADER));
> +    VarInfo.Header.NameSize     = Variable->NameSize;
> +    VarInfo.Header.VendorGuid   = &Variable->VendorGuid;
> +    VarInfo.Header.Attributes   = Variable->Attributes;
> +    VarInfo.Header.DataSize     = Variable->DataSize;
> +  }
> +
> +  Buffer              = VARIABLE_NAME (VarInfo.Buffer, VarInfo.Flags.Auth);
> +  Buffer              = GET_BUFR (GET_ADRS (Buffer) + VarInfo.Header.NameSize);
> +  Buffer              = GET_BUFR (GET_ADRS (Buffer) + GET_PAD_SIZE
> (VarInfo.Header.NameSize));
> +  VarInfo.Header.Data = Buffer;
> +
> +  Status    = ProtectedVariableLibGetDataInternal (Global, &VarInfo);
> +  *DataSize = VarInfo.PlainDataSize;
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize);
> +
> +  return Status;
> +}
> +
> +/**
> +  This service retrieves a variable's value using its name and GUID.
> +
> +  Read the specified variable from the UEFI variable store. If the Data
> +  buffer is too small to hold the contents of the variable, the error
> +  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
> +  size to obtain the data.
> +
> +  @param  VariableName          A pointer to a null-terminated string that is the
> variable's name.
> +  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's
> GUID. The combination of
> +                                VariableGuid and VariableName must be unique.
> +  @param  Attributes            If non-NULL, on return, points to the variable's
> attributes.
> +  @param  DataSize              On entry, points to the size in bytes of the Data
> buffer.
> +                                On return, points to the size of the data returned in Data.
> +  @param  Data                  Points to the buffer which will hold the returned
> variable value.
> +                                May be NULL with a zero DataSize in order to determine the
> size of the buffer needed.

[JianJW] missing [in/out] for parameters

> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable was be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting
> data.
> +                                DataSize is updated with the size required for
> +                                the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or
> Data is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetByName (
> +  IN      CONST  CHAR16    *VariableName,
> +  IN      CONST  EFI_GUID  *VariableGuid,
> +  OUT UINT32               *Attributes,
> +  IN  OUT UINTN            *DataSize,
> +  OUT VOID                 *Data OPTIONAL
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  VARIABLE_DIGEST                *VarDig;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +  EFI_TIME                       TimeStamp;
> +  VOID                           *DataBuffer;
> +
> +  if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {
> +    ASSERT (VariableName != NULL);
> +    ASSERT (VariableGuid != NULL);
> +    ASSERT (DataSize != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  ContextIn = GET_CNTX (Global);
> +
> +  ZeroMem (&VarInfo, sizeof (VarInfo));
> +  VarInfo.StoreIndex          = VAR_INDEX_INVALID;
> +  VarInfo.Header.VariableName = (CHAR16 *)VariableName;
> +  VarInfo.Header.NameSize     = StrSize (VariableName);
> +  VarInfo.Header.VendorGuid   = (EFI_GUID *)VariableGuid;
> +
> +  VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
> +  if (VarDig == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (Attributes != NULL) {
> +    *Attributes = VarDig->Attributes;
> +  }
> +
> +  if ((Data == NULL) || (*DataSize < VarDig->PlainDataSize)) {
> +    *DataSize = VarDig->PlainDataSize;
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  VarInfo.Flags.Auth      = VarDig->Flags.Auth;
> +  VarInfo.Flags.Protected = VarDig->Flags.Protected;
> +
> +  //
> +  // Verify digest before copy the data back, if the variable is not in cache.
> +  //
> +  if (VarDig->CacheIndex != VAR_INDEX_INVALID) {
> +    VarInfo.Header.VariableName = NULL;
> +    VarInfo.Header.VendorGuid   = NULL;
> +    VarInfo.Buffer              = GET_BUFR (VarDig->CacheIndex);
> +
> +    Status = ContextIn->GetVariableInfo (&VarInfo);
> +    ASSERT_EFI_ERROR (Status);
> +  } else {
> +    //
> +    // A buffer for at least one variable data (<=PcdMax(Auth)VariableSize)
> +    // must be reserved in advance.
> +    //
> +    ASSERT (
> +      Global->VariableCache != 0
> +           && Global->VariableCacheSize >= VarDig->DataSize
> +      );
> +    DataBuffer = GET_BUFR (Global->VariableCache);
> +    //
> +    // Note name and GUID are already there.
> +    //
> +    VarInfo.StoreIndex = VarDig->StoreIndex;
> +
> +    VarInfo.Header.VariableName = NULL; // Prevent name from being retrieved
> again.
> +    VarInfo.Header.NameSize     = 0;
> +    VarInfo.Header.VendorGuid   = NULL; // Prevent guid from being retrieved
> again.
> +    VarInfo.Header.TimeStamp    = &TimeStamp;
> +    VarInfo.Header.Data         = DataBuffer;
> +    VarInfo.Header.DataSize     = VarDig->DataSize;
> +
> +    //
> +    // Get detailed information about the variable.
> +    //
> +    Status = ContextIn->GetVariableInfo (&VarInfo);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    //
> +    // The variable must be validated its digest value to avoid TOCTOU, if it's
> +    // not been cached yet.
> +    //
> +    VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
> +    VarInfo.Header.NameSize     = VarDig->NameSize;
> +    VarInfo.Header.VendorGuid   = &VarDig->VendorGuid;
> +    Status                      = VerifyVariableDigest (Global, &VarInfo, VarDig);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
> +  VarInfo.PlainDataSize = (UINT32)*DataSize;
> +
> +  //
> +  // Decrypt the data, if necessary.
> +  //
> +  Status    = ProtectedVariableLibGetDataInternal (Global, &VarInfo);
> +  *DataSize = VarInfo.PlainDataSize;
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "%a: %d Exit(). VariableName = %s, VariableGuid = 0x%g, DataSize = 0x%X,
> Data Buffer = 0x%lX, Status = %r\n",
> +      __FUNCTION__,
> +      __LINE__,
> +      VariableName,
> +      VariableGuid,
> +      *DataSize,
> +      Data,
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize);
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  This function is used to enumerate the variables managed by current
> +  ProtectedVariableLib.
> +
> +  If the VarInfo->StoreIndex is invalid (VAR_INDEX_INVALID), the first variable
> +  with the smallest StoreIndex will be returned. Otherwise, the variable with
> +  StoreIndex just after than the VarInfo->StoreIndex will be returned.
> +
> +  @param[in,out]      VarInfo     Pointer to structure containing variable
> information.
> +
> +  @retval EFI_SUCCESS               Found the specified variable.
> +  @retval EFI_INVALID_PARAMETER     VarInfo is NULL.
> +  @retval EFI_NOT_FOUND             The specified variable could not be found.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GetNextVariableInternal (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VARIABLE_DIGEST            *Found;
> +
> +  if (VarInfo == NULL) {
> +    ASSERT (VarInfo != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  Found = FindVariableInternal (Global, VarInfo, TRUE);
> +  if (Found == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Return all cached data.
> +  //
> +  VarInfo->Header.VariableName = VAR_DIG_NAME (Found);
> +  VarInfo->Header.VendorGuid   = VAR_DIG_GUID (Found);
> +  VarInfo->Header.NameSize     = Found->NameSize;
> +  VarInfo->Header.DataSize     = Found->DataSize;
> +  VarInfo->Header.Attributes   = Found->Attributes;
> +
> +  VarInfo->PlainDataSize = Found->PlainDataSize;
> +  VarInfo->StoreIndex    = Found->StoreIndex;
> +  if (Found->CacheIndex != VAR_INDEX_INVALID) {
> +    VarInfo->Buffer = GET_BUFR (Found->CacheIndex);
> +  }
> +
> +  VarInfo->Flags.Auth = Found->Flags.Auth;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Find the request variable.
> +
> +  @param[in, out]  VarInfo      Pointer to variable data.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_INVALID_PARAMETER Variable info is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFind (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VARIABLE_DIGEST            *Found;
> +
> +  if (VarInfo == NULL) {
> +    ASSERT (VarInfo != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  Found = FindVariableInternal (Global, VarInfo, FALSE);
> +  if (Found == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Return all cached data.
> +  //
> +  VarInfo->Header.VariableName = VAR_DIG_NAME (Found);
> +  VarInfo->Header.VendorGuid   = VAR_DIG_GUID (Found);
> +  VarInfo->Header.NameSize     = Found->NameSize;
> +  VarInfo->Header.DataSize     = Found->DataSize;
> +  VarInfo->Header.Attributes   = Found->Attributes;
> +
> +  VarInfo->PlainDataSize = Found->PlainDataSize;
> +  VarInfo->StoreIndex    = Found->StoreIndex;
> +  if (Found->CacheIndex != VAR_INDEX_INVALID) {
> +    VarInfo->Buffer = GET_BUFR (Found->CacheIndex);
> +  }
> +
> +  VarInfo->Flags.Auth = Found->Flags.Auth;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Return the next variable name and GUID.
> +
> +  This function is called multiple times to retrieve the VariableName
> +  and VariableGuid of all variables currently available in the system.
> +  On each call, the previous results are passed into the interface,
> +  and, on return, the interface returns the data for the next
> +  interface. When the entire variable list has been returned,
> +  EFI_NOT_FOUND is returned.
> +
> +  @param  VariableNameSize  On entry, points to the size of the buffer pointed
> to by VariableName.
> +                            On return, the size of the variable name buffer.
> +  @param  VariableName      On entry, a pointer to a null-terminated string that
> is the variable's name.
> +                            On return, points to the next variable's null-terminated name
> string.
> +  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the
> variable's GUID.
> +                            On return, a pointer to the next variable's GUID.
> +
> +  @retval EFI_SUCCESS           The variable was read successfully.
> +  @retval EFI_NOT_FOUND         The variable could not be found.
> +  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the
> resulting
> +                                data. VariableNameSize is updated with the size
> +                                required for the specified variable.
> +  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
> +                                VariableNameSize is NULL.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of
> a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNext (
> +  IN OUT UINTN     *VariableNameSize,
> +  IN OUT CHAR16    *VariableName,
> +  IN OUT EFI_GUID  *VariableGuid
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  PROTECTED_VARIABLE_INFO    VarInfo;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VARIABLE_DIGEST            *VarDig;
> +  UINTN                      Size;
> +
> +  if ((VariableNameSize == NULL) || (VariableName == NULL) || (VariableGuid
> == NULL)) {
> +    ASSERT (VariableNameSize != NULL);
> +    ASSERT (VariableName != NULL);
> +    ASSERT (VariableGuid != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  SetMem (&VarInfo, sizeof (VarInfo), 0);
> +  Size = StrSize (VariableName);
> +
> +  if (Size <= 2) {
> +    VarDig = VAR_DIG_PTR (Global->VariableDigests);
> +  } else {
> +    VarInfo.Header.VariableName = VariableName;
> +    VarInfo.Header.NameSize     = Size;
> +    VarInfo.Header.VendorGuid   = VariableGuid;
> +
> +    VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +
> +    VarDig = FindVariableInternal (Global, &VarInfo, TRUE);
> +  }
> +
> +  if (VarDig == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (VarDig->NameSize > *VariableNameSize) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  CopyMem (VariableName, VAR_DIG_NAME (VarDig), VarDig->NameSize);
> +  CopyGuid (VariableGuid, &VarDig->VendorGuid);
> +  *VariableNameSize = VarInfo.Header.NameSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Return the next variable name and GUID.
> +
> +  @param[in, out]  VarInfo        Pointer to variable data.
> +
> +  @retval EFI_SUCCESS             The variable was read successfully.
> +  @retval EFI_INVALID_PARAMETER   VarInfo is NULL.
> +  @retval EFI_NOT_FOUND           The specified variable could not be found.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibFindNextEx (
> +  IN  OUT PROTECTED_VARIABLE_INFO  *VarInfo
> +  )
> +{
> +  return GetNextVariableInternal (VarInfo);
> +}
> +
> +/**
> +
> +  Return the max count of a variable.
> +
> +  @return   max count of a variable.
> +
> +**/
> +UINTN
> +ProtectedVariableLibGetMaxVariablesCount (
> +  VOID
> +  )
> +{
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  PROTECTED_VARIABLE_INFO    VarInfo;
> +  VARIABLE_DIGEST            *VarDig;
> +  EFI_STATUS                 Status;
> +  UINTN                      Count;
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return 0;
> +  }
> +
> +  Count = 0;
> +  ZeroMem (&VarInfo, sizeof (VarInfo));
> +
> +  //
> +  // Start with first entry
> +  //
> +  VarDig                      = VAR_DIG_PTR (Global->VariableDigests);
> +  VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
> +  VarInfo.Header.VendorGuid   = VAR_DIG_GUID (VarDig);
> +  VarInfo.StoreIndex          = VarDig->StoreIndex;
> +
> +  do {
> +    VarInfo.Buffer = NULL;
> +    Status         = ProtectedVariableLibFindNextEx (&VarInfo);
> +    if (EFI_ERROR (Status)) {
> +      return Count;
> +    }
> +
> +    Count++;
> +  } while (TRUE);
> +}
> +
> +/**
> +  The function is called by PerformQuickSort to sort.
> +
> +  @param[in] Left            The pointer to first buffer.
> +  @param[in] Right           The pointer to second buffer.
> +
> +  @retval 0                  Buffer1 equal to Buffer2.
> +  @return < 0                Buffer1 is less than Buffer2.
> +  @return > 0                Buffer1 is greater than Buffer2.
> +
> +**/
> +INTN
> +EFIAPI
> +CompareStoreIndex (
> +  IN CONST VOID  *Left,
> +  IN CONST VOID  *Right
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  StoreIndex1;
> +  EFI_PHYSICAL_ADDRESS  StoreIndex2;
> +
> +  StoreIndex1 = (*(EFI_PHYSICAL_ADDRESS *)Left);
> +  StoreIndex2 = (*(EFI_PHYSICAL_ADDRESS *)Right);
> +
> +  if (StoreIndex1 == StoreIndex2) {
> +    return (0);
> +  }
> +
> +  if (StoreIndex1 < StoreIndex2) {
> +    return (-1);
> +  }
> +
> +  return (1);
> +}
> +
> +/**
> +  Refresh variable information changed by variable service.
> +
> +  @param Buffer           Pointer to a pointer of buffer.
> +  @param NumElements      Pointer to number of elements in list.
> +
> +
> +  @return EFI_SUCCESS     Successfully retrieved sorted list.
> +  @return others          Unsuccessful.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibGetSortedList (
> +  IN  OUT  EFI_PHYSICAL_ADDRESS  **Buffer,
> +  IN  OUT  UINTN                 *NumElements
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  UINTN                      Count;
> +  UINTN                      StoreIndexTableSize;
> +  EFI_PHYSICAL_ADDRESS       *StoreIndexTable;
> +  PROTECTED_VARIABLE_INFO    VarInfo;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VARIABLE_DIGEST            *VarDig;
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  Count = 0;
> +  ZeroMem (&VarInfo, sizeof (VarInfo));
> +  StoreIndexTableSize = ProtectedVariableLibGetMaxVariablesCount ();
> +  StoreIndexTable     = AllocateZeroPool (sizeof (EFI_PHYSICAL_ADDRESS) *
> StoreIndexTableSize);
> +
> +  //
> +  // Start with first entry
> +  //
> +  VarDig                      = VAR_DIG_PTR (Global->VariableDigests);
> +  VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
> +  VarInfo.Header.VendorGuid   = VAR_DIG_GUID (VarDig);
> +  VarInfo.StoreIndex          = VarDig->StoreIndex;
> +  StoreIndexTable[Count]      = VarInfo.StoreIndex;
> +  Count++;
> +
> +  //
> +  // Populate the un-sorted table
> +  //
> +  do {
> +    VarInfo.Buffer = NULL;
> +    Status         = ProtectedVariableLibFindNextEx (&VarInfo);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    StoreIndexTable[Count] = VarInfo.StoreIndex;
> +    Count++;
> +  } while (TRUE);
> +
> +  PerformQuickSort (
> +    StoreIndexTable,
> +    Count,
> +    sizeof (EFI_PHYSICAL_ADDRESS),
> +    (SORT_COMPARE)CompareStoreIndex
> +    );
> +
> +  *Buffer      = StoreIndexTable;
> +  *NumElements = Count;
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> new file mode 100644
> index 000000000000..94df21eacf25
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> @@ -0,0 +1,163 @@
> +/** @file
> +  Implemention of ProtectedVariableLib for SMM variable services.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Uefi.h>
> +
> +#include "Library/UefiBootServicesTableLib.h"
> +#include "Library/MemoryAllocationLib.h"
> +
> +#include "ProtectedVariableInternal.h"
> +
> +PROTECTED_VARIABLE_CONTEXT_IN  mVariableContextIn = {
> +  PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
> +  sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
> +  0,
> +  FromSmmModule,
> +  NULL,
> +  NULL,
> +  NULL,
> +  NULL,
> +  NULL
> +};
> +
> +PROTECTED_VARIABLE_GLOBAL  mProtectedVariableGlobal = {
> +  PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
> +  sizeof (PROTECTED_VARIABLE_GLOBAL),
> +  { 0 },
> +  { 0 },
> +  0,
> +  0,
> +  0,
> +  0,
> +  0,
> +  0,
> +  { 0,                                          0,  0 },
> +  0,
> +  0,
> +  { 0,                                          0,  0, 0, 0, 0}
> +};
> +
> +/**
> +  Fix incorrect state of MetaDataHmacVariable before any variable update.
> +
> +  @param[in]   Event    The event that occurred
> +  @param[in]   Context  For EFI compatibility.  Not used.
> +
> +**/
> +VOID
> +EFIAPI
> +VariableWriteProtocolCallback (
> +  IN  EFI_EVENT  Event,
> +  IN  VOID       *Context
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Fix incorrect state of MetaDataHmacVariable before any variable update.
> +  // This has to be done here due to the fact that this operation needs to
> +  // update NV storage but the FVB and FTW protocol might not be ready during
> +  // ProtectedVariableLibInitialize().
> +  //
> +  Status = FixupHmacVariable ();
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = ProtectedVariableLibWriteInit ();
> +  ASSERT_EFI_ERROR (Status);
> +
> +  gBS->CloseEvent (Event);
> +}
> +
> +/**
> +
> +  Initialization for protected variable services.
> +
> +  If this initialization failed upon any error, the whole variable services
> +  should not be used.  A system reset might be needed to re-construct NV
> +  variable storage to be the default state.
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected
> variables.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ProtectedVarContext;
> +  PROTECTED_VARIABLE_GLOBAL      *OldGlobal;
> +  PROTECTED_VARIABLE_GLOBAL      *NewGlobal;
> +  VOID                           *VarWriteReg;
> +
> +  if (  (ContextIn == NULL)
> +     || (ContextIn->StructVersion !=
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
> +     || (ContextIn->StructSize != sizeof (PROTECTED_VARIABLE_CONTEXT_IN))
> +     || (ContextIn->GetVariableInfo == NULL)
> +     || (ContextIn->GetNextVariableInfo == NULL)
> +     || (ContextIn->UpdateVariableStore == NULL)
> +     || (ContextIn->UpdateVariable == NULL))
> +  {
> +    ASSERT (ContextIn != NULL);
> +    ASSERT (ContextIn->StructVersion ==
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION);
> +    ASSERT (ContextIn->StructSize == sizeof
> (PROTECTED_VARIABLE_CONTEXT_IN));
> +    ASSERT (ContextIn->GetVariableInfo != NULL);
> +    ASSERT (ContextIn->GetNextVariableInfo != NULL);
> +    ASSERT (ContextIn->UpdateVariableStore != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  GetProtectedVariableGlobal (&NewGlobal);
> +  ProtectedVarContext = GET_CNTX (NewGlobal);
> +  CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn));
> +  ProtectedVarContext->VariableServiceUser = FromSmmModule;
> +
> +  //
> +  // Get root key and HMAC key from HOB created by PEI variable driver.
> +  //
> +  Status = GetProtectedVariableGlobalFromHob (&OldGlobal);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof
> (*OldGlobal));
> +
> +  //
> +  // The keys must not be available outside SMM.
> +  //
> +  if (ProtectedVarContext->VariableServiceUser == FromSmmModule) {
> +    ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey));
> +    ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal-
> >MetaDataHmacKey));
> +  }
> +
> +  //
> +  // Register variable write protocol notify function used to fix any
> +  // inconsistency in MetaDataHmacVariable before the first variable write
> +  // operation.
> +  //
> +  NewGlobal->Flags.WriteInit  = FALSE;
> +  NewGlobal->Flags.WriteReady = FALSE;
> +
> +  EfiCreateProtocolNotifyEvent (
> +    &gEfiVariableWriteArchProtocolGuid,
> +    TPL_CALLBACK,
> +    VariableWriteProtocolCallback,
> +    NULL,
> +    &VarWriteReg
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> new file mode 100644
> index 000000000000..8b5ccb83e32d
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> @@ -0,0 +1,1327 @@
> +/** @file
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Uefi.h>
> +#include <PiPei.h>
> +
> +#include <Guid/VariableFormat.h>
> +#include <Ppi/MemoryDiscovered.h>
> +
> +#include <Library/HobLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +
> +#include "ProtectedVariableInternal.h"
> +
> +/**
> +  Function allocates a global buffer.
> +
> +  This function allocates a buffer with the specified size.
> +
> +  @param[in] Size           Size of buffer to allocate.
> +  @param[in] AllocatePage   Whether to allocate pages.
> +
> +  @retval Buffer             Pointer to the Buffer allocated.
> +  @retval NULL               if no Buffer was found.
> +
> +**/
> +VOID *
> +AllocateGlobalBuffer (
> +  IN UINT32   Size,
> +  IN BOOLEAN  AllocatePage
> +  )
> +{
> +  VOID                       *Buffer;
> +  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;
> +  EFI_PEI_HOB_POINTERS       Hob;
> +
> +  Buffer = NULL;
> +  if (!AllocatePage) {
> +    Buffer = BuildGuidHob (&gEdkiiProtectedVariableGlobalGuid, Size);
> +  }
> +
> +  if (Buffer == NULL) {
> +    //
> +    // Use the AllocatePages() to get over size limit of general GUID-ed HOB.
> +    //
> +    Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));
> +    if (Buffer == NULL) {
> +      ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
> +      return NULL;
> +    }
> +
> +    //
> +    // Mark the HOB holding the pages just allocated so that it can be
> +    // identified later.
> +    //
> +    MemoryAllocationHob = NULL;
> +    Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
> +    while (Hob.Raw != NULL) {
> +      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
> +      if ((UINTN)Buffer == (UINTN)MemoryAllocationHob-
> >AllocDescriptor.MemoryBaseAddress) {
> +        CopyGuid (
> +          &MemoryAllocationHob->AllocDescriptor.Name,
> +          &gEdkiiProtectedVariableGlobalGuid
> +          );
> +        break;
> +      }
> +
> +      Hob.Raw = GET_NEXT_HOB (Hob);
> +      Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION,
> Hob.Raw);
> +    }
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Callback use to re-verify all variables and cache them in memory.
> +
> +  @param[in] PeiServices          General purpose services available to every PEIM.
> +  @param[in] NotifyDescriptor     The notification structure this PEIM registered
> on install.
> +  @param[in] Ppi                  The memory discovered PPI.  Not used.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval others                  There's error in MP initialization.
> +**/
> +EFI_STATUS
> +EFIAPI
> +MemoryDiscoveredPpiNotifyCallback (
> +  IN EFI_PEI_SERVICES           **PeiServices,
> +  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> +  IN VOID                       *Ppi
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  VARIABLE_DIGEST                *VarDig;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +  VOID                           *Buffer;
> +  UINT32                         VarSize;
> +  INTN                           Result;
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  ContextIn = GET_CNTX (Global);
> +
> +  //
> +  // Allocate last Var buffer for confidentiality crypto operation
> +  //
> +  VarSize = (Global->VariableNumber + 1) * MAX_VARIABLE_SIZE;
> +  Buffer  = AllocateGlobalBuffer (VarSize, TRUE);
> +
> +  //
> +  // Traverse all valid variables.
> +  //
> +  VarDig = VAR_DIG_PTR (Global->VariableDigests);
> +  while (VarDig != NULL) {
> +    if (VarDig->CacheIndex == VAR_INDEX_INVALID) {
> +      ASSERT (VarDig->StoreIndex != VAR_INDEX_INVALID);
> +
> +      VarSize  =  VARIABLE_HEADER_SIZE (Global->Flags.Auth);
> +      VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
> +      VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
> +      VarSize  = HEADER_ALIGN (VarSize);
> +
> +      //
> +      // Note the variable might be in unconsecutive space.
> +      //
> +      ZeroMem (&VarInfo, sizeof (VarInfo));
> +      VarInfo.StoreIndex = VarDig->StoreIndex;
> +      VarInfo.Buffer     = Buffer;
> +      VarInfo.Flags.Auth = VarDig->Flags.Auth;
> +
> +      Status = ContextIn->GetVariableInfo (&VarInfo);
> +      ASSERT_EFI_ERROR (Status);
> +      //
> +      // VerifyVariableDigest() refers to CipherData for raw data.
> +      //
> +      VarInfo.CipherData     = VarInfo.Header.Data;
> +      VarInfo.CipherDataSize = (UINT32)VarInfo.Header.DataSize;
> +
> +      //
> +      // Make sure that the cached copy is not compromised.
> +      //
> +      Status = VerifyVariableDigest (Global, &VarInfo, VarDig);
> +      if (EFI_ERROR (Status)) {
> +        REPORT_STATUS_CODE (
> +          EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
> +          (PcdGet32 (PcdStatusCodeVariableIntegrity) | (Status & 0xFF))
> +          );
> +        ASSERT_EFI_ERROR (Status);
> +        CpuDeadLoop ();
> +      }
> +
> +      //
> +      // Simply use the cache address as CacheIndex of the variable.
> +      //
> +      VarDig->CacheIndex = GET_ADRS (Buffer);
> +      Buffer             = (UINT8 *)Buffer + MAX_VARIABLE_SIZE;
> +    } else {
> +      Result = StrnCmp (
> +                 VAR_DIG_NAME (VarDig),
> +                 METADATA_HMAC_VARIABLE_NAME,
> +                 METADATA_HMAC_VARIABLE_NAME_SIZE
> +                 );
> +      if (Result == 0) {
> +        CopyMem (
> +          Buffer,
> +          GET_BUFR (Global->GlobalSelf + (Global->StructSize -
> GetMetaDataHmacVarSize (Global->Flags.Auth))),
> +          GetMetaDataHmacVarSize (Global->Flags.Auth)
> +          );
> +
> +        //
> +        // Simply use the cache address as CacheIndex of the variable.
> +        //
> +        VarDig->CacheIndex = GET_ADRS (Buffer);
> +        Buffer             = (UINT8 *)Buffer + MAX_VARIABLE_SIZE;
> +      }
> +    }
> +
> +    VarDig = VAR_DIG_NEXT (VarDig);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Callback use to perform variable integrity check.
> +
> +  @param[in] PeiServices          General purpose services available to every PEIM.
> +  @param[in] NotifyDescriptor     The notification structure this PEIM registered
> on install.
> +  @param[in] Ppi                  The memory discovered PPI.  Not used.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval others                  There's error in MP initialization.
> +**/
> +EFI_STATUS
> +EFIAPI
> +VariableStoreDiscoveredPpiNotifyCallback (
> +  IN EFI_PEI_SERVICES           **PeiServices,
> +  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> +  IN VOID                       *Ppi
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  EFI_HOB_GUID_TYPE              *GuidHob;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +
> +  GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
> +  if (GuidHob != NULL) {
> +    ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA
> (GuidHob);
> +  } else {
> +    ASSERT (GuidHob == NULL);
> +  }
> +
> +  Status = ContextIn->IsHobVariableStoreAvailable ();
> +
> +  if (Status == EFI_NOT_READY) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  Status = PerformVariableIntegrityCheck (ContextIn);
> +
> +  return Status;
> +}
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR  mPostMemNotifyList[] = {
> +  {
> +    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +    &gEfiPeiMemoryDiscoveredPpiGuid,
> +    MemoryDiscoveredPpiNotifyCallback
> +  }
> +};
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR  mVariableStoreNotifyList[] = {
> +  {
> +    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +    &gEfiPeiVariableStoreDiscoveredPpiGuid,
> +    VariableStoreDiscoveredPpiNotifyCallback
> +  }
> +};
> +
> +/**
> +
> +  Get global data structure used to process protected variable.
> +
> +  @param[out]   Global      Pointer to global configuration data.
> +
> +  @retval EFI_SUCCESS         Get requested structure successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableGlobal (
> +  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
> +  )
> +{
> +  return GetProtectedVariableGlobalFromHob (Global);
> +}
> +
> +/**
> +
> +  Get context data structure used to process protected variable.
> +
> +  @param[out]   ContextIn   Pointer to context provided by variable runtime
> services.
> +
> +  @retval EFI_SUCCESS         Get requested structure successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableContext (
> +  PROTECTED_VARIABLE_CONTEXT_IN  **ContextIn  OPTIONAL
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  GuidHob = GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid);
> +  if (GuidHob != NULL) {
> +    *ContextIn = (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA
> (GuidHob);
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Verify the HMAC value stored in MetaDataHmacVar against all valid and
> +  protected variables in storage.
> +
> +  @param[in,out]  Global          Pointer to global configuration data.
> +
> +  @retval   EFI_SUCCESS           The HMAC value matches.
> +  @retval   EFI_ABORTED           Error in HMAC value calculation.
> +  @retval   EFI_VOLUME_CORRUPTED  Inconsistency found in NV variable
> storage.
> +  @retval   EFI_COMPROMISED_DATA  The HMAC value doesn't match.
> +
> +**/
> +EFI_STATUS
> +VerifyMetaDataHmac (
> +  IN OUT  PROTECTED_VARIABLE_GLOBAL  *Global
> +  )
> +{
> +  EFI_STATUS       Status;
> +  VARIABLE_DIGEST  *VariableDig;
> +  UINT32           Counter1;
> +  UINT32           Counter2;
> +  VOID             *Hmac1;
> +  VOID             *Hmac2;
> +  UINT8            HmacVal1[METADATA_HMAC_SIZE];
> +  UINT8            HmacVal2[METADATA_HMAC_SIZE];
> +
> +  Hmac1 = NULL;
> +  Hmac2 = HmacSha256New ();
> +  if (Hmac2 == NULL) {
> +    ASSERT (Hmac2 != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  if (!HmacSha256SetKey (Hmac2, Global->MetaDataHmacKey, sizeof (Global-
> >MetaDataHmacKey))) {
> +    ASSERT (FALSE);
> +    Status = EFI_ABORTED;
> +    goto Done;
> +  }
> +
> +  //
> +  // Retrieve the RPMC counter value.
> +  //
> +  Status = RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    goto Done;
> +  }
> +
> +  Status = RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    goto Done;
> +  }
> +
> +  //
> +  // Counter1 must be either equal to Counter2 or just one step ahead of
> Counter2.
> +  //
> +  if ((Counter1 > Counter2) && ((Counter1 - Counter2) > 1)) {
> +    Status = EFI_COMPROMISED_DATA;
> +    goto Done;
> +  }
> +
> +  VariableDig = VAR_DIG_PTR (Global->VariableDigests);
> +  while (VariableDig != NULL) {
> +    //
> +    // Only take valid protected variables into account.
> +    //
> +    if (VariableDig->Flags.Protected && VariableDig->Flags.Valid) {
> +      if (!HmacSha256Update (
> +             Hmac2,
> +             VAR_DIG_VALUE (VariableDig),
> +             VariableDig->DigestSize
> +             ))
> +      {
> +        ASSERT (FALSE);
> +        Status = EFI_ABORTED;
> +        goto Done;
> +      }
> +    }
> +
> +    VariableDig = VAR_DIG_NEXT (VariableDig);
> +  }
> +
> +  //
> +  // If two MetaDataHmacVariable were found, check which one is valid. We
> might
> +  // need two HMAC values to check against: one for Counter1, one for
> Counter2.
> +  //
> +  if (  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
> +     && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID)
> +     && (Counter1 != Counter2))
> +  {
> +    //
> +    // Might need to check Counter1. There must be something wrong in last
> boot.
> +    //
> +    Hmac1 = HmacSha256New ();
> +    if ((Hmac1 == NULL) || !HmacSha256Duplicate (Hmac2, Hmac1)) {
> +      ASSERT (FALSE);
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto Done;
> +    }
> +
> +    if (  !HmacSha256Update (Hmac1, &Counter1, sizeof (Counter1))
> +       || !HmacSha256Final (Hmac1, HmacVal1))
> +    {
> +      ASSERT (FALSE);
> +      Status = EFI_ABORTED;
> +      goto Done;
> +    }
> +  }
> +
> +  //
> +  // Always check Counter2.
> +  //
> +  if (  !HmacSha256Update (Hmac2, &Counter2, sizeof (Counter2))
> +     || !HmacSha256Final (Hmac2, HmacVal2))
> +  {
> +    ASSERT (FALSE);
> +    Status = EFI_ABORTED;
> +    goto Done;
> +  }
> +
> +  //
> +  //  When writing (update or add) a variable, there must be following steps
> +  //  performed:
> +  //
> +  //    A - Increment Counter1
> +  //    B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +  //    C - Calculate new HMAC value against Counter2+1,
> +  //        and force-add a new MetaDataHmacVar with state of VAR_ADDED
> +  //    D - Write the new protected variable
> +  //    E - Increment Counter2
> +  //    F - Mark old MetaDataHmacVar as VAR_DELETED
> +  //
> +  Status = EFI_COMPROMISED_DATA;
> +  if (  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
> +     && (Global->Unprotected[IndexHmacInDel] == VAR_INDEX_INVALID))
> +  {
> +    if (CompareMem (
> +          VAR_DIG_VALUE (VAR_DIG_PTR (Global-
> >Unprotected[IndexHmacAdded])),
> +          HmacVal2,
> +          METADATA_HMAC_SIZE
> +          ) == 0)
> +    {
> +      //
> +      //
> +      // + A - Increment Counter1
> +      //   B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +      //   C - Calculate new HMAC value against Counter2+1,
> +      //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
> +      //   D - Write the new protected variable
> +      //   E - Increment Counter2
> +      //   F - Mark old MetaDataHmacVar as VAR_DELETED
> +      //
> +      // or,
> +      //
> +      // + A - Increment Counter1
> +      // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +      // + C - Calculate new HMAC value against Counter2+1,
> +      //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
> +      // + D - Write the new protected variable
> +      // + E - Increment Counter2
> +      // + F - Mark old MetaDataHmacVar as VAR_DELETED
> +      //
> +      Status = EFI_SUCCESS;
> +
> +      VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid =
> TRUE;
> +    }
> +  } else if (  (Global->Unprotected[IndexHmacAdded] == VAR_INDEX_INVALID)
> +            && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID))
> +  {
> +    if (CompareMem (
> +          VAR_DIG_VALUE (VAR_DIG_PTR (Global-
> >Unprotected[IndexHmacInDel])),
> +          HmacVal2,
> +          METADATA_HMAC_SIZE
> +          ) == 0)
> +    {
> +      //
> +      // + A - Increment Counter1
> +      // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +      //   C - Calculate new HMAC value against Counter2+1,
> +      //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
> +      //   D - Write the new protected variable
> +      //   E - Increment Counter2
> +      //   F - Mark old MetaDataHmacVar as VAR_DELETED
> +      //
> +      Status = EFI_SUCCESS;
> +
> +      VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = TRUE;
> +    }
> +  } else if (  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
> +            && (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID))
> +  {
> +    if (Counter1 > Counter2) {
> +      if (CompareMem (
> +            VAR_DIG_VALUE (VAR_DIG_PTR (Global-
> >Unprotected[IndexHmacInDel])),
> +            HmacVal2,
> +            METADATA_HMAC_SIZE
> +            ) == 0)
> +      {
> +        //
> +        // + A - Increment Counter1
> +        // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +        // + C - Calculate new HMAC value against Counter2+1,
> +        //       and force-add a new MetaDataHmacVar with state VAR_ADDED
> +        //   D - Write the new protected variable
> +        //   E - Increment Counter2
> +        //   F - Mark old MetaDataHmacVar as VAR_DELETED
> +        //
> +        Status = EFI_SUCCESS;
> +
> +        VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid =
> FALSE;
> +        VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid =
> TRUE;
> +      } else if (CompareMem (
> +                   VAR_DIG_VALUE (VAR_DIG_PTR (Global-
> >Unprotected[IndexHmacAdded])),
> +                   HmacVal1,
> +                   METADATA_HMAC_SIZE
> +                   ) == 0)
> +      {
> +        //
> +        // + A - Increment Counter1
> +        // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +        // + C - Calculate new HMAC value against Counter2+1,
> +        //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
> +        // + D - Write the new protected variable
> +        //   E - Increment Counter2
> +        //   F - Mark old MetaDataHmacVar as VAR_DELETED
> +        //
> +        Status = EFI_SUCCESS;
> +
> +        VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid =
> TRUE;
> +        VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid =
> FALSE;
> +      }
> +    } else {
> +      if (CompareMem (
> +            VAR_DIG_VALUE (VAR_DIG_PTR (Global-
> >Unprotected[IndexHmacAdded])),
> +            HmacVal2,
> +            METADATA_HMAC_SIZE
> +            ) == 0)
> +      {
> +        //
> +        // + A - Increment Counter1
> +        // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION
> +        // + C - Calculate new HMAC value against Counter2+1,
> +        //       and force-add a new MetaDataHmacVar with state of VAR_ADDED
> +        // + D - Write the new protected variable
> +        // + E - Increment Counter2
> +        //   F - Mark old MetaDataHmacVar as VAR_DELETED
> +        //
> +        Status = EFI_SUCCESS;
> +
> +        VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid =
> TRUE;
> +        VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid =
> FALSE;
> +      }
> +    }
> +  } else {
> +    //
> +    // There must be logic error or variable written to storage skipped
> +    // the protected variable service, if code reaches here.
> +    //
> +    ASSERT (FALSE);
> +  }
> +
> +Done:
> +  if (Hmac1 != NULL) {
> +    HmacSha256Free (Hmac1);
> +  }
> +
> +  if (Hmac2 != NULL) {
> +    HmacSha256Free (Hmac2);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Collect variable digest information.
> +
> +  This information is collected to be used to for integrity check.
> +
> +  @param[in]       Global             Pointer to global configuration data.
> +  @param[in]       ContextIn          Pointer to variable service context needed by
> +                                      protected variable.
> +  @param[in, out]  DigestBuffer       Base address of digest of each variable.
> +  @param[out]      DigestBufferSize   Digest size of one variable if DigestBuffer
> is NULL.
> +                                      Size of DigestBuffer if DigestBuffer is NOT NULL.
> +  @param[out]      VariableNumber     Number of valid variables.
> +
> +  @retval   EFI_SUCCESS             Successfully retreived variable digest.
> +  @retval   EFI_INVALID_PARAMETER   One ore more parameters are invalid.
> +  @retval   EFI_OUT_OF_RESOURCES    Unable to allocate memory.
> +  @retval   EFI_BUFFER_TOO_SMALL    The DigestBufferSize pass in is too small.
> +
> +**/
> +EFI_STATUS
> +CollectVariableDigestInfo (
> +  IN      PROTECTED_VARIABLE_GLOBAL      *Global,
> +  IN      PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn,
> +  IN  OUT VOID                           *DigestBuffer OPTIONAL,
> +  OUT UINT32                             *DigestBufferSize OPTIONAL,
> +  OUT UINT32                             *VariableNumber OPTIONAL
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  PROTECTED_VARIABLE_INFO     VarInfo;
> +  UINT32                      VarNum;
> +  UINT32                      DigSize;
> +  VARIABLE_DIGEST             *VarDig;
> +  EFI_TIME                    TimeStamp;
> +  UNPROTECTED_VARIABLE_INDEX  VarIndex;
> +
> +  //
> +  // This function might be called before Global is initialized. In that case,
> +  // Global must be NULL but not ContextIn.
> +  //
> +  if ((Global == NULL) && (ContextIn == NULL)) {
> +    ASSERT (Global != NULL || ContextIn != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Global == NULL) && (DigestBuffer != NULL)) {
> +    ASSERT (Global != NULL && DigestBuffer != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (  (DigestBuffer != NULL)
> +     && ((DigestBufferSize == NULL) || (*DigestBufferSize == 0)))
> +  {
> +    ASSERT (
> +      DigestBuffer != NULL
> +           && DigestBufferSize != NULL && *DigestBufferSize > 0
> +      );
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Global != NULL) && (ContextIn == NULL)) {
> +    ContextIn = GET_CNTX (Global);
> +  }
> +
> +  DigSize = 0;
> +  VarNum  = 0;
> +  VarDig  = NULL;
> +
> +  ZeroMem (&VarInfo, sizeof (VarInfo));
> +  VarInfo.StoreIndex = VAR_INDEX_INVALID; // To get the first variable.
> +
> +  if ((Global != NULL) &&
> +      (Global->VariableCache != 0) &&
> +      (Global->VariableCacheSize > 0))
> +  {
> +    //
> +    // Use the variable cache to hold a copy of one variable.
> +    //
> +    VarInfo.Buffer = GET_BUFR (Global->VariableCache);
> +  } else {
> +    //
> +    // Allocate a buffer to hold a copy of one variable
> +    //
> +    VarInfo.Buffer = AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
> +    if (VarInfo.Buffer == NULL) {
> +      ASSERT (VarInfo.Buffer != NULL);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +  }
> +
> +  if ((DigestBuffer != NULL) && (*DigestBufferSize > 0)) {
> +    VarDig = DigestBuffer;
> +  }
> +
> +  while (TRUE) {
> +    if (VarDig != NULL) {
> +      if (DigSize >= (*DigestBufferSize)) {
> +        //
> +        // Out of buffer.
> +        //
> +        break;
> +      }
> +
> +      VarInfo.Header.VendorGuid   = &VarDig->VendorGuid;
> +      VarInfo.Header.VariableName = VAR_DIG_NAME (VarDig);
> +      VarInfo.Header.NameSize     = (UINTN)DigestBuffer +
> (UINTN)*DigestBufferSize
> +                                    - (UINTN)VarInfo.Header.VariableName;
> +      VarInfo.Header.TimeStamp = &TimeStamp;
> +      VarInfo.Header.Data      = NULL;
> +    } else {
> +      ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header));
> +    }
> +
> +    Status = ContextIn->GetNextVariableInfo (&VarInfo);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    //
> +    // Skip deleted variables.
> +    //
> +    if (  (VarInfo.Header.State != VAR_ADDED)
> +       && (VarInfo.Header.State != (VAR_ADDED &
> VAR_IN_DELETED_TRANSITION)))
> +    {
> +      continue;
> +    }
> +
> +    if (Global != NULL) {
> +      Global->Flags.Auth &= VarInfo.Flags.Auth;
> +    }
> +
> +    VarNum  += 1;
> +    DigSize += (UINT32)(sizeof (VARIABLE_DIGEST)
> +                        + VarInfo.Header.NameSize
> +                        + METADATA_HMAC_SIZE);
> +    if ((DigestBuffer != NULL) && (DigSize > *DigestBufferSize)) {
> +      ASSERT (DigSize <= *DigestBufferSize);
> +      return EFI_BUFFER_TOO_SMALL;
> +    }
> +
> +    if (VarDig != NULL) {
> +      VarDig->Prev       = 0;
> +      VarDig->Next       = 0;
> +      VarDig->State      = VarInfo.Header.State;
> +      VarDig->Attributes = VarInfo.Header.Attributes;
> +      VarDig->DataSize   = (UINT32)VarInfo.Header.DataSize;
> +      VarDig->NameSize   = (UINT16)VarInfo.Header.NameSize;
> +      VarDig->DigestSize = METADATA_HMAC_SIZE;
> +      VarDig->StoreIndex = VarInfo.StoreIndex;
> +
> +      if ((VarInfo.Buffer != NULL) && ((UINTN)VarInfo.Buffer != Global-
> >VariableCache)) {
> +        VarDig->CacheIndex = GET_ADRS (VarInfo.Buffer);
> +      } else {
> +        VarDig->CacheIndex = VAR_INDEX_INVALID;
> +      }
> +
> +      VarDig->Flags.Auth  = VarInfo.Flags.Auth;
> +      VarDig->Flags.Valid = TRUE;
> +
> +      VarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
> +      if (VarIndex >= UnprotectedVarIndexMax) {
> +        //
> +        // Check information relating to encryption, if enabled.
> +        //
> +        VarDig->Flags.Encrypted = FALSE;
> +        if ((VarInfo.Header.Data != NULL) && (VarInfo.Header.DataSize > 0)) {
> +          VarInfo.CipherData     = NULL;
> +          VarInfo.CipherDataSize = 0;
> +          VarInfo.PlainData      = NULL;
> +          VarInfo.PlainDataSize  = 0;
> +          Status                 = GetCipherDataInfo (&VarInfo);
> +          if (!EFI_ERROR (Status)) {
> +            //
> +            // Discovered encrypted variable mark variable to be
> +            // encrypted on the next SetVariable() operation
> +            //
> +            VarDig->Flags.Encrypted = PcdGetBool
> (PcdProtectedVariableConfidentiality);
> +          } else {
> +            VarInfo.PlainData        = VarInfo.Header.Data;
> +            VarInfo.PlainDataSize    = (UINT32)VarInfo.Header.DataSize;
> +            VarInfo.CipherDataType   = 0;
> +            VarInfo.CipherHeaderSize = 0;
> +            if (Status == EFI_NOT_FOUND) {
> +              //
> +              // Found variable that is not encrypted mark variable to be
> +              // encrypted on the next SetVariable() operation
> +              //
> +              VarDig->Flags.Encrypted = PcdGetBool
> (PcdProtectedVariableConfidentiality);
> +            }
> +          }
> +        }
> +
> +        //
> +        // Variable is protected
> +        //
> +        VarDig->Flags.Protected = PcdGetBool (PcdProtectedVariableIntegrity);
> +        VarDig->PlainDataSize   = VarInfo.PlainDataSize;
> +
> +        //
> +        // Calculate digest only for protected variable.
> +        //
> +        Status = GetVariableDigest (Global, &VarInfo, VAR_DIG_VALUE (VarDig));
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +
> +        //
> +        // Keep the VarDig in an ordered list.
> +        //
> +        InsertVariableDigestNode (Global, VarDig, CompareVariableDigestInfo);
> +      } else {
> +        VarDig->Flags.Protected = FALSE;
> +        VarDig->Flags.Encrypted = FALSE;
> +        VarDig->PlainDataSize   = VarDig->DataSize;
> +
> +        //
> +        // Make use of VARIABLE_DIGEST->DigestValue to cache HMAC value
> from
> +        // MetaDataHmacVar, which doesn't need a digest value (only protected
> +        // variables need it for integrity check).
> +        //
> +        if ((VarIndex == IndexHmacInDel) || (VarIndex == IndexHmacAdded)) {
> +          if (VarDig->State == VAR_ADDED) {
> +            VarIndex = IndexHmacAdded;
> +          } else {
> +            VarIndex = IndexHmacInDel;
> +          }
> +        }
> +
> +        Global->Unprotected[VarIndex] = VAR_DIG_ADR (VarDig);
> +
> +        if ((VarInfo.Header.Data != NULL) && (VarDig->DataSize <= VarDig-
> >DigestSize)) {
> +          CopyMem (VAR_DIG_VALUE (VarDig), VarInfo.Header.Data, VarDig-
> >DataSize);
> +        }
> +
> +        //
> +        // Don't add the VarDig for MetaDataHmacVar into the linked list now.
> +        // Do it after the HMAC has been validated.
> +        //
> +        if ((VarIndex != IndexHmacInDel) || (VarIndex != IndexHmacAdded)) {
> +          InsertVariableDigestNode (Global, VarDig, CompareVariableDigestInfo);
> +        }
> +      }
> +
> +      VarDig = (VARIABLE_DIGEST *)((UINTN)VarDig + VAR_DIG_END (VarDig));
> +    }
> +  }
> +
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    return Status;
> +  }
> +
> +  if (DigestBufferSize != NULL) {
> +    *DigestBufferSize = DigSize;
> +  }
> +
> +  if (VariableNumber != NULL) {
> +    *VariableNumber = VarNum;
> +  }
> +
> +  if ((Global == NULL) && (VarInfo.Buffer != NULL)) {
> +    //
> +    // Free Buffer
> +    //
> +    FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Perform for protected variable integrity check.
> +
> +  If this initialization failed upon any error, the whole variable services
> +  should not be used.  A system reset might be needed to re-construct NV
> +  variable storage to be the default state.
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected
> variables.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PerformVariableIntegrityCheck (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  UINT32                     HobDataSize;
> +  UINT32                     VarNumber;
> +  VOID                       *Buffer;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VARIABLE_DIGEST            *DigBuffer;
> +  UINT32                     DigBufferSize;
> +  UINT32                     HmacMetaDataSize;
> +  UINTN                      Index;
> +  BOOLEAN                    PreviousKey;
> +  EFI_HOB_GUID_TYPE          *GuidHob;
> +
> +  if ((ContextIn == NULL) || (ContextIn->GetNextVariableInfo == NULL)) {
> +    ASSERT (ContextIn != NULL);
> +    ASSERT (ContextIn->GetNextVariableInfo != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ContextIn->StructSize = (ContextIn->StructSize == 0) ? sizeof (*ContextIn)
> +                                                       : ContextIn->StructSize;
> +
> +  //
> +  // Enumerate all variables first to collect info for resource allocation.
> +  //
> +  DigBufferSize = 0;
> +  Status        = CollectVariableDigestInfo (
> +                    NULL,
> +                    ContextIn,
> +                    NULL,
> +                    &DigBufferSize,
> +                    &VarNumber
> +                    );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return EFI_VOLUME_CORRUPTED;
> +  }
> +
> +  //
> +  // Allocate buffer for Global. Memory layout:
> +  //
> +  //      Global
> +  //      Digest context
> +  //      Variable Digest List
> +  //      HmacMetaData
> +  //
> +  // To save precious NEM space of processor, variable cache will not be
> +  // allocated at this point until physical memory is ready for use.
> +  //
> +  HmacMetaDataSize = (UINT32)GetMetaDataHmacVarSize (TRUE);
> +  HobDataSize      = sizeof (PROTECTED_VARIABLE_GLOBAL)
> +                     + (UINT32)DIGEST_CONTEXT_SIZE
> +                     + DigBufferSize
> +                     + HmacMetaDataSize;
> +  Buffer = AllocateGlobalBuffer (HobDataSize, FALSE);
> +  if (Buffer == NULL) {
> +    ASSERT (Buffer != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Global                = (PROTECTED_VARIABLE_GLOBAL *)((UINTN)Buffer);
> +  Global->DigestContext = GET_ADRS (Global + 1);
> +
> +  if (DigBufferSize > 0) {
> +    DigBuffer = (VARIABLE_DIGEST *)(UINTN)(Global->DigestContext +
> DIGEST_CONTEXT_SIZE);
> +    ZeroMem (DigBuffer, DigBufferSize);
> +  } else {
> +    DigBuffer = NULL;
> +  }
> +
> +  //
> +  // Keep a copy of ContextIn in HOB for later uses.
> +  //
> +  Global->GlobalSelf = GET_ADRS (Global);
> +  Global->ContextIn  = GET_ADRS (ContextIn);
> +
> +  Global->StructVersion =
> PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION;
> +  Global->StructSize    = HobDataSize;
> +
> +  Global->VariableNumber  = VarNumber;
> +  Global->VariableDigests = 0;
> +
> +  Global->Flags.Auth       = TRUE;
> +  Global->Flags.WriteInit  = FALSE;
> +  Global->Flags.WriteReady = FALSE;
> +
> +  GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
> +  if (GuidHob == NULL) {
> +    GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
> +    if (GuidHob != NULL) {
> +      Global->Flags.Auth = FALSE;
> +    }
> +  }
> +
> +  Global->Flags.RecoveryMode = (GuidHob != NULL);
> +
> +  //
> +  // Before physical memory is ready, we cannot cache all variables in the very
> +  // limited NEM space. But we still need to reserve buffer to hold data of
> +  // one variable as well as context for integrity check (HMAC calculation).
> +  //
> +  Global->VariableCacheSize = MAX_VARIABLE_SIZE;
> +  Buffer                    = AllocatePages (EFI_SIZE_TO_PAGES (Global-
> >VariableCacheSize));
> +  if (Buffer == NULL) {
> +    ASSERT (Buffer != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Global->VariableCache        = GET_ADRS (Buffer);
> +  Global->LastAccessedVariable = VAR_INDEX_INVALID;
> +
> +  for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
> +    Global->Unprotected[Index] = VAR_INDEX_INVALID;
> +  }
> +
> +  //
> +  // Re-enumerate all NV variables and build digest list.
> +  //
> +  Status = CollectVariableDigestInfo (
> +             Global,
> +             ContextIn,
> +             DigBuffer,
> +             &DigBufferSize,
> +             &VarNumber
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  ASSERT (Global->VariableNumber == VarNumber);
> +
> +  //
> +  // Fix-up number of valid protected variables (i.e. exclude unprotected ones)
> +  //
> +  for (Index = 0; VarNumber != 0 && Index < UnprotectedVarIndexMax; ++Index)
> {
> +    if (Global->Unprotected[Index] != VAR_INDEX_INVALID) {
> +      --VarNumber;
> +    }
> +  }
> +
> +  //
> +  // Get root key and generate HMAC key.
> +  //
> +  PreviousKey = FALSE;
> +  Status      = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global-
> >RootKey));
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (FALSE);
> +    Status = EFI_COMPROMISED_DATA;
> +  }
> +
> +  //
> +  // Derive the MetaDataHmacKey from root key
> +  //
> +  if (!GenerateMetaDataHmacKey (
> +         Global->RootKey,
> +         sizeof (Global->RootKey),
> +         Global->MetaDataHmacKey,
> +         sizeof (Global->MetaDataHmacKey)
> +         ))
> +  {
> +    ASSERT (FALSE);
> +    Status = EFI_COMPROMISED_DATA;
> +  }
> +
> +  //
> +  // Check the integrity of all NV variables, if any.
> +  //
> +  if ((  (Global->Unprotected[IndexHmacAdded] != VAR_INDEX_INVALID)
> +      || (Global->Unprotected[IndexHmacInDel] != VAR_INDEX_INVALID)))
> +  {
> +    //
> +    // Validate the HMAC stored in variable MetaDataHmacVar.
> +    //
> +    Status = VerifyMetaDataHmac (Global);
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Try again with the previous root key if the latest key failed the HMAC
> validation.
> +      //
> +      Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global-
> >RootKey));
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // Derive the MetaDataHmacKey from previous root key
> +        //
> +        if (GenerateMetaDataHmacKey (
> +              Global->RootKey,
> +              sizeof (Global->RootKey),
> +              Global->MetaDataHmacKey,
> +              sizeof (Global->MetaDataHmacKey)
> +              ) == TRUE)
> +        {
> +          //
> +          // Validate the HMAC stored in variable MetaDataHmacVar.
> +          //
> +          Status = VerifyMetaDataHmac (Global);
> +          if (!EFI_ERROR (Status)) {
> +            Status = EFI_COMPROMISED_DATA;
> +          }
> +        } else {
> +          Status = EFI_COMPROMISED_DATA;
> +        }
> +      }
> +    }
> +  } else if (Global->Flags.RecoveryMode) {
> +    //
> +    // Generate the first version of MetaDataHmacVar.
> +    //
> +    Status = SyncRpmcCounter ();
> +    if (!EFI_ERROR (Status)) {
> +      Status = RefreshVariableMetadataHmac (Global, NULL, NULL);
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // MetaDataHmacVar is always calculated against Counter2+1. Updating
> +        // RPMCs to match it.
> +        //
> +        (VOID)IncrementMonotonicCounter (RPMC_COUNTER_1);
> +        (VOID)IncrementMonotonicCounter (RPMC_COUNTER_2);
> +      }
> +    }
> +  } else if ((VarNumber > 0) && !Global->Flags.RecoveryMode) {
> +    //
> +    // There's no MetaDataHmacVar found for protected variables. Suppose
> +    // the variable storage is compromised.
> +    //
> +    Status = EFI_COMPROMISED_DATA;
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // The integrity of variables have been compromised. The platform has to do
> +    // something to recover the variable store. But the boot should not go on
> +    // anyway this time.
> +    //
> +    DEBUG ((DEBUG_ERROR, "%a: %d Integrity check Status = %r\n",
> __FUNCTION__, __LINE__, Status));
> +    REPORT_STATUS_CODE (
> +      EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
> +      (PcdGet32 (PcdStatusCodeVariableIntegrity) |
> EFI_SW_PEI_PC_RECOVERY_BEGIN)
> +      );
> + #if defined (EDKII_UNIT_TEST_FRAMEWORK_ENABLED) // Avoid test
> malfunctioning.
> +    return Status;
> + #else
> +    ASSERT_EFI_ERROR (Status);
> +    CpuDeadLoop ();
> + #endif
> +  }
> +
> +  //
> +  // Everything's OK.
> +  //
> +  REPORT_STATUS_CODE (
> +    EFI_PROGRESS_CODE,
> +    PcdGet32 (PcdStatusCodeVariableIntegrity)
> +    );
> +
> +  if (GET_BUFR (Global->VariableCacheSize) != NULL) {
> +    //
> +    // Free Buffer
> +    //
> +    FreePages (Buffer, EFI_SIZE_TO_PAGES (Global->VariableCacheSize));
> +  }
> +
> +  //
> +  // Keep the valid MetaDataHmacVar in the list.
> +  //
> +  for (Index = 0; Index < IndexPlatformVar; ++Index) {
> +    if (  (Global->Unprotected[Index] != VAR_INDEX_INVALID)
> +       && VAR_DIG_PTR (Global->Unprotected[Index])->Flags.Valid)
> +    {
> +      InsertVariableDigestNode (
> +        Global,
> +        VAR_DIG_PTR (Global->Unprotected[Index]),
> +        NULL
> +        );
> +    }
> +  }
> +
> +  //
> +  // Restore the key to the latest one.
> +  //
> +  if (PreviousKey) {
> +    Status = GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->RootKey));
> +    ASSERT_EFI_ERROR (Status);
> +
> +    //
> +    // Derive the MetaDataHmacKey from root key
> +    //
> +    if (!GenerateMetaDataHmacKey (
> +           Global->RootKey,
> +           sizeof (Global->RootKey),
> +           Global->MetaDataHmacKey,
> +           sizeof (Global->MetaDataHmacKey)
> +           ))
> +    {
> +      ASSERT (FALSE);
> +    }
> +  }
> +
> +  //
> +  // Make sure that the RPMC counter is in-sync.
> +  //
> +  Status = SyncRpmcCounter ();
> +
> +  //
> +  // Setup a hook to migrate data in Global once physical memory is ready.
> +  //
> +  Status = PeiServicesNotifyPpi (mPostMemNotifyList);
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Initialization for protected variable services.
> +
> +  If the variable store is available than perform integrity check.
> +  Otherwise, defer integrity check until variable store is available.
> +
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected
> variables.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  )
> +{
> +  EFI_STATUS               Status;
> +  VOID                     *ContextInHob;
> +  PROTECTED_VARIABLE_INFO  VarInfo;
> +
> +  if ((ContextIn == NULL) || (ContextIn->GetNextVariableInfo == NULL)) {
> +    ASSERT (ContextIn != NULL);
> +    ASSERT (ContextIn->GetNextVariableInfo != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Keep a copy of ContextIn in HOB for later uses.
> +  //
> +  ContextIn->StructSize = (ContextIn->StructSize == 0) ? sizeof (*ContextIn)
> +                                                       : ContextIn->StructSize;
> +  ContextInHob = BuildGuidHob (&gEdkiiProtectedVariableContextGuid,
> ContextIn->StructSize);
> +  CopyMem (ContextInHob, ContextIn, ContextIn->StructSize);
> +
> +  //
> +  // Discover if Variable Store Info Hob has been published by platform driver.
> +  // It contains information regards to HOB or NV Variable Store availability
> +  //
> +  ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header));
> +  VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +  VarInfo.Buffer     = AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE));
> +  if (VarInfo.Buffer == NULL) {
> +    ASSERT (VarInfo.Buffer != NULL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES ((MAX_VARIABLE_SIZE)));
> +
> +  Status = ContextIn->GetNextVariableInfo (&VarInfo);
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // Register for platform driver callback when Variable Store is available.
> +    //
> +    DEBUG ((DEBUG_INFO, "Variable Store is not available. Register for a
> integrity check callback\n"));
> +    Status = PeiServicesNotifyPpi (mVariableStoreNotifyList);
> +    return Status;
> +  }
> +
> +  //
> +  // HOB Variable store is not available
> +  // Assume NV Variable store is available instead
> +  // Perform integrity check on NV Variable Store
> +  //
> +  DEBUG ((DEBUG_INFO, "NV Variable Store is available. Perform integrity
> check\n"));
> +  Status = PerformVariableIntegrityCheck (ContextInHob);
> +  return Status;
> +}
> +
> +/**
> +
> +  Prepare for variable update.
> +
> +  (Not suppported in PEI phase.)
> +
> +  @retval EFI_UNSUPPORTED         Updating variable is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> +  VOID
> +  )
> +{
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Update a variable with protection provided by this library.
> +
> +  Not supported in PEI phase.
> +
> +  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
> +                                      adding a new variable.
> +  @param[in]      CurrVariableInDel   In-delete-transition copy of updating
> variable.
> +  @param[in,out]  NewVariable         Buffer of new variable data.
> +                                      Buffer of "MetaDataHmacVar" and new
> +                                      variable (encrypted).
> +  @param[in,out]  NewVariableSize     Size of NewVariable.
> +                                      Size of (encrypted) NewVariable and
> +                                      "MetaDataHmacVar".
> +
> +  @retval EFI_UNSUPPORTED         Not support updating variable in PEI phase.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> +  IN  OUT VARIABLE_HEADER  *CurrVariable,
> +  IN      VARIABLE_HEADER  *CurrVariableInDel,
> +  IN  OUT VARIABLE_HEADER  *NewVariable,
> +  IN  OUT UINTN            *NewVariableSize
> +  )
> +{
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Finalize a variable updating after it's written to NV variable storage
> +  successfully.
> +
> +  @param[in]      NewVariable       Buffer of new variables and
> MetaDataHmacVar.
> +  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
> +  @param[in]      StoreIndex        StoreIndex to NV variable storage from where
> the new
> +                                    variable and MetaDataHmacVar have been written.
> +
> +  @retval EFI_UNSUPPORTED           Not support updating variable in PEI phase.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> +  IN  VARIABLE_HEADER  *NewVariable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex
> +  )
> +{
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> new file mode 100644
> index 000000000000..8e964f4cd28d
> --- /dev/null
> +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> @@ -0,0 +1,209 @@
> +/** @file
> +  Implemention of ProtectedVariableLib for SMM variable services.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Uefi.h>
> +
> +#include "Guid/SmmVariableCommon.h"
> +
> +#include "Library/MmServicesTableLib.h"
> +#include "Library/MemoryAllocationLib.h"
> +
> +#include "ProtectedVariableInternal.h"
> +
> +PROTECTED_VARIABLE_CONTEXT_IN  mVariableContextIn = {
> +  PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
> +  sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
> +  0,
> +  FromSmmModule,
> +  NULL,
> +  NULL,
> +  NULL,
> +  NULL,
> +  NULL
> +};
> +
> +PROTECTED_VARIABLE_GLOBAL  mProtectedVariableGlobal = {
> +  PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
> +  sizeof (PROTECTED_VARIABLE_GLOBAL),
> +  { 0 },
> +  { 0 },
> +  0,
> +  0,
> +  0,
> +  0,
> +  0,
> +  0,
> +  { 0,                                          0,  0 },
> +  0,
> +  0,
> +  { 0,                                          0,  0, 0}
> +};
> +
> +/**
> +
> +  Callback function to call variable write.
> +
> +  @param[in]  Protocol    Not Used.
> +  @param[in]  Interface   Not Used.
> +  @param[in]  Handle      Not Used.
> +
> +  @retval EFI_SUCCESS     Protected variable write successful.
> +  @retval others          Protected variable write failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VariableWriteProtocolCallback (
> +  IN CONST EFI_GUID  *Protocol,
> +  IN VOID            *Interface,
> +  IN EFI_HANDLE      Handle
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  Status = ProtectedVariableLibWriteInit ();
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Initialization for protected variable services.
> +
> +  If this initialization failed upon any error, the whole variable services
> +  should not be used.  A system reset might be needed to re-construct NV
> +  variable storage to be the default state.
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +  @retval EFI_COMPROMISED_DATA      If failed to check integrity of protected
> variables.
> +  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
> +  @retval EFI_UNSUPPORTED           Unsupported to process protected variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ProtectedVarContext;
> +  PROTECTED_VARIABLE_GLOBAL      *OldGlobal;
> +  PROTECTED_VARIABLE_GLOBAL      *NewGlobal;
> +  VARIABLE_DIGEST                *VarDig;
> +  VARIABLE_DIGEST                *NewVarDig;
> +  EFI_PHYSICAL_ADDRESS           NewCacheIndex;
> +  UINTN                          VarSize;
> +  UNPROTECTED_VARIABLE_INDEX     Index;
> +
> +  if (  (ContextIn == NULL)
> +     || (ContextIn->StructVersion !=
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
> +     || (ContextIn->StructSize != sizeof (PROTECTED_VARIABLE_CONTEXT_IN))
> +     || (ContextIn->GetVariableInfo == NULL)
> +     || (ContextIn->GetNextVariableInfo == NULL)
> +     || (ContextIn->UpdateVariableStore == NULL)
> +     || (ContextIn->UpdateVariable == NULL))
> +  {
> +    ASSERT (ContextIn != NULL);
> +    ASSERT (ContextIn->StructVersion ==
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION);
> +    ASSERT (ContextIn->StructSize == sizeof
> (PROTECTED_VARIABLE_CONTEXT_IN));
> +    ASSERT (ContextIn->GetVariableInfo != NULL);
> +    ASSERT (ContextIn->GetNextVariableInfo != NULL);
> +    ASSERT (ContextIn->UpdateVariableStore != NULL);
> +    ASSERT (ContextIn->UpdateVariable != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  GetProtectedVariableGlobal (&NewGlobal);
> +  ProtectedVarContext = GET_CNTX (NewGlobal);
> +  CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn));
> +  ProtectedVarContext->VariableServiceUser = FromSmmModule;
> +
> +  //
> +  // Get root key and HMAC key from HOB created by PEI variable driver.
> +  //
> +  Status = GetProtectedVariableGlobalFromHob (&OldGlobal);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof
> (*OldGlobal));
> +
> +  //
> +  // The keys must not be available outside SMM.
> +  //
> +  if (ProtectedVarContext->VariableServiceUser == FromSmmModule) {
> +    ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey));
> +    ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal-
> >MetaDataHmacKey));
> +  }
> +
> +  NewGlobal->Flags.WriteInit      = FALSE;
> +  NewGlobal->Flags.WriteReady     = FALSE;
> +  NewGlobal->LastAccessedVariable = 0;
> +  NewGlobal->VariableCache        = GET_ADRS (AllocateZeroPool
> (MAX_VARIABLE_SIZE));
> +  NewGlobal->DigestContext        = GET_ADRS (AllocateZeroPool
> (DIGEST_CONTEXT_SIZE));
> +  if (NewGlobal->DigestContext == 0) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Copy over variable from HOB to SMM memory
> +  //
> +  NewGlobal->VariableDigests = 0;
> +  VarDig                     = VAR_DIG_PTR (OldGlobal->VariableDigests);
> +  while (VarDig != NULL) {
> +    //
> +    // Allocate new Var Digest in SMM memory
> +    //
> +    NewVarDig = (VARIABLE_DIGEST *)AllocateZeroPool (
> +                                     sizeof (VARIABLE_DIGEST) + VarDig->NameSize +
> METADATA_HMAC_SIZE
> +                                     );
> +    if (NewVarDig == NULL) {
> +      ASSERT (NewVarDig != NULL);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    CopyMem (NewVarDig, VarDig, sizeof (VARIABLE_DIGEST));
> +    NewVarDig->Prev = 0;
> +    NewVarDig->Next = 0;
> +
> +    CopyMem (VAR_DIG_NAME (NewVarDig), VAR_DIG_NAME (VarDig), VarDig-
> >NameSize);
> +    CopyMem (VAR_DIG_VALUE (NewVarDig), VAR_DIG_VALUE (VarDig),
> VarDig->DigestSize);
> +
> +    VarSize  =  VARIABLE_HEADER_SIZE (NewGlobal->Flags.Auth);
> +    VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
> +    VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
> +    VarSize  = HEADER_ALIGN (VarSize);
> +
> +    NewCacheIndex = GET_ADRS (AllocateZeroPool (VarSize));
> +    if (GET_BUFR (NewCacheIndex) == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    CopyMem (GET_BUFR (NewCacheIndex), GET_BUFR (VarDig->CacheIndex),
> VarSize);
> +    NewVarDig->CacheIndex     = NewCacheIndex;
> +    NewVarDig->Flags.Freeable = TRUE;
> +
> +    for (Index = 0; Index < UnprotectedVarIndexMax; ++Index) {
> +      if (OldGlobal->Unprotected[Index] == VAR_DIG_ADR (VarDig)) {
> +        NewGlobal->Unprotected[Index] = VAR_DIG_ADR (NewVarDig);
> +      }
> +    }
> +
> +    InsertVariableDigestNode (NewGlobal, NewVarDig, NULL);
> +
> +    VarDig = VAR_DIG_NEXT (VarDig);
> +  }
> +
> +  return Status;
> +}
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon
> .c
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon
> .c
> new file mode 100644
> index 000000000000..8472fc8a33c7
> --- /dev/null
> +++
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon
> .c
> @@ -0,0 +1,967 @@
> +/** @file
> +  Implemention of ProtectedVariableLib for SMM variable services.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Uefi.h>
> +
> +#include "Guid/SmmVariableCommon.h"
> +
> +#include "Library/MmServicesTableLib.h"
> +#include "Library/MemoryAllocationLib.h"
> +#include <Library/HobLib.h>
> +
> +#include "ProtectedVariableInternal.h"
> +
> +/**
> +
> +  Get context and/or global data structure used to process protected variable.
> +
> +  @param[out]   Global      Pointer to global configuration data.
> +
> +  @retval EFI_SUCCESS         Get requested structure successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableGlobal (
> +  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
> +  )
> +{
> +  if (Global != NULL) {
> +    mProtectedVariableGlobal.ContextIn = GET_ADRS (&mVariableContextIn);
> +    *Global                            = &mProtectedVariableGlobal;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Encrypt given variable data and generate new HMAC value against it.
> +
> +  @param[in]      Global          Pointer to global configuration data.
> +  @param[in,out]  NewVarInfo      Pointer to buffer of new variable data.
> +  @param[in,out]  NewVarDig       Pointer to buffer of new variable digest.
> +
> +  @retval EFI_SUCCESS           No error occurred during the encryption and HMC
> calculation.
> +  @retval EFI_ABORTED           Failed to do HMC calculation.
> +  @return EFI_OUT_OF_RESOURCES  Not enough resource to calculate HMC
> value.
> +  @return EFI_NOT_FOUND         The MetaDataHmacVar was not found in
> storage.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +UpdateVariableInternal (
> +  IN      PROTECTED_VARIABLE_GLOBAL  *Global,
> +  IN  OUT PROTECTED_VARIABLE_INFO    *NewVarInfo,
> +  IN  OUT VARIABLE_DIGEST            *NewVarDig
> +  )
> +{
> +  EFI_STATUS               Status;
> +  PROTECTED_VARIABLE_INFO  CachedVarInfo;
> +  VOID                     *Buffer;
> +  UINTN                    VarSize;
> +
> +  if ((NewVarInfo == NULL) || (NewVarDig == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // If Add or update variable, encrypt new data first.
> +  //
> +  if (NewVarInfo->Buffer != NULL) {
> +    Status = EFI_UNSUPPORTED;
> +
> +    if (NewVarDig->Flags.Encrypted) {
> +      NewVarInfo->PlainData          = NULL;
> +      NewVarInfo->PlainDataSize      = 0;
> +      NewVarInfo->CipherData         = NULL;
> +      NewVarInfo->CipherDataSize     = 0;
> +      NewVarInfo->Key                = Global->RootKey;
> +      NewVarInfo->KeySize            = sizeof (Global->RootKey);
> +      NewVarInfo->Header.Attributes &= (~EFI_VARIABLE_APPEND_WRITE);
> +      Status                         = EncryptVariable (NewVarInfo);
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // Update new data size in variable header.
> +        //
> +        SET_VARIABLE_DATA_SIZE (NewVarInfo, NewVarInfo->CipherDataSize);
> +      } else if (Status != EFI_UNSUPPORTED) {
> +        ASSERT (FALSE);
> +        return Status;
> +      }
> +    }
> +
> +    if (Status == EFI_UNSUPPORTED) {
> +      NewVarInfo->CipherData     = NewVarInfo->Header.Data;
> +      NewVarInfo->CipherDataSize = (UINT32)NewVarInfo->Header.DataSize;
> +      NewVarInfo->PlainData      = NULL;
> +      NewVarInfo->PlainDataSize  = 0;
> +    }
> +  } else {
> +    NewVarInfo->CipherData     = NULL;
> +    NewVarInfo->CipherDataSize = 0;
> +    NewVarInfo->PlainData      = NULL;
> +    NewVarInfo->PlainDataSize  = 0;
> +  }
> +
> +  if (NewVarDig->CacheIndex != 0) {
> +    //
> +    // Update the cached copy.
> +    //
> +    ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo));
> +    CachedVarInfo.Buffer     = GET_BUFR (NewVarDig->CacheIndex);
> +    CachedVarInfo.StoreIndex = VAR_INDEX_INVALID;
> +    CachedVarInfo.Flags.Auth = NewVarInfo->Flags.Auth;
> +
> +    Status = GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    if ((CachedVarInfo.Header.DataSize != 0) && (NewVarInfo->CipherDataSize >
> CachedVarInfo.Header.DataSize)) {
> +      //
> +      // allocate new VarInfo buffer that is of greater CipherDataSize
> +      //
> +      VarSize  =  VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth);
> +      VarSize += NewVarInfo->Header.NameSize + GET_PAD_SIZE (NewVarInfo-
> >Header.NameSize);
> +      VarSize += NewVarInfo->CipherDataSize + GET_PAD_SIZE (NewVarInfo-
> >CipherDataSize);
> +      VarSize  = HEADER_ALIGN (VarSize);
> +      Buffer   = AllocateZeroPool (VarSize);
> +      if (Buffer != NULL) {
> +        VarSize  =  VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth);
> +        VarSize += CachedVarInfo.Header.NameSize + GET_PAD_SIZE
> (CachedVarInfo.Header.NameSize);
> +        VarSize += CachedVarInfo.Header.DataSize + GET_PAD_SIZE
> (CachedVarInfo.DataSize);
> +        VarSize  = HEADER_ALIGN (VarSize);
> +
> +        CopyMem (
> +          Buffer,
> +          CachedVarInfo.Buffer,
> +          VarSize
> +          );
> +
> +        FreePool (CachedVarInfo.Buffer);
> +
> +        //
> +        // Update the cached copy.
> +        //
> +        ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo));
> +        CachedVarInfo.Buffer     = Buffer;
> +        CachedVarInfo.StoreIndex = VAR_INDEX_INVALID;
> +        CachedVarInfo.Flags.Auth = NewVarInfo->Flags.Auth;
> +        Status                   = GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo);
> +        ASSERT_EFI_ERROR (Status);
> +        NewVarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
> +      }
> +    }
> +
> +    CopyMem (
> +      CachedVarInfo.Header.Data,
> +      NewVarInfo->CipherData,
> +      NewVarInfo->CipherDataSize
> +      );
> +    SET_VARIABLE_DATA_SIZE (&CachedVarInfo, NewVarInfo->CipherDataSize);
> +
> +    NewVarDig->State    = VAR_ADDED;
> +    NewVarDig->DataSize = NewVarInfo->CipherDataSize;
> +
> +    if (NewVarInfo->PlainDataSize > 0) {
> +      NewVarDig->PlainDataSize = NewVarInfo->PlainDataSize;
> +    } else {
> +      NewVarDig->PlainDataSize = NewVarDig->DataSize;
> +    }
> +
> +    //
> +    // (Re-)Calculate the hash of the variable.
> +    //
> +    if (NewVarDig->Flags.Protected) {
> +      GetVariableDigest (Global, NewVarInfo, VAR_DIG_VALUE (NewVarDig));
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Fix state of MetaDataHmacVar on NV variable storage, if there's failure at
> +  last boot during updating variable.
> +
> +  This must be done before the first writing of variable in current boot,
> +  including storage reclaim.
> +
> +  @retval EFI_UNSUPPORTED        Updating NV variable storage is not
> supported.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough resource to complete the
> operation.
> +  @retval EFI_SUCCESS            Variable store was successfully updated.
> +
> +**/
> +EFI_STATUS
> +FixupHmacVariable (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_INFO        HmacVarInfo;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  VARIABLE_DIGEST                *VarDig;
> +  UINTN                          Index;
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  if (Global->Flags.WriteReady) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  ContextIn = GET_CNTX (Global);
> +
> +  //
> +  // Delete invalid MetaDataHmacVar.
> +  //
> +  for (Index = 0; Index <= IndexHmacAdded; ++Index) {
> +    if (Global->Unprotected[Index] == VAR_INDEX_INVALID) {
> +      continue;
> +    }
> +
> +    VarDig = VAR_DIG_PTR (Global->Unprotected[Index]);
> +    if (VarDig->Flags.Valid) {
> +      continue;
> +    }
> +
> +    ZeroMem ((VOID *)&HmacVarInfo, sizeof (HmacVarInfo));
> +    HmacVarInfo.StoreIndex = VarDig->StoreIndex;
> +    HmacVarInfo.Flags.Auth = VarDig->Flags.Auth;
> +
> +    Status = ContextIn->GetVariableInfo (&HmacVarInfo);
> +    if (!EFI_ERROR (Status) && (HmacVarInfo.Buffer != NULL)) {
> +      HmacVarInfo.Buffer->State &= VAR_DELETED;
> +      Status                     = ContextIn->UpdateVariableStore (
> +                                                &HmacVarInfo,
> +                                                OFFSET_OF (VARIABLE_HEADER, State),
> +                                                sizeof (HmacVarInfo.Buffer->State),
> +                                                &HmacVarInfo.Buffer->State
> +                                                );
> +      if (EFI_ERROR (Status)) {
> +        ASSERT_EFI_ERROR (Status);
> +        return Status;
> +      }
> +    }
> +
> +    //
> +    // Release the resource and update related states.
> +    //
> +    VarDig->State &= VAR_DELETED;
> +    RemoveVariableDigestNode (Global, VarDig, FALSE);
> +    Global->Unprotected[Index] = VAR_INDEX_INVALID;
> +  }
> +
> +  //
> +  // There should be no MetaDataHmacVar if in variable storage recovery mode.
> +  //
> +  if (Global->Flags.RecoveryMode) {
> +    ASSERT (Global->Unprotected[IndexHmacAdded] == VAR_INDEX_INVALID);
> +    ASSERT (Global->Unprotected[IndexHmacInDel] == VAR_INDEX_INVALID);
> +  }
> +
> +  Global->Flags.WriteReady = TRUE;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Prepare for variable update.
> +
> +  This is needed only once during current boot to mitigate replay attack. Its
> +  major job is to advance RPMC (Replay Protected Monotonic Counter).
> +
> +  @retval EFI_SUCCESS             Variable is ready to update hereafter.
> +  @retval EFI_UNSUPPORTED         Updating variable is not supported.
> +  @retval EFI_DEVICE_ERROR        Error in advancing RPMC.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +
> +  (VOID)GetProtectedVariableGlobal (&Global);
> +  ContextIn = GET_CNTX (Global);
> +
> +  //
> +  // HmacVarInfo should be here
> +  //
> +  if (Global->Flags.RecoveryMode) {
> +    //
> +    // Flush default variables to variable storage if in variable recovery mode.
> +    //
> +    Status = ContextIn->UpdateVariableStore (NULL, 0, (UINT32)-1, NULL);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return Status;
> +    }
> +  } else {
> +    ContextIn = GET_CNTX (Global);
> +
> +    //
> +    // Fix any wrong MetaDataHmacVar information before adding new one.
> +    //
> +    Status = FixupHmacVariable ();
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return Status;
> +    }
> +
> +    if (!Global->Flags.WriteReady) {
> +      return EFI_NOT_READY;
> +    }
> +
> +    //
> +    // Refresh MetaDataHmacVar with RPMC2 by 1 in each boot before any
> variable
> +    // update,  by deleting (attr == 0 && datasize == 0) the old one.
> +    //
> +    ZeroMem (&VarInfo, sizeof (PROTECTED_VARIABLE_INFO));  // Zero attr &
> datasize
> +
> +    VarInfo.Flags.Auth          = Global->Flags.Auth;
> +    VarInfo.Header.VariableName = METADATA_HMAC_VARIABLE_NAME;
> +    VarInfo.Header.NameSize     = METADATA_HMAC_VARIABLE_NAME_SIZE;
> +    VarInfo.Header.VendorGuid   = &METADATA_HMAC_VARIABLE_GUID;
> +
> +    //
> +    // Pretend to delete MetaDataHmacVar.
> +    //
> +    Status = ContextIn->UpdateVariable (&VarInfo.Header);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return Status;
> +    }
> +  }
> +
> +  mProtectedVariableGlobal.Flags.WriteInit = TRUE;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Update a variable with protection provided by this library.
> +
> +  If variable encryption is employed, the new variable data will be encrypted
> +  before being written to NV variable storage.
> +
> +  A special variable, called "MetaDataHmacVar", will always be updated along
> +  with variable being updated to reflect the changes (HMAC value) of all
> +  protected valid variables. The only exceptions, currently, is variable
> +  variable "VarErrorLog".
> +
> +  The buffer passed by NewVariable must be double of maximum variable size,
> +  which allows to pass the "MetaDataHmacVar" back to caller along with
> encrypted
> +  new variable data, if any. This can make sure the new variable data and
> +  "MetaDataHmacVar" can be written at almost the same time to reduce the
> chance
> +  of compromising the integrity.
> +
> +  If *NewVariableSize is zero, it means to delete variable passed by CurrVariable
> +  and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in such
> +  case because of less variables in storage. NewVariable should be always
> passed
> +  in to convey new "MetaDataHmacVar" back.
> +
> +  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
> +                                      adding a new variable.
> +  @param[in]      CurrVariableInDel   In-delete-transition copy of updating
> variable.
> +  @param[in,out]  NewVariable         Buffer of new variable data.
> +                                      Buffer of "MetaDataHmacVar" and new
> +                                      variable (encrypted).
> +  @param[in,out]  NewVariableSize     Size of NewVariable.
> +                                      Size of (encrypted) NewVariable and
> +                                      "MetaDataHmacVar".
> +
> +  @retval EFI_SUCCESS             The variable is updated with protection
> successfully.
> +  @retval EFI_INVALID_PARAMETER   NewVariable is NULL.
> +  @retval EFI_NOT_FOUND           Information missing to finish the operation.
> +  @retval EFI_ABORTED             Failed to encrypt variable or calculate HMAC.
> +  @retval EFI_NOT_READY           The RPMC device is not yet initialized.
> +  @retval EFI_DEVICE_ERROR        The RPMC device has error in updating.
> +  @retval EFI_ACCESS_DENIED       The given variable is not allowed to update.
> +                                  Currently this only happens on updating
> +                                  "MetaDataHmacVar" from code outside of this
> +                                  library.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> +  IN  OUT VARIABLE_HEADER  *CurrVariable,
> +  IN      VARIABLE_HEADER  *CurrVariableInDel,
> +  IN  OUT VARIABLE_HEADER  *NewVariable,
> +  IN  OUT UINTN            *NewVariableSize
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +  VARIABLE_DIGEST                *VarDig;
> +  VARIABLE_DIGEST                *CurrVarDig;
> +  VARIABLE_DIGEST                *NewVarDig;
> +  PROTECTED_VARIABLE_INFO        NewVarInfo;
> +  PROTECTED_VARIABLE_INFO        NewHmacVarInfo;
> +  UINTN                          VarSize;
> +  UINT64                         UnprotectedVarIndex;
> +
> +  //
> +  // Advance RPMC
> +  //
> +  Status = IncrementMonotonicCounter (RPMC_COUNTER_1);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Buffer for new variable is always needed, even this function is called to
> +  // delete an existing one, because we need to pass the MetaDataHmacVar
> back
> +  // which will be updated upon each variable addition or deletion.
> +  //
> +  if ((NewVariable == NULL) || (NewVariableSize == NULL)) {
> +    ASSERT (NewVariable != NULL);
> +    ASSERT (NewVariableSize != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  ASSERT_EFI_ERROR (Status);
> +  ContextIn = GET_CNTX (Global);
> +
> +  if (!Global->Flags.WriteReady && !Global->Flags.WriteInit) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  VarSize             = 0;
> +  CurrVarDig          = NULL;
> +  NewVarDig           = NULL;
> +  UnprotectedVarIndex = VAR_INDEX_INVALID;
> +
> +  //
> +  // Check existing copy of the same variable.
> +  //
> +  if (CurrVariable != NULL) {
> +    //
> +    // Find local cached copy, if possible.
> +    //
> +    ZeroMem (&VarInfo, sizeof (VarInfo));
> +    VarInfo.Buffer     = CurrVariable;
> +    VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +    VarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +    Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
> +    ASSERT_EFI_ERROR (Status);
> +
> +    UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global, &VarInfo);
> +    if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
> +      CurrVarDig = VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]);
> +    } else {
> +      CurrVarDig = FindVariableInternal (Global, &VarInfo, FALSE);
> +    }
> +
> +    ASSERT (CurrVarDig != NULL);
> +    CurrVarDig->State &= VAR_DELETED;
> +  }
> +
> +  //
> +  // The old copy of the variable might haven't been deleted completely.
> +  //
> +  if (CurrVariableInDel != NULL) {
> +    //
> +    // Find local cached copy, if possible.
> +    //
> +    ZeroMem (&VarInfo, sizeof (VarInfo));
> +    VarInfo.Buffer     = CurrVariableInDel;
> +    VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +    VarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +    Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
> +    ASSERT_EFI_ERROR (Status);
> +
> +    if (UnprotectedVarIndex == VAR_INDEX_INVALID) {
> +      UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global,
> &VarInfo);
> +    }
> +
> +    if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
> +      VarDig = VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]);
> +    } else {
> +      VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
> +    }
> +
> +    if ((VarDig != NULL) && (VAR_DIG_ADR (VarDig) != VAR_INDEX_INVALID)) {
> +      VarDig->State &= VAR_DELETED;
> +
> +      //
> +      // Just need one node for the same variable. So remove the one
> +      // in-del-transition.
> +      //
> +      if ((CurrVarDig != NULL) && (VarDig != CurrVarDig)) {
> +        RemoveVariableDigestNode (Global, VarDig, TRUE);
> +      } else {
> +        CurrVarDig = VarDig;  // Reuse the one in-del-transition.
> +      }
> +    }
> +  }
> +
> +  //
> +  // New data of the variable or new variable to be added.
> +  //
> +  if (NewVariable != NULL) {
> +    //
> +    // Completely new variable?
> +    //
> +    if (UnprotectedVarIndex == VAR_INDEX_INVALID) {
> +      ZeroMem (&VarInfo, sizeof (VarInfo));
> +      VarInfo.Buffer     = NewVariable;
> +      VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +      VarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +      Status = ContextIn->GetVariableInfo (&VarInfo); // Retrieve the name/guid
> +      ASSERT_EFI_ERROR (Status);
> +
> +      UnprotectedVarIndex = CheckKnownUnprotectedVariable (Global,
> &VarInfo);
> +    }
> +  }
> +
> +  //
> +  // Reserve space for MetaDataHmacVar (before the new variable so
> +  // that it can be written first).
> +  //
> +  ZeroMem (&NewVarInfo, sizeof (NewVarInfo));
> +  ZeroMem (&NewHmacVarInfo, sizeof (NewHmacVarInfo));
> +
> +  //
> +  // Put the MetaDataHmacVar at the beginning of buffer.
> +  //
> +  NewHmacVarInfo.Buffer = NewVariable;
> +
> +  if (*NewVariableSize == 0) {
> +    //
> +    // Delete variable (but not MetaDataHmacVar)
> +    //
> +    if (  (UnprotectedVarIndex != IndexHmacAdded)
> +       && (UnprotectedVarIndex != IndexHmacInDel))
> +    {
> +      RemoveVariableDigestNode (Global, CurrVarDig, TRUE);
> +    }
> +
> +    NewVarInfo.Buffer = NULL;
> +  } else if (UnprotectedVarIndex >= IndexPlatformVar) {
> +    //
> +    // Add/update variable. Move new variable data to be after
> MetaDataHmacVar.
> +    //
> +    // TRICK: New MetaDataHmacVar will be put at the beginning of buffer
> +    //        for new variable so that they can be written into non-volatile
> +    //        variable storage in one call. This can avoid writing one variable
> +    //        (NewHmacVarInfo) in the middle of writing another variable
> +    //        (NewVarInfo), which will need two calls and introduce extra
> +    //        complexities (from temp variable buffer reservation to variable
> +    //        space reclaim, etc.) in current implementation of variable
> +    //        services. The caller must make sure there's enough space in
> +    //        variable buffer (i.e. at least 2 * MaxVariableSize).
> +    //
> +    NewVarInfo.Buffer = (VARIABLE_HEADER *)((UINTN)NewVariable
> +                                            + GetMetaDataHmacVarSize (Global->Flags.Auth));
> +    CopyMem ((VOID *)NewVarInfo.Buffer, (VOID *)NewVariable,
> *NewVariableSize);
> +
> +    NewVarInfo.StoreIndex = VAR_INDEX_INVALID;   // Skip offset calculation
> (it's new one)
> +    NewVarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +    Status = ContextIn->GetVariableInfo (&NewVarInfo);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    if (CurrVarDig != NULL) {
> +      //
> +      // Update existing variable. Re-use the node.
> +      //
> +      NewVarDig = CurrVarDig;
> +    } else {
> +      //
> +      // Add new variable.
> +      //
> +      NewVarDig = CreateVariableDigestNode (
> +                    NewVarInfo.Header.VariableName,
> +                    NewVarInfo.Header.VendorGuid,
> +                    (UINT16)NewVarInfo.Header.NameSize,
> +                    (UINT32)NewVarInfo.Header.DataSize,
> +                    NewVarInfo.Flags.Auth,
> +                    Global
> +                    );
> +      if (NewVarDig == NULL) {
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      NewVarDig->Attributes = NewVarInfo.Header.Attributes;
> +      if (UnprotectedVarIndex < UnprotectedVarIndexMax) {
> +        NewVarDig->Flags.Protected               = FALSE;
> +        NewVarDig->Flags.Encrypted               = FALSE;
> +        Global->Unprotected[UnprotectedVarIndex] = VAR_DIG_ADR (NewVarDig);
> +      }
> +
> +      //
> +      // copy new variable to CacheIndex
> +      //
> +      VarSize  =  VARIABLE_HEADER_SIZE (NewVarInfo.Flags.Auth);
> +      VarSize += NewVarInfo.Header.NameSize + GET_PAD_SIZE
> (NewVarInfo.Header.NameSize);
> +      VarSize += NewVarInfo.Header.DataSize + GET_PAD_SIZE
> (NewVarInfo.Header.DataSize);
> +      VarSize  = HEADER_ALIGN (VarSize);
> +      CopyMem (GET_BUFR (NewVarDig->CacheIndex), GET_BUFR
> (NewVarInfo.Buffer), VarSize);
> +      InsertVariableDigestNode (Global, NewVarDig, NULL);
> +    }
> +  }
> +
> +  if (  (UnprotectedVarIndex == IndexHmacAdded)
> +     || (UnprotectedVarIndex == IndexHmacInDel))
> +  {
> +    //
> +    // MetaDataHmacVar should be managed only by this library. It's not
> +    // supposed to be updated by external users of variable service. The only
> +    // exception is that deleting it (not really delete but refresh the HMAC
> +    // value against RPMC+1) is allowed before WriteInit, as a way to always
> +    // increment RPMC once in current boot before any variable updates.
> +    //
> +    if ((NewVarInfo.Buffer != NULL) || Global->Flags.WriteInit) {
> +      return EFI_ACCESS_DENIED;
> +    }
> +  } else {
> +    //
> +    // Do encryption, if enabled.
> +    //
> +    if ((NewVarDig != NULL) && (NewVarInfo.Buffer != NULL)) {
> +      Status = UpdateVariableInternal (Global, &NewVarInfo, NewVarDig);
> +      if (EFI_ERROR (Status)) {
> +        ASSERT_EFI_ERROR (Status);
> +        return Status;
> +      }
> +    }
> +  }
> +
> +  //
> +  // Refresh MetaDataHmacVar.
> +  //
> +  Status = RefreshVariableMetadataHmac (Global, NULL, &NewHmacVarInfo);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  //
> +  // Return size for both MetaDataHmacVar and added/updated one.
> +  //
> +  VarSize          = VARIABLE_SIZE (&NewHmacVarInfo);
> +  *NewVariableSize = HEADER_ALIGN (VarSize);
> +  if (NewVarInfo.Buffer != NULL) {
> +    VarSize = VARIABLE_SIZE (&NewVarInfo);
> +    VarSize = HEADER_ALIGN (VarSize);
> +
> +    if (VarSize > GET_CNTX (Global)->MaxVariableSize) {
> +      return EFI_BAD_BUFFER_SIZE;
> +    }
> +
> +    *NewVariableSize += VarSize;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Finalize a variable updating after it's written to NV variable storage
> +  successfully.
> +
> +  This usually includes works like increasing RPMC, synchronizing local cache,
> +  updating new position of "MetaDataHmacVar", deleting old copy of
> "MetaDataHmacVar"
> +  completely, etc.
> +
> +  @param[in]      NewVariable       Buffer of new variables and
> MetaDataHmacVar.
> +  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
> +  @param[in]      StoreIndex        StoreIndex to NV variable storage from where
> the new
> +                                    variable and MetaDataHmacVar have been written.
> +
> +  @retval EFI_SUCCESS         No problem in winding up the variable write
> operation.
> +  @retval Others              Failed to updating state of old copy of updated
> +                              variable, or failed to increase RPMC, etc.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> +  IN  VARIABLE_HEADER  *NewVariable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  PROTECTED_VARIABLE_INFO        VarInfo;
> +  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn;
> +  PROTECTED_VARIABLE_GLOBAL      *Global;
> +  UNPROTECTED_VARIABLE_INDEX     Index;
> +  VARIABLE_DIGEST                *VarDig;
> +  VOID                           *Buffer;
> +  UINTN                          VarSize;
> +  UINTN                          NewVarSize;
> +
> +  Status = GetProtectedVariableGlobal (&Global);
> +  ASSERT_EFI_ERROR (Status);
> +  ContextIn = GET_CNTX (Global);
> +
> +  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
> +  VarInfo.Buffer     = NewVariable;
> +  VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +  VarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +  Status = ContextIn->GetVariableInfo (&VarInfo);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Index = CheckKnownUnprotectedVariable (Global, &VarInfo);
> +  if (Index < UnprotectedVarIndexMax) {
> +    VarDig = VAR_DIG_PTR (Global->Unprotected[Index]);
> +  } else {
> +    VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
> +  }
> +
> +  if (Index == IndexHmacAdded) {
> +    //
> +    // Advance the RPMC to let it match new MetaDataHmacVar.
> +    //
> +    Status = IncrementMonotonicCounter (RPMC_COUNTER_2);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    if ((VarDig->StoreIndex != VAR_INDEX_INVALID) && (VarDig->State !=
> VAR_ADDED)) {
> +      ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
> +      VarInfo.StoreIndex = VarDig->StoreIndex;  // Still point to old copy
> +      VarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +      //
> +      // Delete variable completely.
> +      //
> +      Status = ContextIn->GetVariableInfo (&VarInfo);
> +      ASSERT_EFI_ERROR (Status);
> +
> +      if (  (VarInfo.Buffer->State == VAR_ADDED)
> +         || (VarInfo.Buffer->State == (VAR_ADDED &
> VAR_IN_DELETED_TRANSITION)))
> +      {
> +        VarInfo.Buffer->State &= VAR_DELETED;
> +        Status                 = ContextIn->UpdateVariableStore (
> +                                              &VarInfo,
> +                                              OFFSET_OF (VARIABLE_HEADER, State),
> +                                              sizeof (VarInfo.Buffer->State),
> +                                              &VarInfo.Buffer->State
> +                                              );
> +        if (EFI_ERROR (Status)) {
> +          ASSERT_EFI_ERROR (Status);
> +          return Status;
> +        }
> +      }
> +    }
> +  }
> +
> +  VarDig->StoreIndex = StoreIndex;
> +  VarDig->State      = VAR_ADDED;
> +
> +  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
> +  VarInfo.Buffer     = NULL;
> +  VarInfo.StoreIndex = VarDig->StoreIndex;
> +  VarInfo.Flags.Auth = Global->Flags.Auth;
> +  Status             = ContextIn->GetVariableInfo (&VarInfo);
> +
> +  //
> +  // Check if cache pool need re-allocation due to variable size increase
> +  //
> +  VarSize  =  VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
> +  VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
> +  VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
> +  VarSize  = HEADER_ALIGN (VarSize);
> +
> +  NewVarSize  =  VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth);
> +  NewVarSize += VarInfo.Header.NameSize + GET_PAD_SIZE
> (VarInfo.Header.NameSize);
> +  NewVarSize += VarInfo.Header.DataSize + GET_PAD_SIZE
> (VarInfo.Header.DataSize);
> +  NewVarSize  = HEADER_ALIGN (NewVarSize);
> +
> +  if (VarSize < NewVarSize) {
> +    if (VarDig->Flags.Freeable == TRUE) {
> +      FreePool (GET_BUFR (VarDig->CacheIndex));
> +    }
> +
> +    Buffer = AllocatePool (NewVarSize);
> +    if (Buffer != NULL) {
> +      VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
> +    } else {
> +      ASSERT (FALSE);
> +      return EFI_ABORTED;
> +    }
> +  }
> +
> +  //
> +  // Update cached copy.
> +  //
> +  CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize);
> +
> +  //
> +  // Check if there is consecutive variable as part of the write or
> +  // is it just the MetaDataHmacVar variable
> +  //
> +  if (NewVarSize < VariableSize) {
> +    //
> +    // Advance to consecutive Variable
> +    //
> +    NewVariable = GET_BUFR (GET_ADRS (NewVariable) + NewVarSize);
> +
> +    //
> +    // Update the StoreIndex of consecutive Variable
> +    //
> +    ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
> +    VarInfo.Buffer     = NULL;
> +    VarInfo.StoreIndex = VarDig->StoreIndex;
> +    VarInfo.Flags.Auth = Global->Flags.Auth;
> +    Status             = ContextIn->GetNextVariableInfo (&VarInfo);
> +    StoreIndex         = VarInfo.StoreIndex;
> +
> +    //
> +    // The new StoreIndex does not exist in the variable digest.
> +    // It is yet to be updated.
> +    // Therefore, find variable by Name & Guid instead.
> +    //
> +    VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +    VarDig             = FindVariableInternal (Global, &VarInfo, FALSE);
> +
> +    //
> +    // Check if cache pool need re-allocation due to variable size increase
> +    //
> +    VarSize  =  VARIABLE_HEADER_SIZE (VarDig->Flags.Auth);
> +    VarSize += VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize);
> +    VarSize += VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize);
> +    VarSize  = HEADER_ALIGN (VarSize);
> +
> +    NewVarSize  =  VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth);
> +    NewVarSize += VarInfo.Header.NameSize + GET_PAD_SIZE
> (VarInfo.Header.NameSize);
> +    NewVarSize += VarInfo.Header.DataSize + GET_PAD_SIZE
> (VarInfo.Header.DataSize);
> +    NewVarSize  = HEADER_ALIGN (NewVarSize);
> +
> +    if (VarSize < NewVarSize) {
> +      if (VarDig->Flags.Freeable == TRUE) {
> +        FreePool (GET_BUFR (VarDig->CacheIndex));
> +      }
> +
> +      Buffer = AllocatePool (NewVarSize);
> +      if (Buffer != NULL) {
> +        VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
> +      } else {
> +        ASSERT (FALSE);
> +        return EFI_ABORTED;
> +      }
> +    }
> +
> +    //
> +    // Update cached copy.
> +    //
> +    CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize);
> +    VarDig->StoreIndex = StoreIndex;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Refresh variable information changed by variable service.
> +
> +  @param[in]  Variable         Pointer to buffer of the updated variable.
> +  @param[in]  VariableSize     Size of variable pointed by Variable.
> +  @param[in]  StoreIndex       New index of the variable in store.
> +  @param[in]  RefreshData      Flag to indicate if the variable has been updated.
> +
> +  @return EFI_SUCCESS     No error occurred in updating.
> +  @return EFI_NOT_FOUND   The given variable was not found in
> +                          ProtectedVariableLib.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibRefresh (
> +  IN  VARIABLE_HEADER  *Variable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex,
> +  IN  BOOLEAN          RefreshData
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  PROTECTED_VARIABLE_INFO    VarInfo;
> +  PROTECTED_VARIABLE_GLOBAL  *Global;
> +  VARIABLE_DIGEST            *VarDig;
> +
> +  (VOID)GetProtectedVariableGlobal (&Global);
> +
> +  ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo));
> +  VarInfo.Buffer     = Variable;
> +  VarInfo.StoreIndex = VAR_INDEX_INVALID;
> +  VarInfo.Flags.Auth = Global->Flags.Auth;
> +
> +  Status = GET_CNTX (Global)->GetVariableInfo (&VarInfo);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  VarDig = FindVariableInternal (Global, &VarInfo, FALSE);
> +  if (VarDig == NULL) {
> +    ASSERT (VarDig != NULL);
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (StoreIndex != VAR_INDEX_INVALID) {
> +    VarDig->StoreIndex = StoreIndex;
> +  }
> +
> +  if (RefreshData) {
> +    if (VarDig->CacheIndex == VAR_INDEX_INVALID) {
> +      VarDig->CacheIndex = (EFI_PHYSICAL_ADDRESS)(UINTN)
> +                           AllocatePool (MAX_VARIABLE_SIZE);
> +    }
> +
> +    CopyMem (GET_BUFR (VarDig->CacheIndex), Variable, VariableSize);
> +  }
> +
> +  //
> +  // Information should stay the same other than following ones.
> +  //
> +  VarDig->State    = VarInfo.Header.State;
> +  VarDig->DataSize = (UINT32)VarInfo.Header.DataSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Determine if the variable is the HMAC variable
> +
> +  @param VariableName   Pointer to variable name.
> +
> +  @return TRUE      Variable is HMAC variable
> +  @return FALSE     Variable is not HMAC variable
> +
> +**/
> +BOOLEAN
> +ProtectedVariableLibIsHmac (
> +  IN CHAR16  *VariableName
> +  )
> +{
> +  INTN  Result;
> +
> +  Result = StrnCmp (
> +             METADATA_HMAC_VARIABLE_NAME,
> +             VariableName,
> +             METADATA_HMAC_VARIABLE_NAME_SIZE
> +             );
> +
> +  if (Result == 0) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> diff --git
> a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> new file mode 100644
> index 000000000000..4591d1cd59e5
> --- /dev/null
> +++
> b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> @@ -0,0 +1,233 @@
> +/** @file
> +  Implemention of ProtectedVariableLib for BootService/Runtime use cases.
> +
> +Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Uefi.h>
> +
> +#include "Library/MemoryAllocationLib.h"
> +#include "Library/UefiBootServicesTableLib.h"
> +#include "Library/UefiRuntimeLib.h"
> +#include "ProtectedVariableInternal.h"
> +
> +EFI_EVENT  mVaChangeEvent = NULL;
> +
> +PROTECTED_VARIABLE_CONTEXT_IN  mRtVariableContextIn = {
> +  PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION,
> +  sizeof (PROTECTED_VARIABLE_CONTEXT_IN),
> +  0,
> +  FromRuntimeModule,
> +  NULL,
> +  NULL,
> +  NULL,
> +  NULL,
> +  NULL
> +};
> +
> +PROTECTED_VARIABLE_GLOBAL  mRtProtectedVariableGlobal = {
> +  PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION,
> +  sizeof (PROTECTED_VARIABLE_GLOBAL),
> +  { 0 },
> +  { 0 },
> +  0,
> +  0,
> +  0,
> +  0,
> +  0,
> +  0,
> +  { 0,                                          0,  0 },
> +  0,
> +  0,
> +  { 0,                                          0,  0, 0, 0, 0}
> +};
> +
> +/**
> +
> +  Get global data structure used to process protected variable.
> +
> +  @param[out]   Global      Pointer to global configuration data.
> +
> +  @retval EFI_SUCCESS         Get requested structure successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetProtectedVariableGlobal (
> +  OUT PROTECTED_VARIABLE_GLOBAL  **Global OPTIONAL
> +  )
> +{
> +  if (Global != NULL) {
> +    mRtProtectedVariableGlobal.ContextIn = GET_ADRS
> (&mRtVariableContextIn);
> +    *Global                              = &mRtProtectedVariableGlobal;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  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
> +VirtualAddressChangeEvent (
> +  IN EFI_EVENT  Event,
> +  IN VOID       *Context
> +  )
> +{
> +  if (mRtVariableContextIn.FindVariableSmm != NULL) {
> +    EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.FindVariableSmm);
> +  }
> +
> +  if (mRtVariableContextIn.GetVariableInfo != NULL) {
> +    EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.GetVariableInfo);
> +  }
> +
> +  if (mRtVariableContextIn.GetNextVariableInfo != NULL) {
> +    EfiConvertPointer (0x0, (VOID
> **)&mRtVariableContextIn.GetNextVariableInfo);
> +  }
> +
> +  if (mRtVariableContextIn.UpdateVariableStore != NULL) {
> +    EfiConvertPointer (0x0, (VOID
> **)&mRtVariableContextIn.UpdateVariableStore);
> +  }
> +
> +  EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn);
> +  if (mRtProtectedVariableGlobal.VariableCache != 0) {
> +    EfiConvertPointer (0x0, (VOID
> **)&mRtProtectedVariableGlobal.VariableCache);
> +  }
> +
> +  EfiConvertPointer (0x0, (VOID **)&mRtProtectedVariableGlobal);
> +}
> +
> +/**
> +
> +  Initialization for protected variable services.
> +
> +  If this initialization failed upon any error, the whole variable services
> +  should not be used.  A system reset might be needed to re-construct NV
> +  variable storage to be the default state.
> +
> +  @param[in]  ContextIn   Pointer to variable service context needed by
> +                          protected variable.
> +
> +  @retval EFI_SUCCESS               Protected variable services are ready.
> +  @retval EFI_INVALID_PARAMETER     If ContextIn == NULL or something
> missing or
> +                                    mismatching in the content in ContextIn.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibInitialize (
> +  IN  PROTECTED_VARIABLE_CONTEXT_IN  *ContextIn
> +  )
> +{
> +  if (  (ContextIn == NULL)
> +     || (ContextIn->StructVersion !=
> PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION)
> +     || (ContextIn->FindVariableSmm == NULL)
> +     || (ContextIn->GetVariableInfo == NULL))
> +  {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  CopyMem (&mRtVariableContextIn, ContextIn, sizeof
> (mRtVariableContextIn));
> +
> +  //
> +  // Register the event to convert the pointer for runtime.
> +  //
> +  gBS->CreateEventEx (
> +         EVT_NOTIFY_SIGNAL,
> +         TPL_NOTIFY,
> +         VirtualAddressChangeEvent,
> +         NULL,
> +         &gEfiEventVirtualAddressChangeGuid,
> +         &mVaChangeEvent
> +         );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Prepare for variable update.
> +
> +  Not supported in DXE phase.
> +
> +  @retval EFI_UNSUPPORTED         Updating variable is not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteInit (
> +  VOID
> +  )
> +{
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Update a variable with protection provided by this library.
> +
> +  Not supported in DXE phase.
> +
> +  @param[in,out]  CurrVariable        Variable to be updated. It's NULL if
> +                                      adding a new variable.
> +  @param[in]      CurrVariableInDel   In-delete-transition copy of updating
> variable.
> +  @param[in,out]  NewVariable         Buffer of new variable data or
> +                                      Buffer of "MetaDataHmacVar" and new variable
> (encrypted).
> +  @param[in,out]  NewVariableSize     Size of NewVariable or
> +                                      Size of (encrypted) NewVariable and "MetaDataHmacVar".
> +
> +  @retval EFI_UNSUPPORTED             Not support updating variable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibUpdate (
> +  IN  OUT VARIABLE_HEADER  *CurrVariable,
> +  IN      VARIABLE_HEADER  *CurrVariableInDel,
> +  IN  OUT VARIABLE_HEADER  *NewVariable,
> +  IN  OUT UINTN            *NewVariableSize
> +  )
> +{
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +
> +  Finalize a variable updating after it's written to NV variable storage
> +  successfully.
> +
> +  (Not supported for BootService/Runtime use cases.)
> +
> +  @param[in]      NewVariable       Buffer of new variables and
> MetaDataHmacVar.
> +  @param[in]      VariableSize      Size of buffer pointed by NewVariable.
> +  @param[in]      StoreIndex        StoreIndex to NV variable storage from where
> the new
> +                                    variable and MetaDataHmacVar have been written.
> +
> +  @retval EFI_UNSUPPORTED           Not supported for BootService/Runtime use
> cases.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProtectedVariableLibWriteFinal (
> +  IN  VARIABLE_HEADER  *NewVariable,
> +  IN  UINTN            VariableSize,
> +  IN  UINT64           StoreIndex
> +  )
> +{
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files
  2022-11-06  7:35 ` [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files Judah Vang
@ 2022-11-22  8:05   ` Wang, Jian J
  0 siblings, 0 replies; 37+ messages in thread
From: Wang, Jian J @ 2022-11-22  8:05 UTC (permalink / raw)
  To: Vang, Judah, devel@edk2.groups.io; +Cc: Yao, Jiewen, Mistry, Nishant C


Reviewed-by: Jian J Wang <jian.j.wang@intel.com>

Regards,
Jian

> -----Original Message-----
> From: Vang, Judah <judah.vang@intel.com>
> Sent: Sunday, November 06, 2022 3:35 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Mistry, Nishant C <nishant.c.mistry@intel.com>
> Subject: [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594
> 
> Add references to the different *ProtectedVariableLib.inf.
> Also add references to VariableKeyLibNull.inf,
> EncryptionVariableLibNull.inf, ProtectedVariableNull.inf.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Nishant C Mistry <nishant.c.mistry@intel.com>
> Signed-off-by: Judah Vang <judah.vang@intel.com>
> ---
>  SecurityPkg/SecurityPkg.dsc | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc
> index 6bf53c565882..3134b103ff53 100644
> --- a/SecurityPkg/SecurityPkg.dsc
> +++ b/SecurityPkg/SecurityPkg.dsc
> @@ -1,7 +1,7 @@
>  ## @file
>  #  Security Module Package for All Architectures.
>  #
> -# Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR>
>  # (C) Copyright 2015-2020 Hewlett Packard Enterprise Development LP<BR>
>  # Copyright (c) 2022, Loongson Technology Corporation Limited. All rights
> reserved.<BR>
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -67,8 +67,11 @@ [LibraryClasses]
> 
> TcgStorageCoreLib|SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.
> inf
> 
> TcgStorageOpalLib|SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.i
> nf
> 
> ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSys
> temLibNull.inf
> +
> +  # These should be Null by default
>    VariableKeyLib|SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf
>    RpmcLib|SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf
> +
> EncryptionVariableLib|SecurityPkg/Library/EncryptionVariableLibNull/Encryption
> VariableLibNull.inf
> 
> TcgEventLogRecordLib|SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLo
> gRecordLib.inf
> 
> MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockM
> emoryLibNull.inf
> 
> SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBoot
> VariableLib.inf
> @@ -261,9 +264,17 @@ [Components]
>    #
>    # Variable Confidentiality & Integrity
>    #
> +  SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> +  SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> +  SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> +
> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.inf
> +  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> +  SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
> +
>    SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf
>    SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf
> 
> SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLib
> VarPolicy.inf
> +  SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.inf
> 
>    #
>    # Other
> --
> 2.35.1.windows.2


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [edk2-devel] [PATCH v5 00/19] UEFI variable protection
  2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
                   ` (18 preceding siblings ...)
  2022-11-06  7:35 ` [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files Judah Vang
@ 2022-12-09  8:03 ` Yao, Jiewen
       [not found] ` <172F11512E3044E7.1612@groups.io>
  20 siblings, 0 replies; 37+ messages in thread
From: Yao, Jiewen @ 2022-12-09  8:03 UTC (permalink / raw)
  To: devel@edk2.groups.io, Vang, Judah
  Cc: Yao, Jiewen, Kinney, Michael D, Wang, Jian J

Hi
Since this is a big feature in SecurityPkg and MdeModulePkg, I proposal to add *dedicated reviewer(s)* to support the maintenance work in EDKII.

Something like:

===============
MdeModulePkg: Protected Variable
F: MdeModulePkg/Universal/Variable/Protected/
F: <Please list all newly added file>
R: <Please give the reviewer name>


SecurityPkg: Protected Variable
F: SecurityPkg/Library/ProtectedVariableLib/
F: <Please list all newly added file>
R: <Please give the reviewer name>

===============

Please follow the style at https://github.com/tianocore/edk2/blob/master/Maintainers.txt

Thank you
Yao, Jiewen


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Judah
> Vang
> Sent: Sunday, November 6, 2022 3:35 PM
> To: devel@edk2.groups.io
> Subject: [edk2-devel] [PATCH v5 00/19] UEFI variable protection
> 
> Patch 07 - Add PEI Variable Protection into a new directory and leave the
> existing PEI Variable unchanged.
> 
> Patch 08 - Add RuntimeDxe Variable Protection into a new directory and
> keep existing Variable for RuntimeDxe unchanged.
> 
> Patch 09 - Add reference to new Protected Variable libs.
> 
> Patch 16 - Applied code review comments by adding PEIM to library class
> 
> Patch 18 - Applied code review comments by removing unused API.
> 
> Notes:
> The CryptoPkg changes are now being tracked separately.
> Patches 21 on is no longer needed due to reorganization of the new
> protected variable modules.
> 
> Judah Vang (19):
>   MdePkg: Add reference to new Ppi Guid
>   MdeModulePkg: Update AUTH_VARIABLE_INFO struct
>   MdeModulePkg: Add new ProtectedVariable GUIDs
>   MdeModulePkg: Add new include files
>   MdeModulePkg: Add new GUID for Variable Store Info
>   MdeModulePkg: Add Null ProtectedVariable Library
>   MdeModulePkg: Add new Variable functionality
>   MdeModulePkg: Add support for Protected Variables
>   MdeModulePkg: Reference Null ProtectedVariableLib
>   SecurityPkg: Add new GUIDs for
>   SecurityPkg: Add new KeyService types and defines
>   SecurityPkg: Add new variable types and functions
>   SecurityPkg: Update RPMC APIs with index
>   SecurityPkg: Fix GetVariableKey API
>   SecurityPkg: Add null encryption variable libs
>   SecurityPkg: Add VariableKey library function
>   SecurityPkg: Add EncryptionVariable lib with AES
>   SecurityPkg: Add Protected Variable Services
>   SecurityPkg: Add references to new *.inf files
> 
>  MdeModulePkg/MdeModulePkg.dec
> |   13 +-
>  SecurityPkg/SecurityPkg.dec
> |   43 +-
>  MdeModulePkg/MdeModulePkg.dsc
> |   20 +-
>  MdeModulePkg/Test/MdeModulePkgHostTest.dsc
> |    8 +
>  SecurityPkg/SecurityPkg.dsc
> |   13 +-
> 
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull
> .inf                                    |   34 +
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> |   79 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> tTest/VariableLockRequestToLockUnitTest.inf |   36 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eDxe.inf                                   |  151 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.i
> nf                                          |  153 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxe.inf                                |  119 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> oneMm.inf                                 |  143 +
>  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> |   43 +
> 
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.in
> f                                   |   34 +
>  SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> |   64 +
>  SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> |   68 +
>  SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> |   67 +
> 
> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLi
> b.inf                                   |   62 +
>  SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
> |   36 +
>  MdeModulePkg/Include/Guid/ProtectedVariable.h
> |   22 +
>  MdeModulePkg/Include/Library/AuthVariableLib.h
> |    4 +-
>  MdeModulePkg/Include/Library/EncryptionVariableLib.h
> |  165 +
>  MdeModulePkg/Include/Library/ProtectedVariableLib.h
> |  607 +++
>  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> |  225 ++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> |  309 ++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> |  116 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolym
> orphic.h                                   |  158 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
> |  948 +++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> atile.h                                    |   67 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> .h                                        |  424 ++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eCache.h                                   |   51 +
>  MdePkg/Include/Ppi/ReadOnlyVariable2.h
> |    4 +-
>  SecurityPkg/Include/Library/RpmcLib.h
> |   15 +-
>  SecurityPkg/Include/Library/VariableKeyLib.h
> |   37 +-
>  SecurityPkg/Include/Ppi/KeyServicePpi.h
> |   57 +
>  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> |   49 +
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> |  589 +++
>  MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> |  336 ++
>  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> |  628 +++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> |  941 +++++
>  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> |  307 ++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
> |  343 ++
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
> |  504 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> tTest/VariableLockRequestToLockUnitTest.c   |  607 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> rierDxe.c                                  |   27 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> rierSmm.c                                  |   26 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe
> .c                                          |  153 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSm
> m.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/VariableLockRe
> questToLock.c                              |   96 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> atile.c                                    |  537 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> .c                                        | 1110 ++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicyS
> mmDxe.c                                   |  575 +++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eCache.c                                   |  158 +
>  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
> | 1268 ++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxe.c                                  | 1895 +++++++++
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> oneMm.c                                   |   89 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditi
> onalMm.c                                  |  130 +
>  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> |  734 ++++
>  SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> |   92 +
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> | 2103 ++++++++++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> |  163 +
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> | 1327 +++++++
>  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> |  209 +
> 
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeComm
> on.c                                      |  967 +++++
> 
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> |  233 ++
>  SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
> |    8 +-
>  SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
> |   59 +
>  SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
> |    8 +-
>  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> |   16 +
>  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> |   14 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eDxe.uni                                   |   22 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eDxeExtra.uni                              |   14 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.u
> ni                                          |   27 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmEx
> tra.uni                                     |   14 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxe.uni                                |   23 +
> 
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxeExtra.uni                           |   14 +
>  80 files changed, 26556 insertions(+), 48 deletions(-)
>  create mode 100644
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull
> .inf
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> tTest/VariableLockRequestToLockUnitTest.inf
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eDxe.inf
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.i
> nf
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxe.inf
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> oneMm.inf
>  create mode 100644
> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
>  create mode 100644
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.in
> f
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLi
> b.inf
>  create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
>  create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
>  create mode 100644
> MdeModulePkg/Include/Library/EncryptionVariableLib.h
>  create mode 100644
> MdeModulePkg/Include/Library/ProtectedVariableLib.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolym
> orphic.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> atile.h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> .h
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eCache.h
>  create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
>  create mode 100644
> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
>  create mode 100644
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> tTest/VariableLockRequestToLockUnitTest.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> rierDxe.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> rierSmm.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe
> .c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSm
> m.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRe
> questToLock.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> atile.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> .c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicyS
> mmDxe.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eCache.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxe.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> oneMm.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditi
> onalMm.c
>  create mode 100644
> SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
>  create mode 100644
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeComm
> on.c
>  create mode 100644
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
>  create mode 100644 SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eDxe.uni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> eDxeExtra.uni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.u
> ni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmEx
> tra.uni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxe.uni
>  create mode 100644
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> untimeDxeExtra.uni
> 
> --
> 2.35.1.windows.2
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [edk2-devel] [PATCH v5 00/19] UEFI variable protection
       [not found] ` <172F11512E3044E7.1612@groups.io>
@ 2022-12-09  9:41   ` Yao, Jiewen
  0 siblings, 0 replies; 37+ messages in thread
From: Yao, Jiewen @ 2022-12-09  9:41 UTC (permalink / raw)
  To: devel@edk2.groups.io, Yao, Jiewen, Vang, Judah
  Cc: Kinney, Michael D, Wang, Jian J, Yao, Jiewen

Hey
I notice that there is duplicated code in variable driver (MdeModulePkg/Universal/Variable/Protected/ and MdeModulePkg/Universal/Variable/). That is not the best idea and it adds maintenance burden.
I am not sure if the feature is ready for EDKII.

Another option is to create ProtectedVariablePkg in https://github.com/tianocore/edk2-platforms/tree/master/Features/Intel, and put code there.

It can merge back from edk2-platforms to edk2, after we finalize the Variable driver interface and avoid code duplication.

Thank you
Yao, Jiewen

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Yao,
> Jiewen
> Sent: Friday, December 9, 2022 4:04 PM
> To: devel@edk2.groups.io; Vang, Judah <judah.vang@intel.com>
> Cc: Yao, Jiewen <jiewen.yao@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Wang, Jian J <jian.j.wang@intel.com>
> Subject: Re: [edk2-devel] [PATCH v5 00/19] UEFI variable protection
> 
> Hi
> Since this is a big feature in SecurityPkg and MdeModulePkg, I proposal to
> add *dedicated reviewer(s)* to support the maintenance work in EDKII.
> 
> Something like:
> 
> ===============
> MdeModulePkg: Protected Variable
> F: MdeModulePkg/Universal/Variable/Protected/
> F: <Please list all newly added file>
> R: <Please give the reviewer name>
> 
> 
> SecurityPkg: Protected Variable
> F: SecurityPkg/Library/ProtectedVariableLib/
> F: <Please list all newly added file>
> R: <Please give the reviewer name>
> 
> ===============
> 
> Please follow the style at
> https://github.com/tianocore/edk2/blob/master/Maintainers.txt
> 
> Thank you
> Yao, Jiewen
> 
> 
> > -----Original Message-----
> > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Judah
> > Vang
> > Sent: Sunday, November 6, 2022 3:35 PM
> > To: devel@edk2.groups.io
> > Subject: [edk2-devel] [PATCH v5 00/19] UEFI variable protection
> >
> > Patch 07 - Add PEI Variable Protection into a new directory and leave the
> > existing PEI Variable unchanged.
> >
> > Patch 08 - Add RuntimeDxe Variable Protection into a new directory and
> > keep existing Variable for RuntimeDxe unchanged.
> >
> > Patch 09 - Add reference to new Protected Variable libs.
> >
> > Patch 16 - Applied code review comments by adding PEIM to library class
> >
> > Patch 18 - Applied code review comments by removing unused API.
> >
> > Notes:
> > The CryptoPkg changes are now being tracked separately.
> > Patches 21 on is no longer needed due to reorganization of the new
> > protected variable modules.
> >
> > Judah Vang (19):
> >   MdePkg: Add reference to new Ppi Guid
> >   MdeModulePkg: Update AUTH_VARIABLE_INFO struct
> >   MdeModulePkg: Add new ProtectedVariable GUIDs
> >   MdeModulePkg: Add new include files
> >   MdeModulePkg: Add new GUID for Variable Store Info
> >   MdeModulePkg: Add Null ProtectedVariable Library
> >   MdeModulePkg: Add new Variable functionality
> >   MdeModulePkg: Add support for Protected Variables
> >   MdeModulePkg: Reference Null ProtectedVariableLib
> >   SecurityPkg: Add new GUIDs for
> >   SecurityPkg: Add new KeyService types and defines
> >   SecurityPkg: Add new variable types and functions
> >   SecurityPkg: Update RPMC APIs with index
> >   SecurityPkg: Fix GetVariableKey API
> >   SecurityPkg: Add null encryption variable libs
> >   SecurityPkg: Add VariableKey library function
> >   SecurityPkg: Add EncryptionVariable lib with AES
> >   SecurityPkg: Add Protected Variable Services
> >   SecurityPkg: Add references to new *.inf files
> >
> >  MdeModulePkg/MdeModulePkg.dec
> > |   13 +-
> >  SecurityPkg/SecurityPkg.dec
> > |   43 +-
> >  MdeModulePkg/MdeModulePkg.dsc
> > |   20 +-
> >  MdeModulePkg/Test/MdeModulePkgHostTest.dsc
> > |    8 +
> >  SecurityPkg/SecurityPkg.dsc
> > |   13 +-
> >
> >
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull
> > .inf                                    |   34 +
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> > |   79 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> > tTest/VariableLockRequestToLockUnitTest.inf |   36 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eDxe.inf                                   |  151 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.i
> > nf                                          |  153 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxe.inf                                |  119 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> > oneMm.inf                                 |  143 +
> >  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> > |   43 +
> >
> >
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.in
> > f                                   |   34 +
> >  SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> > |   64 +
> >  SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> > |   68 +
> >  SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> > |   67 +
> >
> >
> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLi
> > b.inf                                   |   62 +
> >  SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
> > |   36 +
> >  MdeModulePkg/Include/Guid/ProtectedVariable.h
> > |   22 +
> >  MdeModulePkg/Include/Library/AuthVariableLib.h
> > |    4 +-
> >  MdeModulePkg/Include/Library/EncryptionVariableLib.h
> > |  165 +
> >  MdeModulePkg/Include/Library/ProtectedVariableLib.h
> > |  607 +++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> > |  225 ++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> > |  309 ++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> > |  116 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolym
> > orphic.h                                   |  158 +
> >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
> > |  948 +++++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> > atile.h                                    |   67 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> > .h                                        |  424 ++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eCache.h                                   |   51 +
> >  MdePkg/Include/Ppi/ReadOnlyVariable2.h
> > |    4 +-
> >  SecurityPkg/Include/Library/RpmcLib.h
> > |   15 +-
> >  SecurityPkg/Include/Library/VariableKeyLib.h
> > |   37 +-
> >  SecurityPkg/Include/Ppi/KeyServicePpi.h
> > |   57 +
> >  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> > |   49 +
> >  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> > |  589 +++
> >  MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> > |  336 ++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> > |  628 +++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> > |  941 +++++
> >  MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> > |  307 ++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
> > |  343 ++
> >  MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
> > |  504 +++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> > tTest/VariableLockRequestToLockUnitTest.c   |  607 +++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> > rierDxe.c                                  |   27 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> > rierSmm.c                                  |   26 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe
> > .c                                          |  153 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSm
> > m.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/VariableLockRe
> > questToLock.c                              |   96 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> > atile.c                                    |  537 +++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> > .c                                        | 1110 ++++++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicyS
> > mmDxe.c                                   |  575 +++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eCache.c                                   |  158 +
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
> > | 1268 ++++++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxe.c                                  | 1895 +++++++++
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> > oneMm.c                                   |   89 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditi
> > onalMm.c                                  |  130 +
> >  SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> > |  734 ++++
> >  SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> > |   92 +
> >  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> > | 2103 ++++++++++
> >  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> > |  163 +
> >  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> > | 1327 +++++++
> >  SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> > |  209 +
> >
> >
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeComm
> > on.c                                      |  967 +++++
> >
> >
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> > |  233 ++
> >  SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c
> > |    8 +-
> >  SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
> > |   59 +
> >  SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c
> > |    8 +-
> >  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> > |   16 +
> >  MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> > |   14 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eDxe.uni                                   |   22 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eDxeExtra.uni                              |   14 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.u
> > ni                                          |   27 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmEx
> > tra.uni                                     |   14 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxe.uni                                |   23 +
> >
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxeExtra.uni                           |   14 +
> >  80 files changed, 26556 insertions(+), 48 deletions(-)
> >  create mode 100644
> >
> MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariableLibNull
> > .inf
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/VariablePei.inf
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> > tTest/VariableLockRequestToLockUnitTest.inf
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eDxe.inf
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.i
> > nf
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxe.inf
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> > oneMm.inf
> >  create mode 100644
> > SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf
> >  create mode 100644
> >
> SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariableLibNull.in
> > f
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf
> >  create mode 100644
> >
> SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLi
> > b.inf
> >  create mode 100644
> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.inf
> >  create mode 100644 MdeModulePkg/Include/Guid/ProtectedVariable.h
> >  create mode 100644
> > MdeModulePkg/Include/Library/EncryptionVariableLib.h
> >  create mode 100644
> > MdeModulePkg/Include/Library/ProtectedVariableLib.h
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/Variable.h
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.h
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.h
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolym
> > orphic.h
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> > atile.h
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> > .h
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eCache.h
> >  create mode 100644 SecurityPkg/Include/Ppi/KeyServicePpi.h
> >  create mode 100644
> > SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h
> >  create mode 100644
> > MdeModulePkg/Library/ProtectedVariableLibNull/ProtectedVariable.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/Variable.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/VariableParsing.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/VariableStore.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUni
> > tTest/VariableLockRequestToLockUnitTest.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> > rierDxe.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBar
> > rierSmm.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe
> > .c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSm
> > m.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRe
> > questToLock.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVol
> > atile.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing
> > .c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicyS
> > mmDxe.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eCache.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxe.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandal
> > oneMm.c
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditi
> > onalMm.c
> >  create mode 100644
> > SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c
> >  create mode 100644
> > SecurityPkg/Library/EncryptionVariableLibNull/EncryptionVariable.c
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c
> >  create mode 100644
> > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c
> >  create mode 100644
> >
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeComm
> > on.c
> >  create mode 100644
> >
> SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c
> >  create mode 100644
> SecurityPkg/Library/VariableKeyLib/VariableKeyLib.c
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariable.uni
> >  create mode 100644
> > MdeModulePkg/Universal/Variable/Protected/Pei/PeiVariableExtra.uni
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eDxe.uni
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntim
> > eDxeExtra.uni
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.u
> > ni
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmEx
> > tra.uni
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxe.uni
> >  create mode 100644
> >
> MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmR
> > untimeDxeExtra.uni
> >
> > --
> > 2.35.1.windows.2
> >
> >
> >
> >
> >
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2022-12-09  9:41 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-06  7:34 [PATCH v5 00/19] UEFI variable protection Judah Vang
2022-11-06  7:34 ` [PATCH v5 01/19] MdePkg: Add reference to new Ppi Guid Judah Vang
2022-11-06  7:34 ` [PATCH v5 02/19] MdeModulePkg: Update AUTH_VARIABLE_INFO struct Judah Vang
2022-11-06  7:34 ` [PATCH v5 03/19] MdeModulePkg: Add new ProtectedVariable GUIDs Judah Vang
2022-11-06  7:34 ` [PATCH v5 04/19] MdeModulePkg: Add new include files Judah Vang
2022-11-22  6:31   ` Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 05/19] MdeModulePkg: Add new GUID for Variable Store Info Judah Vang
2022-11-06  7:34 ` [PATCH v5 06/19] MdeModulePkg: Add Null ProtectedVariable Library Judah Vang
2022-11-22  6:39   ` Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 07/19] MdeModulePkg: Add new Variable functionality Judah Vang
2022-11-14  3:43   ` Wang, Jian J
     [not found]   ` <1727569A8ECB6F9D.19699@groups.io>
2022-11-14  4:27     ` [edk2-devel] " Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Judah Vang
2022-11-14  7:14   ` Wang, Jian J
2022-11-14 17:19     ` Judah Vang
2022-11-15  8:49       ` [edk2-devel] " Sami Mujawar
2022-11-22  6:26         ` Wang, Jian J
     [not found]         ` <1729D430BF77E016.5511@groups.io>
2022-11-22  6:42           ` Wang, Jian J
2022-11-06  7:34 ` [PATCH v5 09/19] MdeModulePkg: Reference Null ProtectedVariableLib Judah Vang
2022-11-22  6:44   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 10/19] SecurityPkg: Add new GUIDs for Judah Vang
2022-11-06  7:35 ` [PATCH v5 11/19] SecurityPkg: Add new KeyService types and defines Judah Vang
2022-11-22  6:46   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 12/19] SecurityPkg: Add new variable types and functions Judah Vang
2022-11-06  7:35 ` [PATCH v5 13/19] SecurityPkg: Update RPMC APIs with index Judah Vang
2022-11-06  7:35 ` [PATCH v5 14/19] SecurityPkg: Fix GetVariableKey API Judah Vang
2022-11-06  7:35 ` [PATCH v5 15/19] SecurityPkg: Add null encryption variable libs Judah Vang
2022-11-22  6:55   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 16/19] SecurityPkg: Add VariableKey library function Judah Vang
2022-11-06  7:35 ` [PATCH v5 17/19] SecurityPkg: Add EncryptionVariable lib with AES Judah Vang
2022-11-22  7:15   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 18/19] SecurityPkg: Add Protected Variable Services Judah Vang
2022-11-22  7:59   ` Wang, Jian J
2022-11-06  7:35 ` [PATCH v5 19/19] SecurityPkg: Add references to new *.inf files Judah Vang
2022-11-22  8:05   ` Wang, Jian J
2022-12-09  8:03 ` [edk2-devel] [PATCH v5 00/19] UEFI variable protection Yao, Jiewen
     [not found] ` <172F11512E3044E7.1612@groups.io>
2022-12-09  9:41   ` Yao, Jiewen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox