public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Wang, Jian J" <jian.j.wang@intel.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
	"Wang, Jian J" <jian.j.wang@intel.com>,
	"sami.mujawar@arm.com" <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
Date: Tue, 22 Nov 2022 06:42:07 +0000	[thread overview]
Message-ID: <MW4PR11MB67636341C3533B534AB55C30B60D9@MW4PR11MB6763.namprd11.prod.outlook.com> (raw)
In-Reply-To: <1729D430BF77E016.5511@groups.io>

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
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> 
> 
> 
> 
> 


  parent reply	other threads:[~2022-11-22  6:42 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=MW4PR11MB67636341C3533B534AB55C30B60D9@MW4PR11MB6763.namprd11.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox