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