public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platforms] [PATCH v3 0/4] Add Large Variable Libraries
@ 2021-04-06 19:24 Nate DeSimone
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib Nate DeSimone
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Nate DeSimone @ 2021-04-06 19:24 UTC (permalink / raw)
  To: devel; +Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

Changes from V2:
 - Added comment to LargeVariableLib INF and header files
   describing the usage for drivers that cannot assume that
   PcdMaxVariableSize has been set to a certain minimum value.

Changes from V1:
 - Changed prefix from "Min" to "VarLib"
 - Better comments
 - Added more whitespace for readability
 - Removed unused INF sections
 - Better debug messages

This patch series introduces libaries that enable large data sets
to be stored using the UEFI Variable Services. At present, most
UEFI Variable Services implementations have a maximum variable
size of <=64KB. The exact value varies depending on platform.

These libaries enable a data set to use as much space as needed,
up to the remaining space in the UEFI Variable non-volatile storage.

To implement this, I have broken the problem down into two parts:

 1. Phase angostic UEFI Variable access.
 2. Storage of data across multiple UEFI Variables.

For the first part, I have created two new LibraryClasses:
VariableReadLib and VariableWriteLib. I have provided
implementation instances of VariableReadLib for PEI, DXE, and SMM.
For VariableWriteLib, I have provided implementation instances for
DXE and SMM. This enables code that accesses UEFI variables
to be written in a matter than is phase agnostic, so the same
code can be used in PEI, DXE, or SMM without modification.

The second part involves another two new LibaryClasses:
LargeVariableReadLib and LargeVariableWriteLib. Only one BASE
implementation is needed for both of these as the phase dependent
code was seperated out in the first piece. These libraries provide
logic to calculate the maximum size of an individual UEFI variable
and split the data into as many smaller pieces as needed to store
the entire data set in the UEFI Variable storage. They also provide
the ability to stitch the data back together when it is read.
Deleting the data will delete all variables used to store it.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>

Nate DeSimone (4):
  MinPlatformPkg: Add VariableReadLib
  MinPlatformPkg: Add VariableWriteLib
  MinPlatformPkg: Add LargeVariableReadLib
  MinPlatformPkg: Add LargeVariableWriteLib

 .../Include/Dsc/CoreCommonLib.dsc             |   6 +-
 .../MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc |  12 +-
 .../MinPlatformPkg/Include/Dsc/CorePeiLib.dsc |   9 +-
 .../Include/Library/LargeVariableReadLib.h    |  56 ++
 .../Include/Library/LargeVariableWriteLib.h   |  64 +++
 .../Include/Library/VariableReadLib.h         |  87 ++++
 .../Include/Library/VariableWriteLib.h        | 129 +++++
 .../BaseLargeVariableReadLib.inf              |  50 ++
 .../LargeVariableReadLib.c                    | 199 ++++++++
 .../BaseLargeVariableWriteLib.inf             |  50 ++
 .../LargeVariableWriteLib.c                   | 479 ++++++++++++++++++
 .../DxeRuntimeVariableReadLib.c               | 115 +++++
 .../DxeRuntimeVariableReadLib.inf             |  41 ++
 .../DxeRuntimeVariableWriteLib.c              | 256 ++++++++++
 .../DxeRuntimeVariableWriteLib.inf            |  49 ++
 .../PeiVariableReadLib/PeiVariableReadLib.c   | 153 ++++++
 .../PeiVariableReadLib/PeiVariableReadLib.inf |  42 ++
 .../SmmVariableReadCommon.c                   | 114 +++++
 .../StandaloneMmVariableReadLib.inf           |  50 ++
 .../StandaloneMmVariableReadLibConstructor.c  |  48 ++
 .../TraditionalMmVariableReadLib.inf          |  49 ++
 .../TraditionalMmVariableReadLibConstructor.c |  48 ++
 .../SmmVariableWriteCommon.c                  | 167 ++++++
 .../StandaloneMmVariableWriteLib.inf          |  45 ++
 .../StandaloneMmVariableWriteLibConstructor.c |  48 ++
 .../TraditionalMmVariableWriteLib.inf         |  44 ++
 ...TraditionalMmVariableWriteLibConstructor.c |  48 ++
 .../Intel/MinPlatformPkg/MinPlatformPkg.dsc   |   4 +-
 28 files changed, 2452 insertions(+), 10 deletions(-)
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableWriteLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/VariableWriteLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/LargeVariableWriteLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/SmmVariableWriteCommon.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLibConstructor.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLibConstructor.c

-- 
2.27.0.windows.1


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

* [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib
  2021-04-06 19:24 [edk2-platforms] [PATCH v3 0/4] Add Large Variable Libraries Nate DeSimone
@ 2021-04-06 19:24 ` Nate DeSimone
  2021-04-06 21:59   ` [edk2-devel] " Michael Kubacki
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 2/4] MinPlatformPkg: Add VariableWriteLib Nate DeSimone
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Nate DeSimone @ 2021-04-06 19:24 UTC (permalink / raw)
  To: devel; +Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

VariableReadLib is a phase agnostic libary for reading UEFI
Variables. This library provides the
MinGetVariable() and MinGetNextVariableName() APIs which
are usable PEI, DXE, and SMM.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
---
 .../MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc |  10 +-
 .../MinPlatformPkg/Include/Dsc/CorePeiLib.dsc |   9 +-
 .../Include/Library/VariableReadLib.h         |  87 ++++++++++
 .../DxeRuntimeVariableReadLib.c               | 115 +++++++++++++
 .../DxeRuntimeVariableReadLib.inf             |  41 +++++
 .../PeiVariableReadLib/PeiVariableReadLib.c   | 153 ++++++++++++++++++
 .../PeiVariableReadLib/PeiVariableReadLib.inf |  42 +++++
 .../SmmVariableReadCommon.c                   | 114 +++++++++++++
 .../StandaloneMmVariableReadLib.inf           |  50 ++++++
 .../StandaloneMmVariableReadLibConstructor.c  |  48 ++++++
 .../TraditionalMmVariableReadLib.inf          |  49 ++++++
 .../TraditionalMmVariableReadLibConstructor.c |  48 ++++++
 .../Intel/MinPlatformPkg/MinPlatformPkg.dsc   |   3 +-
 13 files changed, 761 insertions(+), 8 deletions(-)
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c

diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
index fa9098d525..0db1250ab7 100644
--- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
+++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
@@ -1,7 +1,7 @@
 ## @file
 #  Platform description.
 #
-# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -11,7 +11,7 @@
   #
   # Generic EDKII Lib
   #
-  
+
   #
   # DXE phase common
   #
@@ -23,7 +23,7 @@
   ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
 
   HstiLib|MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
-  
+
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
 
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -46,6 +46,9 @@
 
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
 
+[LibraryClasses.common.DXE_CORE, LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION]
+  VariableReadLib|MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
+
 [LibraryClasses.common.DXE_CORE]
   HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
   MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
@@ -89,6 +92,7 @@
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
   Tcg2PhysicalPresenceLib|SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
+  VariableReadLib|MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
 
 [LibraryClasses.common.SMM_CORE]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
index 2bcaed05a1..d64873ac6d 100644
--- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
+++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
@@ -1,7 +1,7 @@
 ## @file
 #  Platform description.
 #
-# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -10,11 +10,11 @@
   #
   # Generic EDKII Lib
   #
-  
+
   #
   # PEI phase common
   #
-  
+
 [LibraryClasses.common.SEC,LibraryClasses.common.PEI_CORE,LibraryClasses.common.PEIM]
   S3BootScriptLib|MdePkg/Library/BaseS3BootScriptLibNull/BaseS3BootScriptLibNull.inf
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
@@ -52,7 +52,7 @@
 !if gMinPlatformPkgTokenSpaceGuid.PcdPerformanceEnable == TRUE
   PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
 !endif
-  
+
 [LibraryClasses.common.PEIM]
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
   TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf
@@ -70,3 +70,4 @@
 !if gMinPlatformPkgTokenSpaceGuid.PcdPerformanceEnable == TRUE
   PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
 !endif
+  VariableReadLib|MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
diff --git a/Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h b/Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
new file mode 100644
index 0000000000..6ff762a960
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
@@ -0,0 +1,87 @@
+/** @file
+  Variable Read Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables. For example, the PEI implementation of this
+  library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+  the UEFI Runtime Services Table, and the SMM implementation uses
+  EFI_SMM_VARIABLE_PROTOCOL.
+
+  Using this library allows code to be written in a generic manner that can be
+  used in PEI, DXE, or SMM without modification.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Returns the value of a 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.
+  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
+                                 attributes bitmask for the variable.
+  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
+                                 On output the size of data returned in Data.
+  @param[out]      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.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetVariable (
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  OUT    UINT32                      *Attributes,    OPTIONAL
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data           OPTIONAL
+  );
+
+/**
+  Enumerates the current variable names.
+
+  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
+                                    enough to fit input string supplied in VariableName buffer.
+  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
+                                    by GetNextVariableName(). On output, returns the Nullterminated
+                                    string of the current variable.
+  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
+                                    GetNextVariableName(). On output, returns the
+                                    VendorGuid of the current variable.
+
+  @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.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetNextVariableName (
+  IN OUT UINTN                    *VariableNameSize,
+  IN OUT CHAR16                   *VariableName,
+  IN OUT EFI_GUID                 *VendorGuid
+  );
diff --git a/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
new file mode 100644
index 0000000000..f611891d6a
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
@@ -0,0 +1,115 @@
+/** @file
+  DXE Variable Read Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables. For example, the PEI implementation of this
+  library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+  the UEFI Runtime Services Table, and the SMM implementation uses
+  EFI_SMM_VARIABLE_PROTOCOL.
+
+  Using this library allows code to be written in a generic manner that can be
+  used in PEI, DXE, or SMM without modification.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/**
+  Returns the value of a 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.
+  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
+                                 attributes bitmask for the variable.
+  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
+                                 On output the size of data returned in Data.
+  @param[out]      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.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetVariable (
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  OUT    UINT32                      *Attributes,    OPTIONAL
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data           OPTIONAL
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (gRT != NULL) {
+    Status = gRT->GetVariable (
+                    VariableName,
+                    VendorGuid,
+                    Attributes,
+                    DataSize,
+                    Data
+                    );
+  }
+  return Status;
+}
+
+/**
+  Enumerates the current variable names.
+
+  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
+                                    enough to fit input string supplied in VariableName buffer.
+  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
+                                    by GetNextVariableName(). On output, returns the Nullterminated
+                                    string of the current variable.
+  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
+                                    GetNextVariableName(). On output, returns the
+                                    VendorGuid of the current variable.
+
+  @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.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetNextVariableName (
+  IN OUT UINTN                    *VariableNameSize,
+  IN OUT CHAR16                   *VariableName,
+  IN OUT EFI_GUID                 *VendorGuid
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (gRT != NULL) {
+    Status = gRT->GetNextVariableName (
+                    VariableNameSize,
+                    VariableName,
+                    VendorGuid
+                    );
+  }
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
new file mode 100644
index 0000000000..848b76344b
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
@@ -0,0 +1,41 @@
+## @file
+# Component description file for DXE Variable Read Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for reading from UEFI variables. For example, the PEI implementation of this
+# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in PEI, DXE, or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeRuntimeVariableReadLib
+  FILE_GUID                      = 9C357AD8-2BF4-450C-9E65-C0938F6D2424
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  LIBRARY_CLASS                  = VariableReadLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[Sources]
+  DxeRuntimeVariableReadLib.c
+
+[LibraryClasses]
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEfiVariableArchProtocolGuid    ## CONSUMES
+
+[Depex]
+  gEfiVariableArchProtocolGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
new file mode 100644
index 0000000000..d9fbce7981
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
@@ -0,0 +1,153 @@
+/** @file
+  PEI Variable Read Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables. For example, the PEI implementation of this
+  library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+  the UEFI Runtime Services Table, and the SMM implementation uses
+  EFI_SMM_VARIABLE_PROTOCOL.
+
+  Using this library allows code to be written in a generic manner that can be
+  used in PEI, DXE, or SMM without modification.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+
+/**
+  Returns the value of a 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.
+  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
+                                 attributes bitmask for the variable.
+  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
+                                 On output the size of data returned in Data.
+  @param[out]      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.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetVariable (
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  OUT    UINT32                      *Attributes,    OPTIONAL
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data           OPTIONAL
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_PEI_READ_ONLY_VARIABLE2_PPI     *VariablePpi;
+
+  //
+  // Locate the variable PPI.
+  //
+  Status = PeiServicesLocatePpi (
+             &gEfiPeiReadOnlyVariable2PpiGuid,
+             0,
+             NULL,
+             &VariablePpi
+             );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (VariablePpi != NULL) {
+    Status = VariablePpi->GetVariable (
+              VariablePpi,
+              VariableName,
+              VendorGuid,
+              Attributes,
+              DataSize,
+              Data
+              );
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+  return Status;
+}
+
+/**
+  Enumerates the current variable names.
+
+  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
+                                    enough to fit input string supplied in VariableName buffer.
+  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
+                                    by GetNextVariableName(). On output, returns the Nullterminated
+                                    string of the current variable.
+  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
+                                    GetNextVariableName(). On output, returns the
+                                    VendorGuid of the current variable.
+
+  @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.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetNextVariableName (
+  IN OUT UINTN                    *VariableNameSize,
+  IN OUT CHAR16                   *VariableName,
+  IN OUT EFI_GUID                 *VendorGuid
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_PEI_READ_ONLY_VARIABLE2_PPI     *VariablePpi;
+
+  //
+  // Locate the variable PPI.
+  //
+  Status = PeiServicesLocatePpi (
+             &gEfiPeiReadOnlyVariable2PpiGuid,
+             0,
+             NULL,
+             &VariablePpi
+             );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (VariablePpi != NULL) {
+    Status = VariablePpi->NextVariableName (
+              VariablePpi,
+              VariableNameSize,
+              VariableName,
+              VendorGuid
+              );
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
new file mode 100644
index 0000000000..b1d8a4b9ea
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
@@ -0,0 +1,42 @@
+## @file
+# Component description file for PEI Variable Read Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for reading from UEFI variables. For example, the PEI implementation of this
+# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in PEI, DXE, or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PeiVariableReadLib
+  FILE_GUID                      = C8707767-5D9D-476B-81EE-8FAFA7098224
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = PEIM
+  LIBRARY_CLASS                  = VariableReadLib|PEI_CORE PEIM
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[Sources]
+  PeiVariableReadLib.c
+
+[LibraryClasses]
+  DebugLib
+  PeiServicesLib
+
+[Ppis]
+  gEfiPeiReadOnlyVariable2PpiGuid   ## CONSUMES
+
+[Depex]
+  gEfiPeiReadOnlyVariable2PpiGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
new file mode 100644
index 0000000000..b663b93999
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
@@ -0,0 +1,114 @@
+/** @file
+  SMM Variable Read Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables.
+
+  This is the common implementation pieces that are shared between
+  traditional SMM and standalone MM.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Protocol/SmmVariable.h>
+
+EFI_SMM_VARIABLE_PROTOCOL  *mVariableReadLibSmmVariable = NULL;
+
+/**
+  Returns the value of a 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.
+  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
+                                 attributes bitmask for the variable.
+  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
+                                 On output the size of data returned in Data.
+  @param[out]      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.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetVariable (
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  OUT    UINT32                      *Attributes,    OPTIONAL
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data           OPTIONAL
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (mVariableReadLibSmmVariable != NULL) {
+    Status = mVariableReadLibSmmVariable->SmmGetVariable (
+                                            VariableName,
+                                            VendorGuid,
+                                            Attributes,
+                                            DataSize,
+                                            Data
+                                            );
+  }
+  return Status;
+}
+
+/**
+  Enumerates the current variable names.
+
+  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
+                                    enough to fit input string supplied in VariableName buffer.
+  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
+                                    by GetNextVariableName(). On output, returns the Nullterminated
+                                    string of the current variable.
+  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
+                                    GetNextVariableName(). On output, returns the
+                                    VendorGuid of the current variable.
+
+  @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.
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+VarLibGetNextVariableName (
+  IN OUT UINTN                    *VariableNameSize,
+  IN OUT CHAR16                   *VariableName,
+  IN OUT EFI_GUID                 *VendorGuid
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (mVariableReadLibSmmVariable != NULL) {
+    Status = mVariableReadLibSmmVariable->SmmGetNextVariableName (
+                                            VariableNameSize,
+                                            VariableName,
+                                            VendorGuid
+                                            );
+  }
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
new file mode 100644
index 0000000000..96a4a25fd7
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Component description file for Standalone MM Variable Read Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for reading from UEFI variables. For example, the PEI implementation of this
+# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in PEI, DXE, or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = SmmVariableReadLib
+  FILE_GUID                      = 46246048-856E-4C60-9026-F15E20C03B68
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = MM_STANDALONE
+  PI_SPECIFICATION_VERSION       = 0x00010032
+  LIBRARY_CLASS                  = VariableReadLib|MM_STANDALONE
+  CONSTRUCTOR                    = StandaloneMmVariableReadLibConstructor
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Sources]
+  SmmVariableReadCommon.c
+  StandaloneMmVariableReadLibConstructor.c
+
+[LibraryClasses]
+  DebugLib
+  MmServicesTableLib
+
+[Guids]
+
+[Protocols]
+  gEfiSmmVariableProtocolGuid   ## CONSUMES
+
+[Pcd]
+
+[Depex]
+  gEfiSmmVariableProtocolGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
new file mode 100644
index 0000000000..d9fb915bb4
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
@@ -0,0 +1,48 @@
+/** @file
+  Standalone MM Variable Read Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables.
+
+  This is the standalone MM specific LibraryClass constructor.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Protocol/SmmVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/MmServicesTableLib.h>
+
+extern EFI_SMM_VARIABLE_PROTOCOL  *mVariableReadLibSmmVariable;
+
+/**
+  The constructor function acquires the EFI SMM Variable Services
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the MM System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmVariableReadLibConstructor (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_MM_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  //
+  // Locate SmmVariableProtocol.
+  //
+  Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mVariableReadLibSmmVariable);
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
new file mode 100644
index 0000000000..39cd8371dc
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
@@ -0,0 +1,49 @@
+## @file
+# Component description file for Traditional MM Variable Read Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for reading from UEFI variables. For example, the PEI implementation of this
+# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in PEI, DXE, or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = TraditionalMmVariableReadLib
+  FILE_GUID                      = 50910542-A4ED-4142-AF25-25E141C016FC
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  LIBRARY_CLASS                  = VariableReadLib|DXE_SMM_DRIVER SMM_CORE
+  CONSTRUCTOR                    = TraditionalMmVariableReadLibConstructor
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Sources]
+  SmmVariableReadCommon.c
+  TraditionalMmVariableReadLibConstructor.c
+
+[LibraryClasses]
+  DebugLib
+  SmmServicesTableLib
+
+[Guids]
+
+[Protocols]
+  gEfiSmmVariableProtocolGuid   ## CONSUMES
+
+[Pcd]
+
+[Depex]
+  gEfiSmmVariableProtocolGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c
new file mode 100644
index 0000000000..5d35bedc05
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c
@@ -0,0 +1,48 @@
+/** @file
+  Traditional MM Variable Read Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables.
+
+  This is the traditional SMM specific LibraryClass constructor.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/SmmVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+
+extern EFI_SMM_VARIABLE_PROTOCOL  *mVariableReadLibSmmVariable;
+
+/**
+  The constructor function acquires the EFI SMM Variable Services
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+TraditionalMmVariableReadLibConstructor (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  //
+  // Locate SmmVariableProtocol.
+  //
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mVariableReadLibSmmVariable);
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc b/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
index 998ee79095..18b5c6f5b1 100644
--- a/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
+++ b/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
@@ -1,7 +1,7 @@
 ## @file
 #  Platform description.
 #
-# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -120,6 +120,7 @@
   PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
   SpiFlashCommonLib|MinPlatformPkg/Flash/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.inf
   StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
+  VariableReadLib|MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
 
 ###################################################################################################
 #
-- 
2.27.0.windows.1


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

* [edk2-platforms] [PATCH v3 2/4] MinPlatformPkg: Add VariableWriteLib
  2021-04-06 19:24 [edk2-platforms] [PATCH v3 0/4] Add Large Variable Libraries Nate DeSimone
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib Nate DeSimone
@ 2021-04-06 19:24 ` Nate DeSimone
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib Nate DeSimone
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 4/4] MinPlatformPkg: Add LargeVariableWriteLib Nate DeSimone
  3 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2021-04-06 19:24 UTC (permalink / raw)
  To: devel; +Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

VariableWriteLib is a phase agnostic library for writing
to UEFI Variables. This library provides the MinSetVariable(),
MinQueryVariableInfo(), MinIsVariableRequestToLockSupported(),
and MinVariableRequestToLock() APIs which are usable in DXE
and SMM.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
---
 .../MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc |   2 +
 .../Include/Library/VariableWriteLib.h        | 129 +++++++++
 .../DxeRuntimeVariableWriteLib.c              | 256 ++++++++++++++++++
 .../DxeRuntimeVariableWriteLib.inf            |  49 ++++
 .../SmmVariableWriteCommon.c                  | 167 ++++++++++++
 .../StandaloneMmVariableWriteLib.inf          |  45 +++
 .../StandaloneMmVariableWriteLibConstructor.c |  48 ++++
 .../TraditionalMmVariableWriteLib.inf         |  44 +++
 ...TraditionalMmVariableWriteLibConstructor.c |  48 ++++
 .../Intel/MinPlatformPkg/MinPlatformPkg.dsc   |   1 +
 10 files changed, 789 insertions(+)
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/VariableWriteLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/SmmVariableWriteCommon.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLibConstructor.c
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLibConstructor.c

diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
index 0db1250ab7..57847e6a4d 100644
--- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
+++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
@@ -48,6 +48,7 @@
 
 [LibraryClasses.common.DXE_CORE, LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION]
   VariableReadLib|MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
+  VariableWriteLib|MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.inf
 
 [LibraryClasses.common.DXE_CORE]
   HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
@@ -93,6 +94,7 @@
   Tcg2PhysicalPresenceLib|SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
   VariableReadLib|MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
+  VariableWriteLib|MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLib.inf
 
 [LibraryClasses.common.SMM_CORE]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
diff --git a/Platform/Intel/MinPlatformPkg/Include/Library/VariableWriteLib.h b/Platform/Intel/MinPlatformPkg/Include/Library/VariableWriteLib.h
new file mode 100644
index 0000000000..c52aec93ec
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/VariableWriteLib.h
@@ -0,0 +1,129 @@
+/** @file
+  Variable Write Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for writing to UEFI variables. For example, the DXE implementation accesses
+  the UEFI Runtime Services Table, and the SMM implementation uses
+  EFI_SMM_VARIABLE_PROTOCOL.
+
+  Using this library allows code to be written in a generic manner that can be
+  used in DXE or SMM without modification.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Sets the value of a variable.
+
+  @param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param[in]  VendorGuid         A unique identifier for the vendor.
+  @param[in]  Attributes         Attributes bitmask to set for the variable.
+  @param[in]  DataSize           The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE or
+                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to
+                                 the variable value (the timestamp associated with the variable may be updated however
+                                 even if no new data value is provided,see the description of the
+                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+  @param[in]  Data               The contents for the variable.
+
+  @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, name, and GUID was supplied, or the
+                                 DataSize exceeds the maximum allowed.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty 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 retrieved due to a hardware error.
+  @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_ACESS being 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
+EFIAPI
+VarLibSetVariable (
+  IN  CHAR16                        *VariableName,
+  IN  EFI_GUID                      *VendorGuid,
+  IN  UINT32                        Attributes,
+  IN  UINTN                         DataSize,
+  IN  VOID                          *Data
+  );
+
+/**
+  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   On output the maximum size of the storage space
+                                            available for the EFI variables associated with the
+                                            attributes specified.
+  @param[out]  RemainingVariableStorageSize Returns the remaining size of the storage space
+                                            available for the EFI variables associated with the
+                                            attributes specified.
+  @param[out]  MaximumVariableSize          Returns the maximum size of the individual EFI
+                                            variables associated with the attributes specified.
+
+  @retval EFI_SUCCESS                  Valid answer returned.
+  @retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied
+  @retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and the
+                                       MaximumVariableStorageSize,
+                                       RemainingVariableStorageSize, MaximumVariableSize
+                                       are undefined.
+**/
+EFI_STATUS
+EFIAPI
+VarLibQueryVariableInfo (
+  IN  UINT32                        Attributes,
+  OUT UINT64                        *MaximumVariableStorageSize,
+  OUT UINT64                        *RemainingVariableStorageSize,
+  OUT UINT64                        *MaximumVariableSize
+  );
+
+/**
+  Indicates if the VarLibVariableRequestToLock() API is supported by the current
+  VariableWriteLib implementation. At time of writting, this API is not
+  available in SMM or after ExitBootServices.
+
+  @retval TRUE                  The VarLibVariableRequestToLock() API is supported
+  @retval FALSE                 The VarLibVariableRequestToLock() API is not supported
+**/
+BOOLEAN
+EFIAPI
+VarLibIsVariableRequestToLockSupported (
+  VOID
+  );
+
+/**
+  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 EDKII_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
+VarLibVariableRequestToLock (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid
+  );
diff --git a/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.c b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.c
new file mode 100644
index 0000000000..3b7f377bc2
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.c
@@ -0,0 +1,256 @@
+/** @file
+  DXE Variable Write Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for writing to UEFI variables. For example, the DXE implementation accesses
+  the UEFI Runtime Services Table, and the SMM implementation uses
+  EFI_SMM_VARIABLE_PROTOCOL.
+
+  Using this library allows code to be written in a generic manner that can be
+  used in DXE or SMM without modification.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/EventGroup.h>
+#include <Protocol/VariableLock.h>
+
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+STATIC EDKII_VARIABLE_LOCK_PROTOCOL  *mVariableWriteLibVariableLock = NULL;
+
+/**
+  Sets the value of a variable.
+
+  @param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param[in]  VendorGuid         A unique identifier for the vendor.
+  @param[in]  Attributes         Attributes bitmask to set for the variable.
+  @param[in]  DataSize           The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE or
+                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to
+                                 the variable value (the timestamp associated with the variable may be updated however
+                                 even if no new data value is provided,see the description of the
+                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+  @param[in]  Data               The contents for the variable.
+
+  @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, name, and GUID was supplied, or the
+                                 DataSize exceeds the maximum allowed.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty 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 retrieved due to a hardware error.
+  @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_ACESS being 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
+EFIAPI
+VarLibSetVariable (
+  IN  CHAR16                        *VariableName,
+  IN  EFI_GUID                      *VendorGuid,
+  IN  UINT32                        Attributes,
+  IN  UINTN                         DataSize,
+  IN  VOID                          *Data
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (gRT != NULL) {
+    Status = gRT->SetVariable (
+                    VariableName,
+                    VendorGuid,
+                    Attributes,
+                    DataSize,
+                    Data
+                    );
+  }
+  return Status;
+}
+
+/**
+  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   On output the maximum size of the storage space
+                                            available for the EFI variables associated with the
+                                            attributes specified.
+  @param[out]  RemainingVariableStorageSize Returns the remaining size of the storage space
+                                            available for the EFI variables associated with the
+                                            attributes specified.
+  @param[out]  MaximumVariableSize          Returns the maximum size of the individual EFI
+                                            variables associated with the attributes specified.
+
+  @retval EFI_SUCCESS                  Valid answer returned.
+  @retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied
+  @retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and the
+                                       MaximumVariableStorageSize,
+                                       RemainingVariableStorageSize, MaximumVariableSize
+                                       are undefined.
+**/
+EFI_STATUS
+EFIAPI
+VarLibQueryVariableInfo (
+  IN  UINT32                        Attributes,
+  OUT UINT64                        *MaximumVariableStorageSize,
+  OUT UINT64                        *RemainingVariableStorageSize,
+  OUT UINT64                        *MaximumVariableSize
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (gRT != NULL) {
+    Status = gRT->QueryVariableInfo (
+                    Attributes,
+                    MaximumVariableStorageSize,
+                    RemainingVariableStorageSize,
+                    MaximumVariableSize
+                    );
+  }
+  return Status;
+}
+
+/**
+  Indicates if the VarLibVariableRequestToLock() API is supported by the current
+  VariableWriteLib implementation. At time of writting, this API is not
+  available in SMM or after ExitBootServices.
+
+  @retval TRUE                  The VarLibVariableRequestToLock() API is supported
+  @retval FALSE                 The VarLibVariableRequestToLock() API is not supported
+**/
+BOOLEAN
+EFIAPI
+VarLibIsVariableRequestToLockSupported (
+  VOID
+  )
+{
+  if (mVariableWriteLibVariableLock != NULL) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  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 EDKII_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
+VarLibVariableRequestToLock (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (mVariableWriteLibVariableLock != NULL) {
+    Status = mVariableWriteLibVariableLock->RequestToLock (
+                                              mVariableWriteLibVariableLock,
+                                              VariableName,
+                                              VendorGuid
+                                              );
+  }
+  return Status;
+}
+
+/**
+  Exit Boot Services Event notification handler.
+
+  @param[in]  Event     Event whose notification function is being invoked.
+  @param[in]  Context   Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+DxeRuntimeVariableWriteLibOnExitBootServices (
+  IN  EFI_EVENT                    Event,
+  IN  VOID                         *Context
+  )
+{
+  mVariableWriteLibVariableLock = NULL;
+}
+
+/**
+  The constructor function acquires the Variable Lock Protocol
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeVariableWriteLibConstructor (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+  EFI_EVENT     ExitBootServiceEvent;
+  EFI_EVENT     LegacyBootEvent;
+
+  //
+  // Locate VariableLockProtocol.
+  //
+  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&mVariableWriteLibVariableLock);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Register the event to inform SMM variable that it is at runtime.
+  //
+  Status = gBS->CreateEventEx (
+             EVT_NOTIFY_SIGNAL,
+             TPL_NOTIFY,
+             DxeRuntimeVariableWriteLibOnExitBootServices,
+             NULL,
+             &gEfiEventExitBootServicesGuid,
+             &ExitBootServiceEvent
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Register the event to inform SMM variable that it is at runtime for legacy boot.
+  // Reuse OnExitBootServices() here.
+  //
+  Status = EfiCreateEventLegacyBootEx (
+             TPL_NOTIFY,
+             DxeRuntimeVariableWriteLibOnExitBootServices,
+             NULL,
+             &LegacyBootEvent
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.inf b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.inf
new file mode 100644
index 0000000000..704a8ac7cc
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableWriteLib/DxeRuntimeVariableWriteLib.inf
@@ -0,0 +1,49 @@
+## @file
+# Component description file for DXE Variable Write Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for writing to UEFI variables. For example, the DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in DXE or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeRuntimeVariableWriteLib
+  FILE_GUID                      = 9681E383-5FD4-47A4-B4F8-6651EE603E4E
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  LIBRARY_CLASS                  = VariableWriteLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+  CONSTRUCTOR                    = DxeRuntimeVariableWriteLibConstructor
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Sources]
+  DxeRuntimeVariableWriteLib.c
+
+[LibraryClasses]
+  DebugLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+
+[Guids]
+  gEfiEventExitBootServicesGuid       ## CONSUMES ## Event
+
+[Protocols]
+  gEfiVariableWriteArchProtocolGuid   ## CONSUMES
+  gEdkiiVariableLockProtocolGuid      ## CONSUMES
+
+[Depex]
+  gEfiVariableWriteArchProtocolGuid AND gEdkiiVariableLockProtocolGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/SmmVariableWriteCommon.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/SmmVariableWriteCommon.c
new file mode 100644
index 0000000000..e8d7d19ed1
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/SmmVariableWriteCommon.c
@@ -0,0 +1,167 @@
+/** @file
+  SMM Variable Write Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for writing to UEFI variables.
+
+  This is the common implementation pieces that are shared between
+  traditional SMM and standalone MM.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Protocol/SmmVariable.h>
+
+EFI_SMM_VARIABLE_PROTOCOL  *mVariableWriteLibSmmVariable = NULL;
+
+/**
+  Sets the value of a variable.
+
+  @param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param[in]  VendorGuid         A unique identifier for the vendor.
+  @param[in]  Attributes         Attributes bitmask to set for the variable.
+  @param[in]  DataSize           The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE or
+                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to
+                                 the variable value (the timestamp associated with the variable may be updated however
+                                 even if no new data value is provided,see the description of the
+                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+  @param[in]  Data               The contents for the variable.
+
+  @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, name, and GUID was supplied, or the
+                                 DataSize exceeds the maximum allowed.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty 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 retrieved due to a hardware error.
+  @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_ACESS being 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
+EFIAPI
+VarLibSetVariable (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (mVariableWriteLibSmmVariable != NULL) {
+    Status = mVariableWriteLibSmmVariable->SmmSetVariable (
+                                            VariableName,
+                                            VendorGuid,
+                                            Attributes,
+                                            DataSize,
+                                            Data
+                                            );
+  }
+  return Status;
+}
+
+/**
+  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   On output the maximum size of the storage space
+                                            available for the EFI variables associated with the
+                                            attributes specified.
+  @param[out]  RemainingVariableStorageSize Returns the remaining size of the storage space
+                                            available for the EFI variables associated with the
+                                            attributes specified.
+  @param[out]  MaximumVariableSize          Returns the maximum size of the individual EFI
+                                            variables associated with the attributes specified.
+
+  @retval EFI_SUCCESS                  Valid answer returned.
+  @retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied
+  @retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and the
+                                       MaximumVariableStorageSize,
+                                       RemainingVariableStorageSize, MaximumVariableSize
+                                       are undefined.
+**/
+EFI_STATUS
+EFIAPI
+VarLibQueryVariableInfo (
+  IN  UINT32            Attributes,
+  OUT UINT64            *MaximumVariableStorageSize,
+  OUT UINT64            *RemainingVariableStorageSize,
+  OUT UINT64            *MaximumVariableSize
+  )
+{
+  EFI_STATUS    Status = EFI_UNSUPPORTED;
+
+  if (mVariableWriteLibSmmVariable != NULL) {
+    Status = mVariableWriteLibSmmVariable->SmmQueryVariableInfo (
+                                             Attributes,
+                                             MaximumVariableStorageSize,
+                                             RemainingVariableStorageSize,
+                                             MaximumVariableSize
+                                             );
+  }
+  return Status;
+}
+
+/**
+  Indicates if the VarLibVariableRequestToLock() API is supported by the current
+  VariableWriteLib implementation. At time of writting, this API is not
+  available in SMM or after ExitBootServices.
+
+  @retval TRUE                  The VarLibVariableRequestToLock() API is supported
+  @retval FALSE                 The VarLibVariableRequestToLock() API is not supported
+**/
+BOOLEAN
+EFIAPI
+VarLibIsVariableRequestToLockSupported (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  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 EDKII_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
+VarLibVariableRequestToLock (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid
+  )
+{
+  //
+  // Variable lock protocol is not accessible from SMM
+  //
+  return EFI_UNSUPPORTED;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLib.inf b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLib.inf
new file mode 100644
index 0000000000..4cafc421c4
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLib.inf
@@ -0,0 +1,45 @@
+## @file
+# Component description file for Standalone MM Variable Write Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for writing to UEFI variables. For example, the DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in DXE or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = SmmVariableWriteLib
+  FILE_GUID                      = 62A023A6-DEBA-4407-A617-18963090DAFD
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = MM_STANDALONE
+  PI_SPECIFICATION_VERSION       = 0x00010032
+  LIBRARY_CLASS                  = VariableWriteLib|MM_STANDALONE
+  CONSTRUCTOR                    = StandaloneMmVariableWriteLibConstructor
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Sources]
+  SmmVariableWriteCommon.c
+  StandaloneMmVariableWriteLibConstructor.c
+
+[LibraryClasses]
+  DebugLib
+  MmServicesTableLib
+
+[Protocols]
+  gEfiSmmVariableProtocolGuid   ## CONSUMES
+
+[Depex]
+  gEfiSmmVariableProtocolGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLibConstructor.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLibConstructor.c
new file mode 100644
index 0000000000..4493929328
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLibConstructor.c
@@ -0,0 +1,48 @@
+/** @file
+  Standalone MM Variable Write Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables.
+
+  This is the standalone MM specific LibraryClass constructor.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Protocol/SmmVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/MmServicesTableLib.h>
+
+extern EFI_SMM_VARIABLE_PROTOCOL  *mVariableWriteLibSmmVariable;
+
+/**
+  The constructor function acquires the EFI SMM Variable Services
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the MM System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmVariableWriteLibConstructor (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_MM_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  //
+  // Locate SmmVariableProtocol.
+  //
+  Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mVariableWriteLibSmmVariable);
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLib.inf b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLib.inf
new file mode 100644
index 0000000000..5d833b7e0f
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLib.inf
@@ -0,0 +1,44 @@
+## @file
+# Component description file for Traditional MM Variable Write Lib
+#
+# This library provides phase agnostic access to the UEFI Variable Services.
+# This is done by implementing a wrapper on top of the phase specific mechanism
+# for writing to UEFI variables. For example, the DXE implementation accesses
+# the UEFI Runtime Services Table, and the SMM implementation uses
+# EFI_SMM_VARIABLE_PROTOCOL.
+#
+# Using this library allows code to be written in a generic manner that can be
+# used in DXE or SMM without modification.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = TraditionalMmVariableWriteLib
+  FILE_GUID                      = 8C385E9B-C260-466C-91D2-43D839712680
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  LIBRARY_CLASS                  = VariableWriteLib|DXE_SMM_DRIVER SMM_CORE
+  CONSTRUCTOR                    = TraditionalMmVariableWriteLibConstructor
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Sources]
+  SmmVariableWriteCommon.c
+  TraditionalMmVariableWriteLibConstructor.c
+
+[LibraryClasses]
+  DebugLib
+  SmmServicesTableLib
+
+[Protocols]
+  gEfiSmmVariableProtocolGuid   ## CONSUMES
+
+[Depex]
+  gEfiSmmVariableProtocolGuid
diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLibConstructor.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLibConstructor.c
new file mode 100644
index 0000000000..472ccc5aad
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableWriteLib/TraditionalMmVariableWriteLibConstructor.c
@@ -0,0 +1,48 @@
+/** @file
+  Traditional MM Variable Write Lib
+
+  This library provides phase agnostic access to the UEFI Variable Services.
+  This is done by implementing a wrapper on top of the phase specific mechanism
+  for reading from UEFI variables.
+
+  This is the traditional SMM specific LibraryClass constructor.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/SmmVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+
+extern EFI_SMM_VARIABLE_PROTOCOL  *mVariableWriteLibSmmVariable;
+
+/**
+  The constructor function acquires the EFI SMM Variable Services
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+TraditionalMmVariableWriteLibConstructor (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  //
+  // Locate SmmVariableProtocol.
+  //
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mVariableWriteLibSmmVariable);
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc b/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
index 18b5c6f5b1..e968ec4cb2 100644
--- a/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
+++ b/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
@@ -121,6 +121,7 @@
   SpiFlashCommonLib|MinPlatformPkg/Flash/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.inf
   StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
   VariableReadLib|MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
+  VariableWriteLib|MinPlatformPkg/Library/SmmVariableWriteLib/StandaloneMmVariableWriteLib.inf
 
 ###################################################################################################
 #
-- 
2.27.0.windows.1


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

* [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib
  2021-04-06 19:24 [edk2-platforms] [PATCH v3 0/4] Add Large Variable Libraries Nate DeSimone
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib Nate DeSimone
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 2/4] MinPlatformPkg: Add VariableWriteLib Nate DeSimone
@ 2021-04-06 19:24 ` Nate DeSimone
  2021-04-06 22:01   ` [edk2-devel] " Michael Kubacki
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 4/4] MinPlatformPkg: Add LargeVariableWriteLib Nate DeSimone
  3 siblings, 1 reply; 8+ messages in thread
From: Nate DeSimone @ 2021-04-06 19:24 UTC (permalink / raw)
  To: devel; +Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

LargeVariableReadLib is used to retrieve large data sets using
the UEFI Variable Services. At time of writting, most UEFI
Variable Services implementations to not allow more than 64KB
of data to be stored in a single UEFI variable. This library
will split data sets across multiple variables as needed.

It adds the GetLargeVariable() API to provide this service.

The primary use for this library is to create binary compatible
drivers and OpROMs which need to work both with TianoCore and
other UEFI PI implementations. When customizing and recompiling
the platform firmware image is possible, adjusting the value of
PcdMaxVariableSize may provide a simpler solution to this
problem.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
---
 .../Include/Dsc/CoreCommonLib.dsc             |   5 +-
 .../Include/Library/LargeVariableReadLib.h    |  56 +++++
 .../BaseLargeVariableReadLib.inf              |  50 +++++
 .../LargeVariableReadLib.c                    | 199 ++++++++++++++++++
 4 files changed, 308 insertions(+), 2 deletions(-)
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c

diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
index cf2940cf02..5f2ad3f0f0 100644
--- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
+++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
@@ -135,13 +135,14 @@
   VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
   PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
   AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
-  
+
 !if gMinPlatformPkgTokenSpaceGuid.PcdUefiSecureBootEnable == TRUE
   AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
 !endif
 
   SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
   BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
+  LargeVariableReadLib|MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
 
   #
   # CryptLib
@@ -165,4 +166,4 @@
 
   SmbusLib|MdePkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.inf
   VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
-  VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
\ No newline at end of file
+  VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
diff --git a/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
new file mode 100644
index 0000000000..5579492727
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
@@ -0,0 +1,56 @@
+/** @file
+  Large Variable Read Lib
+
+  This library is used to retrieve large data sets using the UEFI Variable
+  Services. At time of writing, most UEFI Variable Services implementations to
+  not allow more than 64KB of data to be stored in a single UEFI variable. This
+  library will split data sets across multiple variables as needed.
+
+  In the case where more than one variable is needed to store the data, an
+  integer number will be added to the end of the variable name. This number
+  will be incremented for each variable as needed to retrieve the entire data
+  set.
+
+  The primary use for this library is to create binary compatible drivers
+  and OpROMs which need to work both with TianoCore and other UEFI PI
+  implementations. When customizing and recompiling the platform firmware image
+  is possible, adjusting the value of PcdMaxVariableSize may provide a simpler
+  solution to this problem.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Returns the value of a large 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.
+  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
+                                 On output the size of data returned in Data.
+  @param[out]      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.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+GetLargeVariable (
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data           OPTIONAL
+  );
diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
new file mode 100644
index 0000000000..822febd62b
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Component description file for Large Variable Read Library
+#
+# This library is used to retrieve large data sets using the UEFI Variable
+# Services. At time of writing, most UEFI Variable Services implementations to
+# not allow more than 64KB of data to be stored in a single UEFI variable. This
+# library will split data sets across multiple variables as needed.
+#
+# In the case where more than one variable is needed to store the data, an
+# integer number will be added to the end of the variable name. This number
+# will be incremented for each variable as needed to retrieve the entire data
+# set.
+#
+# The primary use for this library is to create binary compatible drivers
+# and OpROMs which need to work both with TianoCore and other UEFI PI
+# implementations. When customizing and recompiling the platform firmware image
+# is possible, adjusting the value of PcdMaxVariableSize may provide a simpler
+# solution to this problem.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = BaseLargeVariableReadLib
+  FILE_GUID                      = 4E9D7D31-A7A0-4004-AE93-D12F1AB08730
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = LargeVariableReadLib
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  LargeVariableReadLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MinPlatformPkg/MinPlatformPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  PrintLib
+  VariableReadLib
diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
new file mode 100644
index 0000000000..115f3aeb17
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
@@ -0,0 +1,199 @@
+/** @file
+  Large Variable Read Lib
+
+  This library is used to retrieve large data sets using the UEFI Variable
+  Services. At time of writing, most UEFI Variable Services implementations to
+  not allow more than 64KB of data to be stored in a single UEFI variable. This
+  library will split data sets across multiple variables as needed.
+
+  In the case where more than one variable is needed to store the data, an
+  integer number will be added to the end of the variable name. This number
+  will be incremented for each variable as needed to retrieve the entire data
+  set.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/VariableReadLib.h>
+
+//
+// 1024 was choosen because this is the size of the SMM communication buffer
+// used by VariableDxeSmm to transfer the VariableName from DXE to SMM. Choosing
+// the same size will prevent this library from limiting variable names any
+// more than the MdeModulePkg implementation of UEFI Variable Services does.
+//
+#define MAX_VARIABLE_NAME_SIZE      1024
+
+//
+// The 2012 Windows Hardware Requirements specified a minimum variable size of
+// 32KB. By setting the maximum allowed number of variables to 0x20000, this
+// allows up to 4GB of data to be stored on most UEFI implementations in
+// existence. Older UEFI implementations were known to only provide 8KB per
+// variable. In this case, up to 1GB can be stored. Since 1GB vastly exceeds the
+// size of any known NvStorage FV, choosing this number should effectively
+// enable all available NvStorage space to be used to store the given data.
+//
+#define MAX_VARIABLE_SPLIT          131072  // 0x20000
+
+//
+// There are 6 digits in the number 131072, which means the length of the string
+// representation of this number will be at most 6 characters long.
+//
+#define MAX_VARIABLE_SPLIT_DIGITS   6
+
+/**
+  Returns the value of a large 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.
+  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
+                                 On output the size of data returned in Data.
+  @param[out]      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.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_NOT_FOUND          The variable was not found.
+  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
+  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+GetLargeVariable (
+  IN     CHAR16                      *VariableName,
+  IN     EFI_GUID                    *VendorGuid,
+  IN OUT UINTN                       *DataSize,
+  OUT    VOID                        *Data           OPTIONAL
+  )
+{
+  CHAR16        TempVariableName[MAX_VARIABLE_NAME_SIZE];
+  EFI_STATUS    Status;
+  UINTN         TotalSize;
+  UINTN         VarDataSize;
+  UINTN         Index;
+  UINTN         VariableSize;
+  UINTN         BytesRemaining;
+  UINT8         *OffsetPtr;
+
+  VarDataSize = 0;
+
+  //
+  // First check if a variable with the given name exists
+  //
+  Status = VarLibGetVariable (VariableName, VendorGuid, NULL, &VarDataSize, NULL);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    if (*DataSize >= VarDataSize) {
+      if (Data == NULL) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+      DEBUG ((DEBUG_INFO, "GetLargeVariable: Single Variable Found\n"));
+      Status = VarLibGetVariable (VariableName, VendorGuid, NULL, DataSize, Data);
+      goto Done;
+    } else {
+      *DataSize = VarDataSize;
+      Status = EFI_BUFFER_TOO_SMALL;
+      goto Done;
+    }
+
+  } else if (Status == EFI_NOT_FOUND) {
+    //
+    // Check if the first variable of a multi-variable set exists
+    //
+    if (StrLen (VariableName) >= (MAX_VARIABLE_NAME_SIZE - MAX_VARIABLE_SPLIT_DIGITS)) {
+      DEBUG ((DEBUG_ERROR, "GetLargeVariable: Variable name too long\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+
+    VarDataSize = 0;
+    Index       = 0;
+    ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+    UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+    Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VarDataSize, NULL);
+
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      //
+      // The first variable exists. Calculate the total size of all the variables.
+      //
+      DEBUG ((DEBUG_INFO, "GetLargeVariable: Multiple Variables Found\n"));
+      TotalSize = 0;
+      for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
+        VarDataSize = 0;
+        ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+        UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+        Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VarDataSize, NULL);
+        if (Status != EFI_BUFFER_TOO_SMALL) {
+          break;
+        }
+        TotalSize += VarDataSize;
+      }
+      DEBUG ((DEBUG_INFO, "TotalSize = %d, NumVariables = %d\n", TotalSize, Index));
+
+      //
+      // Check if the user provided a large enough buffer
+      //
+      if (*DataSize >= TotalSize) {
+        if (Data == NULL) {
+          Status = EFI_INVALID_PARAMETER;
+          goto Done;
+        }
+
+        //
+        // Read the data from all variables
+        //
+        OffsetPtr       = (UINT8 *) Data;
+        BytesRemaining  = *DataSize;
+        for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
+          VarDataSize = 0;
+          ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+          UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+          VariableSize = BytesRemaining;
+          DEBUG ((DEBUG_INFO, "Reading %s, Guid = %g,", TempVariableName, VendorGuid));
+          Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VariableSize, (VOID *) OffsetPtr);
+          DEBUG ((DEBUG_INFO, " Size %d\n", VariableSize));
+          if (EFI_ERROR (Status)) {
+            if (Status == EFI_NOT_FOUND) {
+              DEBUG ((DEBUG_INFO, "No more variables found\n"));
+              Status = EFI_SUCCESS;   // The end has been reached
+            }
+            goto Done;
+          }
+
+          if (VariableSize < BytesRemaining) {
+            BytesRemaining -= VariableSize;
+            OffsetPtr += VariableSize;
+          } else {
+            DEBUG ((DEBUG_INFO, "All data has been read\n"));
+            BytesRemaining = 0;
+            break;
+          }
+        }   //End of for loop
+
+        goto Done;
+      } else {
+        *DataSize = TotalSize;
+        Status = EFI_BUFFER_TOO_SMALL;
+        goto Done;
+      }
+    } else {
+      Status = EFI_NOT_FOUND;
+    }
+  }
+
+Done:
+  DEBUG ((DEBUG_ERROR, "GetLargeVariable: Status = %r\n", Status));
+  return Status;
+}
-- 
2.27.0.windows.1


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

* [edk2-platforms] [PATCH v3 4/4] MinPlatformPkg: Add LargeVariableWriteLib
  2021-04-06 19:24 [edk2-platforms] [PATCH v3 0/4] Add Large Variable Libraries Nate DeSimone
                   ` (2 preceding siblings ...)
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib Nate DeSimone
@ 2021-04-06 19:24 ` Nate DeSimone
  3 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2021-04-06 19:24 UTC (permalink / raw)
  To: devel; +Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

LargeVariableWriteLib is used to store large data sets using
the UEFI Variable Services. At time of writting, most UEFI
Variable Services implementations to not allow more than 64KB
of data to be stored in a single UEFI variable. This library
will split data sets across multiple variables as needed.

It adds the SetLargeVariable() API to provide this service.

The primary use for this library is to create binary compatible
drivers and OpROMs which need to work both with TianoCore and
other UEFI PI implementations. When customizing and recompiling
the platform firmware image is possible, adjusting the value of
PcdMaxVariableSize may provide a simpler solution to this
problem.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
---
 .../Include/Dsc/CoreCommonLib.dsc             |   1 +
 .../Include/Library/LargeVariableWriteLib.h   |  64 +++
 .../BaseLargeVariableWriteLib.inf             |  50 ++
 .../LargeVariableWriteLib.c                   | 479 ++++++++++++++++++
 4 files changed, 594 insertions(+)
 create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableWriteLib.h
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf
 create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/LargeVariableWriteLib.c

diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
index 5f2ad3f0f0..78d66b9072 100644
--- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
+++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
@@ -143,6 +143,7 @@
   SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
   BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
   LargeVariableReadLib|MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
+  LargeVariableWriteLib|MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf
 
   #
   # CryptLib
diff --git a/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableWriteLib.h b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableWriteLib.h
new file mode 100644
index 0000000000..6d597447f1
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableWriteLib.h
@@ -0,0 +1,64 @@
+/** @file
+  Large Variable Write Lib
+
+  This library is used to store large data sets using the UEFI Variable Services.
+  At time of writting, most UEFI Variable Services implementations to not allow
+  more than 64KB of data to be stored in a single UEFI variable. This library
+  will split data sets across multiple variables as needed.
+
+  In the case where more than one variable is needed to store the data, an
+  integer number will be added to the end of the variable name. This number
+  will be incremented for each variable as needed to store the entire data set.
+
+  The primary use for this library is to create binary compatible drivers
+  and OpROMs which need to work both with TianoCore and other UEFI PI
+  implementations. When customizing and recompiling the platform firmware image
+  is possible, adjusting the value of PcdMaxVariableSize may provide a simpler
+  solution to this problem.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Sets the value of a large variable.
+
+  @param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param[in]  VendorGuid         A unique identifier for the vendor.
+  @param[in]  LockVariable       If TRUE, any further writes to the variable will be prevented until the next reset.
+                                 Note: LockVariable must be FALSE when running in SMM or after ExitBootServices.
+  @param[in]  DataSize           The size in bytes of the Data buffer. A size of zero causes the variable to be deleted.
+                                 If DataSize is zero, then LockVariable must be FALSE since a variable that does not
+                                 exist cannot be locked.
+  @param[in]  Data               The contents for the variable.
+
+  @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 LockVariable, name, and GUID was supplied, or the
+                                 DataSize exceeds the maximum allowed.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
+  @retval EFI_INVALID_PARAMETER  DataSize is zero and LockVariable is TRUE
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
+  @retval EFI_OUT_OF_RESOURCES   The VariableName is longer than 1018 characters
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
+
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+SetLargeVariable (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  BOOLEAN                      LockVariable,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  );
diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf
new file mode 100644
index 0000000000..afecb31e29
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Component description file for Large Variable Write Library
+#
+# This library is used to store large data sets using the UEFI Variable Services.
+# At time of writting, most UEFI Variable Services implementations to not allow
+# more than 64KB of data to be stored in a single UEFI variable. This library
+# will split data sets across multiple variables as needed.
+#
+# In the case where more than one variable is needed to store the data, an
+# integer number will be added to the end of the variable name. This number
+# will be incremented for each variable as needed to store the entire data set.
+#
+# The primary use for this library is to create binary compatible drivers
+# and OpROMs which need to work both with TianoCore and other UEFI PI
+# implementations. When customizing and recompiling the platform firmware image
+# is possible, adjusting the value of PcdMaxVariableSize may provide a simpler
+# solution to this problem.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = BaseLargeVariableWriteLib
+  FILE_GUID                      = 13E7DD75-FBE0-4B92-87A9-6BED253EB99E
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = LargeVariableWriteLib
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  LargeVariableWriteLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MinPlatformPkg/MinPlatformPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  PrintLib
+  VariableReadLib
+  VariableWriteLib
diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/LargeVariableWriteLib.c b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/LargeVariableWriteLib.c
new file mode 100644
index 0000000000..5cf4776707
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/LargeVariableWriteLib.c
@@ -0,0 +1,479 @@
+/** @file
+  Large Variable Write Lib
+
+  This library is used to store large data sets using the UEFI Variable Services.
+  At time of writting, most UEFI Variable Services implementations to not allow
+  more than 64KB of data to be stored in a single UEFI variable. This library
+  will split data sets across multiple variables as needed.
+
+  In the case where more than one variable is needed to store the data, an
+  integer number will be added to the end of the variable name. This number
+  will be incremented for each variable as needed to store the entire data set.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/VariableReadLib.h>
+#include <Library/VariableWriteLib.h>
+
+//
+// 1024 was choosen because this is the size of the SMM communication buffer
+// used by VariableDxeSmm to transfer the VariableName from DXE to SMM. Choosing
+// the same size will prevent this library from limiting variable names any
+// more than the MdeModulePkg implementation of UEFI Variable Services does.
+//
+#define MAX_VARIABLE_NAME_SIZE      1024
+
+//
+// The 2012 Windows Hardware Requirements specified a minimum variable size of
+// 32KB. By setting the maximum allowed number of variables to 0x20000, this
+// allows up to 4GB of data to be stored on most UEFI implementations in
+// existence. Older UEFI implementations were known to only provide 8KB per
+// variable. In this case, up to 1GB can be stored. Since 1GB vastly exceeds the
+// size of any known NvStorage FV, choosing this number should effectively
+// enable all available NvStorage space to be used to store the given data.
+//
+#define MAX_VARIABLE_SPLIT          131072
+
+//
+// There are 6 digits in the number 131072, which means the length of the string
+// representation of this number will be at most 6 characters long.
+//
+#define MAX_VARIABLE_SPLIT_DIGITS   6
+
+//
+// On some architectures (Ex. Itanium) there a requirement to
+// maintain DWORD alignment of the variable data. Hence the
+// maximum possible padding size is 3.
+//
+#define MAX_VARIABLE_NAME_PAD_SIZE  3
+
+/**
+  Returns the amount of space remaining for storage of
+  non-volatile runtime accessible UEFI variables. Runtime accessible UEFI
+  variables are chosen because this is a BASE LibraryClass. Accordingly, it is
+  possible for a Runtime DXE driver to include this library. To simplify
+  implementation we only consider the runtime accessible case.
+
+  @retval The remaining storage space for non-volatile runtime accessible UEFI variables in bytes.
+
+**/
+UINT64
+GetRemainingVariableStorageSpace (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  UINT64          MaximumVariableStorageSize;
+  UINT64          RemainingVariableStorageSize;
+  UINT64          MaximumVariableSize;
+
+  Status                        = EFI_SUCCESS;
+  MaximumVariableStorageSize    = 0;
+  RemainingVariableStorageSize  = 0;
+  MaximumVariableSize           = 0;
+
+  Status = VarLibQueryVariableInfo (
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+             &MaximumVariableStorageSize,
+             &RemainingVariableStorageSize,
+             &MaximumVariableSize
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "GetVariableSplitSize: QueryVariableInfo failed, Status = %r\n", Status));
+    ASSERT_EFI_ERROR (Status);
+    return 0;
+  }
+
+  return RemainingVariableStorageSize;
+}
+
+/**
+  Returns the maximum size of an individual non-volatile runtime accessible
+  UEFI variable. Runtime accessible UEFI variables are chosen because this is
+  a BASE LibraryClass. Accordingly, it is possible for a Runtime DXE driver to
+  include this library. To simplify implementation we only consider the runtime
+  accessible case.
+
+  @param[in] VariableNameLength         Length of the variable name
+
+  @retval The maximum size of an individual UEFI variable.
+
+**/
+UINT64
+GetVariableSplitSize (
+  IN  UINTN                        VariableNameLength
+  )
+{
+  EFI_STATUS      Status;
+  UINT64          MaximumVariableStorageSize;
+  UINT64          RemainingVariableStorageSize;
+  UINT64          VariableSplitSize;
+
+  Status                        = EFI_SUCCESS;
+  MaximumVariableStorageSize    = 0;
+  RemainingVariableStorageSize  = 0;
+  VariableSplitSize             = 0;
+
+  Status = VarLibQueryVariableInfo (
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+             &MaximumVariableStorageSize,
+             &RemainingVariableStorageSize,
+             &VariableSplitSize
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "GetVariableSplitSize: QueryVariableInfo failed, Status = %r\n", Status));
+    ASSERT_EFI_ERROR (Status);
+    return 0;
+  } else {
+    //
+    // The Variable Name counts as part of the consumed NV storage
+    // space for a UEFI Variable
+    //
+    if ((((VariableNameLength + 1) * sizeof (CHAR16)) + MAX_VARIABLE_NAME_PAD_SIZE) >= VariableSplitSize) {
+      VariableSplitSize = 0;
+    } else {
+      VariableSplitSize -= ((VariableNameLength + 1) * sizeof (CHAR16)) + MAX_VARIABLE_NAME_PAD_SIZE;
+    }
+  }
+
+  return VariableSplitSize;
+}
+
+/**
+  Deletes a large variable.
+
+  @param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param[in]  VendorGuid         A unique identifier for the vendor.
+
+  @retval EFI_SUCCESS            The firmware has successfully deleted the variable and its data as
+                                 defined by the Attributes.
+  @retval EFI_INVALID_PARAMETER  An invalid combination of name, and GUID was supplied.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
+  @retval EFI_OUT_OF_RESOURCES   The VariableName is longer than 1018 characters
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
+
+  @retval EFI_NOT_FOUND          The variable trying to be deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteLargeVariableInternal (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid
+  )
+{
+  CHAR16        TempVariableName[MAX_VARIABLE_NAME_SIZE];
+  EFI_STATUS    Status;
+  EFI_STATUS    Status2;
+  UINTN         VarDataSize;
+  UINTN         Index;
+
+  VarDataSize = 0;
+
+  //
+  // First check if a variable with the given name exists
+  //
+  Status = VarLibGetVariable (VariableName, VendorGuid, NULL, &VarDataSize, NULL);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    DEBUG ((DEBUG_INFO, "DeleteLargeVariableInternal: Deleting Single Variable\n"));
+    Status = VarLibSetVariable (
+                VariableName,
+                VendorGuid,
+                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                0,
+                NULL
+                );
+    goto Done;
+  } else if (Status == EFI_NOT_FOUND) {
+
+    //
+    // Check if the first variable of a multi-variable set exists
+    //
+    if (StrLen (VariableName) >= (MAX_VARIABLE_NAME_SIZE - MAX_VARIABLE_SPLIT_DIGITS)) {
+      DEBUG ((DEBUG_ERROR, "DeleteLargeVariableInternal: Variable name too long\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+    VarDataSize = 0;
+    Index       = 0;
+    ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+    UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+    Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VarDataSize, NULL);
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+
+      //
+      // The first variable exists. Delete all the variables.
+      //
+      DEBUG ((DEBUG_INFO, "DeleteLargeVariableInternal: Multiple Variables Found\n"));
+      Status = EFI_SUCCESS;
+      for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
+        VarDataSize = 0;
+        ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+        UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+        DEBUG ((DEBUG_INFO, "Deleting %s, Guid = %g\n", TempVariableName, VendorGuid));
+        Status2 = VarLibSetVariable (
+                    TempVariableName,
+                    VendorGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                    0,
+                    NULL
+                    );
+        if (Status2 == EFI_NOT_FOUND) {
+          DEBUG ((DEBUG_INFO, "DeleteLargeVariableInternal: Deletion Complete.\n"));
+          break;
+        } else if (EFI_ERROR (Status2)) {
+          DEBUG ((DEBUG_ERROR, "DeleteLargeVariableInternal: Error deleting variable: Status = %r\n", Status2));
+          Status = Status2;
+        }
+      }   // End of for loop
+    } else {
+      Status = EFI_NOT_FOUND;
+    }
+  }
+Done:
+  DEBUG ((DEBUG_ERROR, "DeleteLargeVariableInternal: Status = %r\n", Status));
+  return Status;
+}
+
+/**
+  Sets the value of a large variable.
+
+  @param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.
+                                 Each VariableName is unique for each VendorGuid. VariableName must
+                                 contain 1 or more characters. If VariableName is an empty string,
+                                 then EFI_INVALID_PARAMETER is returned.
+  @param[in]  VendorGuid         A unique identifier for the vendor.
+  @param[in]  LockVariable       If TRUE, any further writes to the variable will be prevented until the next reset.
+                                 Note: LockVariable must be FALSE when running in SMM or after ExitBootServices.
+  @param[in]  DataSize           The size in bytes of the Data buffer. A size of zero causes the variable to be deleted.
+                                 If DataSize is zero, then LockVariable must be FALSE since a variable that does not
+                                 exist cannot be locked.
+  @param[in]  Data               The contents for the variable.
+
+  @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 LockVariable, name, and GUID was supplied, or the
+                                 DataSize exceeds the maximum allowed.
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
+  @retval EFI_INVALID_PARAMETER  DataSize is zero and LockVariable is TRUE
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
+  @retval EFI_OUT_OF_RESOURCES   The VariableName is longer than 1018 characters
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
+
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+SetLargeVariable (
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  BOOLEAN                      LockVariable,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  )
+{
+  CHAR16        TempVariableName[MAX_VARIABLE_NAME_SIZE];
+  UINT64        VariableSplitSize;
+  UINT64        RemainingVariableStorage;
+  EFI_STATUS    Status;
+  EFI_STATUS    Status2;
+  UINTN         VariableNameLength;
+  UINTN         Index;
+  UINTN         VariablesSaved;
+  UINT8         *OffsetPtr;
+  UINTN         BytesRemaining;
+  UINTN         SizeToSave;
+
+  //
+  // Check input parameters.
+  //
+  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (DataSize != 0 && Data == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (DataSize == 0 && LockVariable) {
+    DEBUG ((DEBUG_ERROR, "SetLargeVariable: Cannot lock a variable that is being deleted\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VariablesSaved = 0;
+  if (LockVariable && !VarLibIsVariableRequestToLockSupported ()) {
+      Status = EFI_INVALID_PARAMETER;
+      DEBUG ((DEBUG_ERROR, "SetLargeVariable: Variable locking is not currently supported\n"));
+      goto Done;
+  }
+
+  //
+  // Check if the variable is being deleted.
+  //
+  if (DataSize == 0) {
+    DEBUG ((DEBUG_INFO, "SetLargeVariable: Variable is being deleted.\n"));
+    Status = DeleteLargeVariableInternal (VariableName, VendorGuid);
+    goto Done;
+  }
+
+  VariableNameLength  = StrLen (VariableName);
+  VariableSplitSize   = GetVariableSplitSize (VariableNameLength);
+  if (DataSize <= VariableSplitSize) {
+
+    //
+    // A single variable is sufficient to store the data, only create one.
+    //
+    DEBUG ((DEBUG_INFO, "SetLargeVariable: Saving using single variable.\n"));
+    Status = VarLibSetVariable (
+               VariableName,
+               VendorGuid,
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+               DataSize,
+               Data
+               );
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+    if (LockVariable) {
+      Status = VarLibVariableRequestToLock (VariableName, VendorGuid);
+    }
+  } else {
+    //
+    // Multiple variables are needed
+    //
+
+    //
+    // Check the length of the variable name is short enough to allow an integer
+    // to be appended.
+    //
+    if (VariableNameLength >= (MAX_VARIABLE_NAME_SIZE - MAX_VARIABLE_SPLIT_DIGITS)) {
+      Status = EFI_OUT_OF_RESOURCES;
+      DEBUG ((DEBUG_ERROR, "SetLargeVariable: Variable name too long\n"));
+      goto Done;
+    }
+
+    //
+    // Check that it is possible to store the data using less than
+    // MAX_VARIABLE_SPLIT variables
+    //
+    if ((DataSize / (VariableSplitSize - MAX_VARIABLE_SPLIT_DIGITS)) > MAX_VARIABLE_SPLIT) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "SetLargeVariable: More than %d variables are needed to store the data, which exceeds the maximum supported\n",
+        MAX_VARIABLE_SPLIT
+        ));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+
+    //
+    // Check that there is enough space remaining in the UEFI Variable Services
+    // Non-Volatile storage to store the data.
+    //
+    RemainingVariableStorage = GetRemainingVariableStorageSpace ();
+    if (DataSize > RemainingVariableStorage) {
+      DEBUG ((DEBUG_ERROR, "SetLargeVariable: Not enough NV storage space to store the data\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Done;
+    }
+
+    DEBUG ((DEBUG_INFO, "SetLargeVariable: Saving using multiple variables.\n"));
+    OffsetPtr         = (UINT8 *) Data;
+    BytesRemaining    = DataSize;
+    VariablesSaved    = 0;
+
+    //
+    // Store chunks of data in UEFI variables until all data is stored
+    //
+    for (Index = 0; (Index < MAX_VARIABLE_SPLIT) && (BytesRemaining > 0); Index++) {
+      ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+      UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+
+      SizeToSave          = 0;
+      VariableNameLength  = StrLen (TempVariableName);
+      VariableSplitSize   = GetVariableSplitSize (VariableNameLength);
+      if (VariableSplitSize == 0) {
+        DEBUG ((DEBUG_ERROR, "Unable to save variable, out of NV storage space\n"));
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Done;
+      }
+
+      if (BytesRemaining > VariableSplitSize) {
+        SizeToSave = (UINTN) VariableSplitSize;
+      } else {
+        SizeToSave = BytesRemaining;
+      }
+      DEBUG ((DEBUG_INFO, "Saving %s, Guid = %g, Size %d\n", TempVariableName, VendorGuid, SizeToSave));
+      Status = VarLibSetVariable (
+                TempVariableName,
+                VendorGuid,
+                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                SizeToSave,
+                (VOID *) OffsetPtr
+                );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "SetLargeVariable: Error writting variable: Status = %r\n", Status));
+        goto Done;
+      }
+      VariablesSaved  = Index;
+      BytesRemaining -= SizeToSave;
+      OffsetPtr += SizeToSave;
+    }   // End of for loop
+
+    //
+    // If the user requested that the variables be locked, lock them now that
+    // all data is saved.
+    //
+    if (LockVariable) {
+      for (Index = 0; Index < VariablesSaved; Index++) {
+        ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+        UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+
+        DEBUG ((DEBUG_INFO, "Locking %s, Guid = %g\n", TempVariableName, VendorGuid));
+        Status = VarLibVariableRequestToLock (TempVariableName, VendorGuid);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "SetLargeVariable: Error locking variable: Status = %r\n", Status));
+          VariablesSaved = 0;
+          goto Done;
+        }
+      }
+    }
+  }
+
+Done:
+  if (EFI_ERROR (Status) && VariablesSaved > 0) {
+    DEBUG ((DEBUG_ERROR, "SetLargeVariable: An error was encountered, deleting variables with partially stored data\n"));
+    for (Index = 0; Index < VariablesSaved; Index++) {
+      ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
+      UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
+
+      DEBUG ((DEBUG_INFO, "Deleting %s, Guid = %g\n", TempVariableName, VendorGuid));
+      Status2 = VarLibSetVariable (
+                  TempVariableName,
+                  VendorGuid,
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                  0,
+                  NULL
+                  );
+    DEBUG ((DEBUG_ERROR, "SetLargeVariable: Error deleting variable: Status = %r\n", Status2));
+    }
+  }
+  DEBUG ((DEBUG_ERROR, "SetLargeVariable: Status = %r\n", Status));
+  return Status;
+}
-- 
2.27.0.windows.1


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

* Re: [edk2-devel] [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib Nate DeSimone
@ 2021-04-06 21:59   ` Michael Kubacki
  0 siblings, 0 replies; 8+ messages in thread
From: Michael Kubacki @ 2021-04-06 21:59 UTC (permalink / raw)
  To: devel, nathaniel.l.desimone
  Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

Hi Nate,

Feedback is inline.

Most of the items carry over to the VariableWriteLib patch as well but I 
didn't duplicate the response to that patch.

Thanks,
Michael

On 4/6/2021 12:24 PM, Nate DeSimone wrote:
> VariableReadLib is a phase agnostic libary for reading UEFI
> Variables. This library provides the
> MinGetVariable() and MinGetNextVariableName() APIs which
> are usable PEI, DXE, and SMM.
> 
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Michael Kubacki <michael.kubacki@microsoft.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>
> Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
> ---
>   .../MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc |  10 +-
>   .../MinPlatformPkg/Include/Dsc/CorePeiLib.dsc |   9 +-
>   .../Include/Library/VariableReadLib.h         |  87 ++++++++++
>   .../DxeRuntimeVariableReadLib.c               | 115 +++++++++++++
>   .../DxeRuntimeVariableReadLib.inf             |  41 +++++
>   .../PeiVariableReadLib/PeiVariableReadLib.c   | 153 ++++++++++++++++++
>   .../PeiVariableReadLib/PeiVariableReadLib.inf |  42 +++++
>   .../SmmVariableReadCommon.c                   | 114 +++++++++++++
>   .../StandaloneMmVariableReadLib.inf           |  50 ++++++
>   .../StandaloneMmVariableReadLibConstructor.c  |  48 ++++++
>   .../TraditionalMmVariableReadLib.inf          |  49 ++++++
>   .../TraditionalMmVariableReadLibConstructor.c |  48 ++++++
>   .../Intel/MinPlatformPkg/MinPlatformPkg.dsc   |   3 +-
>   13 files changed, 761 insertions(+), 8 deletions(-)
>   create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c
> 
> diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
> index fa9098d525..0db1250ab7 100644
> --- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
> +++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
> @@ -1,7 +1,7 @@
>   ## @file
>   #  Platform description.
>   #
> -# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
> @@ -11,7 +11,7 @@
>     #
>     # Generic EDKII Lib
>     #
> -
> +
>     #
>     # DXE phase common
>     #
> @@ -23,7 +23,7 @@
>     ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
>   
>     HstiLib|MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
> -
> +
>     LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
>   
>     CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
> @@ -46,6 +46,9 @@
>   
>     VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
>   
> +[LibraryClasses.common.DXE_CORE, LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION]
> +  VariableReadLib|MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
> +
>   [LibraryClasses.common.DXE_CORE]
>     HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
>     MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
> @@ -89,6 +92,7 @@
>     CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
>     Tcg2PhysicalPresenceLib|SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
>     BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
> +  VariableReadLib|MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
>   
>   [LibraryClasses.common.SMM_CORE]
>     PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
> diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
> index 2bcaed05a1..d64873ac6d 100644
> --- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
> +++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
> @@ -1,7 +1,7 @@
>   ## @file
>   #  Platform description.
>   #
> -# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
> @@ -10,11 +10,11 @@
>     #
>     # Generic EDKII Lib
>     #
> -
> +
>     #
>     # PEI phase common
>     #
> -
> +
>   [LibraryClasses.common.SEC,LibraryClasses.common.PEI_CORE,LibraryClasses.common.PEIM]
>     S3BootScriptLib|MdePkg/Library/BaseS3BootScriptLibNull/BaseS3BootScriptLibNull.inf
>     PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
> @@ -52,7 +52,7 @@
>   !if gMinPlatformPkgTokenSpaceGuid.PcdPerformanceEnable == TRUE
>     PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
>   !endif
> -
> +
>   [LibraryClasses.common.PEIM]
>     CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
>     TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf
> @@ -70,3 +70,4 @@
>   !if gMinPlatformPkgTokenSpaceGuid.PcdPerformanceEnable == TRUE
>     PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
>   !endif
> +  VariableReadLib|MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
> diff --git a/Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h b/Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
> new file mode 100644
> index 0000000000..6ff762a960
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Include/Library/VariableReadLib.h
> @@ -0,0 +1,87 @@
> +/** @file
> +  Variable Read Lib
> +
> +  This library provides phase agnostic access to the UEFI Variable Services.
> +  This is done by implementing a wrapper on top of the phase specific mechanism
> +  for reading from UEFI variables. For example, the PEI implementation of this
> +  library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +  the UEFI Runtime Services Table, and the SMM implementation uses
> +  EFI_SMM_VARIABLE_PROTOCOL.
> +
> +  Using this library allows code to be written in a generic manner that can be
> +  used in PEI, DXE, or SMM without modification.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +

This file is missing a header guard.

> +#include <Uefi/UefiBaseType.h>
> +
> +/**
> +  Returns the value of a 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.
> +  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
> +                                 attributes bitmask for the variable.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  OUT    UINT32                      *Attributes,    OPTIONAL
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  );
> +
> +/**
> +  Enumerates the current variable names.
> +
> +  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
> +                                    enough to fit input string supplied in VariableName buffer.
> +  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
> +                                    by GetNextVariableName(). On output, returns the Nullterminated
> +                                    string of the current variable.
> +  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
> +                                    GetNextVariableName(). On output, returns the
> +                                    VendorGuid of the current variable.
> +
> +  @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.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetNextVariableName (
> +  IN OUT UINTN                    *VariableNameSize,
> +  IN OUT CHAR16                   *VariableName,
> +  IN OUT EFI_GUID                 *VendorGuid
> +  );
> diff --git a/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
> new file mode 100644
> index 0000000000..f611891d6a
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.c
> @@ -0,0 +1,115 @@
> +/** @file
> +  DXE Variable Read Lib
> +
> +  This library provides phase agnostic access to the UEFI Variable Services.
> +  This is done by implementing a wrapper on top of the phase specific mechanism
> +  for reading from UEFI variables. For example, the PEI implementation of this
> +  library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +  the UEFI Runtime Services Table, and the SMM implementation uses
> +  EFI_SMM_VARIABLE_PROTOCOL.
> +
> +  Using this library allows code to be written in a generic manner that can be
> +  used in PEI, DXE, or SMM without modification.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +
> +/**
> +  Returns the value of a 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.
> +  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
> +                                 attributes bitmask for the variable.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +

It would be nice to have EFI_UNSUPPORTED described as a retval for all 
instances of the library functions.

> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  OUT    UINT32                      *Attributes,    OPTIONAL
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  )
> +{
> +  EFI_STATUS    Status = EFI_UNSUPPORTED;
> +
> +  if (gRT != NULL) {
> +    Status = gRT->GetVariable (
> +                    VariableName,
> +                    VendorGuid,
> +                    Attributes,
> +                    DataSize,
> +                    Data
> +                    );
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Enumerates the current variable names.
> +
> +  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
> +                                    enough to fit input string supplied in VariableName buffer.
> +  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
> +                                    by GetNextVariableName(). On output, returns the Nullterminated
> +                                    string of the current variable.
> +  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
> +                                    GetNextVariableName(). On output, returns the
> +                                    VendorGuid of the current variable.
> +
> +  @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.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetNextVariableName (
> +  IN OUT UINTN                    *VariableNameSize,
> +  IN OUT CHAR16                   *VariableName,
> +  IN OUT EFI_GUID                 *VendorGuid
> +  )
> +{
> +  EFI_STATUS    Status = EFI_UNSUPPORTED;
> +
> +  if (gRT != NULL) {
> +    Status = gRT->GetNextVariableName (
> +                    VariableNameSize,
> +                    VariableName,
> +                    VendorGuid
> +                    );
> +  }
> +  return Status;
> +}
> diff --git a/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
> new file mode 100644
> index 0000000000..848b76344b
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/DxeRuntimeVariableReadLib/DxeRuntimeVariableReadLib.inf
> @@ -0,0 +1,41 @@
> +## @file
> +# Component description file for DXE Variable Read Lib
> +#
> +# This library provides phase agnostic access to the UEFI Variable Services.
> +# This is done by implementing a wrapper on top of the phase specific mechanism
> +# for reading from UEFI variables. For example, the PEI implementation of this
> +# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +# the UEFI Runtime Services Table, and the SMM implementation uses
> +# EFI_SMM_VARIABLE_PROTOCOL.
> +#
> +# Using this library allows code to be written in a generic manner that can be
> +# used in PEI, DXE, or SMM without modification.
> +#
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = DxeRuntimeVariableReadLib
> +  FILE_GUID                      = 9C357AD8-2BF4-450C-9E65-C0938F6D2424
> +  VERSION_STRING                 = 1.0
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
> +  LIBRARY_CLASS                  = VariableReadLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[Sources]
> +  DxeRuntimeVariableReadLib.c
> +
> +[LibraryClasses]
> +  UefiRuntimeServicesTableLib
> +
> +[Protocols]
> +  gEfiVariableArchProtocolGuid    ## CONSUMES
> +
> +[Depex]
> +  gEfiVariableArchProtocolGuid
> diff --git a/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
> new file mode 100644
> index 0000000000..d9fbce7981
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.c
> @@ -0,0 +1,153 @@
> +/** @file
> +  PEI Variable Read Lib
> +
> +  This library provides phase agnostic access to the UEFI Variable Services.
> +  This is done by implementing a wrapper on top of the phase specific mechanism
> +  for reading from UEFI variables. For example, the PEI implementation of this
> +  library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +  the UEFI Runtime Services Table, and the SMM implementation uses
> +  EFI_SMM_VARIABLE_PROTOCOL.
> +
> +  Using this library allows code to be written in a generic manner that can be
> +  used in PEI, DXE, or SMM without modification.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <Ppi/ReadOnlyVariable2.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/PeiServicesLib.h>
> +
> +/**
> +  Returns the value of a 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.
> +  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
> +                                 attributes bitmask for the variable.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  OUT    UINT32                      *Attributes,    OPTIONAL
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  )
> +{
> +  EFI_STATUS                          Status;
> +  EFI_PEI_READ_ONLY_VARIABLE2_PPI     *VariablePpi;
> +
> +  //
> +  // Locate the variable PPI.
> +  //
> +  Status = PeiServicesLocatePpi (
> +             &gEfiPeiReadOnlyVariable2PpiGuid,
> +             0,
> +             NULL,
> +             &VariablePpi
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (VariablePpi != NULL) {
> +    Status = VariablePpi->GetVariable (
> +              VariablePpi,
> +              VariableName,
> +              VendorGuid,
> +              Attributes,
> +              DataSize,
> +              Data
> +              );
> +  } else {
> +    Status = EFI_UNSUPPORTED;
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Enumerates the current variable names.
> +
> +  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
> +                                    enough to fit input string supplied in VariableName buffer.
> +  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
> +                                    by GetNextVariableName(). On output, returns the Nullterminated
> +                                    string of the current variable.
> +  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
> +                                    GetNextVariableName(). On output, returns the
> +                                    VendorGuid of the current variable.
> +
> +  @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.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetNextVariableName (
> +  IN OUT UINTN                    *VariableNameSize,
> +  IN OUT CHAR16                   *VariableName,
> +  IN OUT EFI_GUID                 *VendorGuid
> +  )
> +{
> +  EFI_STATUS                          Status;
> +  EFI_PEI_READ_ONLY_VARIABLE2_PPI     *VariablePpi;
> +
> +  //
> +  // Locate the variable PPI.
> +  //
> +  Status = PeiServicesLocatePpi (
> +             &gEfiPeiReadOnlyVariable2PpiGuid,
> +             0,
> +             NULL,
> +             &VariablePpi
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (VariablePpi != NULL) {
> +    Status = VariablePpi->NextVariableName (
> +              VariablePpi,
> +              VariableNameSize,
> +              VariableName,
> +              VendorGuid
> +              );
> +  } else {
> +    Status = EFI_UNSUPPORTED;
> +  }
> +  return Status;
> +}
> diff --git a/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
> new file mode 100644
> index 0000000000..b1d8a4b9ea
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/PeiVariableReadLib/PeiVariableReadLib.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# Component description file for PEI Variable Read Lib
> +#
> +# This library provides phase agnostic access to the UEFI Variable Services.
> +# This is done by implementing a wrapper on top of the phase specific mechanism
> +# for reading from UEFI variables. For example, the PEI implementation of this
> +# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +# the UEFI Runtime Services Table, and the SMM implementation uses
> +# EFI_SMM_VARIABLE_PROTOCOL.
> +#
> +# Using this library allows code to be written in a generic manner that can be
> +# used in PEI, DXE, or SMM without modification.
> +#
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PeiVariableReadLib
> +  FILE_GUID                      = C8707767-5D9D-476B-81EE-8FAFA7098224
> +  VERSION_STRING                 = 1.0
> +  MODULE_TYPE                    = PEIM
> +  LIBRARY_CLASS                  = VariableReadLib|PEI_CORE PEIM
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[Sources]
> +  PeiVariableReadLib.c
> +
> +[LibraryClasses]
> +  DebugLib
> +  PeiServicesLib
> +
> +[Ppis]
> +  gEfiPeiReadOnlyVariable2PpiGuid   ## CONSUMES
> +
> +[Depex]
> +  gEfiPeiReadOnlyVariable2PpiGuid
> diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
> new file mode 100644
> index 0000000000..b663b93999
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/SmmVariableReadCommon.c
> @@ -0,0 +1,114 @@
> +/** @file
> +  SMM Variable Read Lib
> +
> +  This library provides phase agnostic access to the UEFI Variable Services.
> +  This is done by implementing a wrapper on top of the phase specific mechanism
> +  for reading from UEFI variables.
> +
> +  This is the common implementation pieces that are shared between
> +  traditional SMM and standalone MM.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi/UefiBaseType.h>
> +
> +#include <Protocol/SmmVariable.h>
> +
> +EFI_SMM_VARIABLE_PROTOCOL  *mVariableReadLibSmmVariable = NULL;
> +
> +/**
> +  Returns the value of a 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.
> +  @param[out]      Attributes    If not NULL, a pointer to the memory location to return the
> +                                 attributes bitmask for the variable.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  OUT    UINT32                      *Attributes,    OPTIONAL
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  )
> +{
> +  EFI_STATUS    Status = EFI_UNSUPPORTED;
> +
> +  if (mVariableReadLibSmmVariable != NULL) {
> +    Status = mVariableReadLibSmmVariable->SmmGetVariable (
> +                                            VariableName,
> +                                            VendorGuid,
> +                                            Attributes,
> +                                            DataSize,
> +                                            Data
> +                                            );
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Enumerates the current variable names.
> +
> +  @param[in, out]  VariableNameSize The size of the VariableName buffer. The size must be large
> +                                    enough to fit input string supplied in VariableName buffer.
> +  @param[in, out]  VariableName     On input, supplies the last VariableName that was returned
> +                                    by GetNextVariableName(). On output, returns the Nullterminated
> +                                    string of the current variable.
> +  @param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned by
> +                                    GetNextVariableName(). On output, returns the
> +                                    VendorGuid of the current variable.
> +
> +  @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.
> +  @retval EFI_DEVICE_ERROR      The variable could not be retrieved due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +VarLibGetNextVariableName (
> +  IN OUT UINTN                    *VariableNameSize,
> +  IN OUT CHAR16                   *VariableName,
> +  IN OUT EFI_GUID                 *VendorGuid
> +  )
> +{
> +  EFI_STATUS    Status = EFI_UNSUPPORTED;
> +
> +  if (mVariableReadLibSmmVariable != NULL) {
> +    Status = mVariableReadLibSmmVariable->SmmGetNextVariableName (
> +                                            VariableNameSize,
> +                                            VariableName,
> +                                            VendorGuid
> +                                            );
> +  }
> +  return Status;
> +}
> diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
> new file mode 100644
> index 0000000000..96a4a25fd7
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
> @@ -0,0 +1,50 @@
> +## @file
> +# Component description file for Standalone MM Variable Read Lib
> +#
> +# This library provides phase agnostic access to the UEFI Variable Services.
> +# This is done by implementing a wrapper on top of the phase specific mechanism
> +# for reading from UEFI variables. For example, the PEI implementation of this
> +# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +# the UEFI Runtime Services Table, and the SMM implementation uses
> +# EFI_SMM_VARIABLE_PROTOCOL.
> +#
> +# Using this library allows code to be written in a generic manner that can be
> +# used in PEI, DXE, or SMM without modification.
> +#
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = SmmVariableReadLib

BASE_NAME of "StandaloneMmVariableReadLib" would help distinguish this 
library instance.

> +  FILE_GUID                      = 46246048-856E-4C60-9026-F15E20C03B68
> +  VERSION_STRING                 = 1.0
> +  MODULE_TYPE                    = MM_STANDALONE
> +  PI_SPECIFICATION_VERSION       = 0x00010032
> +  LIBRARY_CLASS                  = VariableReadLib|MM_STANDALONE

I noticed the LIBRARY_CLASS in TraditionalMmVariableReadLib.inf included 
core modules ("DXE_SMM_DRIVER SMM_CORE") whereas this instance does not 
include "MM_CORE_STANDALONE". Was there a particular reason for that?

> +  CONSTRUCTOR                    = StandaloneMmVariableReadLibConstructor
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[Sources]
> +  SmmVariableReadCommon.c
> +  StandaloneMmVariableReadLibConstructor.c
> +
> +[LibraryClasses]
> +  DebugLib
> +  MmServicesTableLib
> +
> +[Guids]
> +
> +[Protocols]
> +  gEfiSmmVariableProtocolGuid   ## CONSUMES
> +
> +[Pcd]
> +
> +[Depex]
> +  gEfiSmmVariableProtocolGuid
> diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
> new file mode 100644
> index 0000000000..d9fb915bb4
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLibConstructor.c
> @@ -0,0 +1,48 @@
> +/** @file
> +  Standalone MM Variable Read Lib
> +
> +  This library provides phase agnostic access to the UEFI Variable Services.
> +  This is done by implementing a wrapper on top of the phase specific mechanism
> +  for reading from UEFI variables.
> +
> +  This is the standalone MM specific LibraryClass constructor.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi/UefiBaseType.h>
> +
> +#include <Protocol/SmmVariable.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/MmServicesTableLib.h>
> +
> +extern EFI_SMM_VARIABLE_PROTOCOL  *mVariableReadLibSmmVariable;
> +
> +/**
> +  The constructor function acquires the EFI SMM Variable Services
> +
> +  @param  ImageHandle   The firmware allocated handle for the EFI image.
> +  @param  SystemTable   A pointer to the MM System Table.
> +
> +  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +StandaloneMmVariableReadLibConstructor (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_MM_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS    Status;
> +
> +  //
> +  // Locate SmmVariableProtocol.
> +  //
> +  Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mVariableReadLibSmmVariable);
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
> new file mode 100644
> index 0000000000..39cd8371dc
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLib.inf
> @@ -0,0 +1,49 @@
> +## @file
> +# Component description file for Traditional MM Variable Read Lib
> +#
> +# This library provides phase agnostic access to the UEFI Variable Services.
> +# This is done by implementing a wrapper on top of the phase specific mechanism
> +# for reading from UEFI variables. For example, the PEI implementation of this
> +# library uses EFI_PEI_READ_ONLY_VARIABLE2_PPI. The DXE implementation accesses
> +# the UEFI Runtime Services Table, and the SMM implementation uses
> +# EFI_SMM_VARIABLE_PROTOCOL.
> +#
> +# Using this library allows code to be written in a generic manner that can be
> +# used in PEI, DXE, or SMM without modification.
> +#
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = TraditionalMmVariableReadLib
> +  FILE_GUID                      = 50910542-A4ED-4142-AF25-25E141C016FC
> +  VERSION_STRING                 = 1.0
> +  MODULE_TYPE                    = DXE_SMM_DRIVER
> +  LIBRARY_CLASS                  = VariableReadLib|DXE_SMM_DRIVER SMM_CORE
> +  CONSTRUCTOR                    = TraditionalMmVariableReadLibConstructor
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[Sources]
> +  SmmVariableReadCommon.c
> +  TraditionalMmVariableReadLibConstructor.c
> +
> +[LibraryClasses]
> +  DebugLib
> +  SmmServicesTableLib
> +
> +[Guids]
> +
> +[Protocols]
> +  gEfiSmmVariableProtocolGuid   ## CONSUMES
> +
> +[Pcd]
> +
> +[Depex]
> +  gEfiSmmVariableProtocolGuid
> diff --git a/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c
> new file mode 100644
> index 0000000000..5d35bedc05
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/SmmVariableReadLib/TraditionalMmVariableReadLibConstructor.c
> @@ -0,0 +1,48 @@
> +/** @file
> +  Traditional MM Variable Read Lib
> +
> +  This library provides phase agnostic access to the UEFI Variable Services.
> +  This is done by implementing a wrapper on top of the phase specific mechanism
> +  for reading from UEFI variables.
> +
> +  This is the traditional SMM specific LibraryClass constructor.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Protocol/SmmVariable.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +
> +extern EFI_SMM_VARIABLE_PROTOCOL  *mVariableReadLibSmmVariable;
> +
> +/**
> +  The constructor function acquires the EFI SMM Variable Services
> +
> +  @param  ImageHandle   The firmware allocated handle for the EFI image.
> +  @param  SystemTable   A pointer to the EFI System Table.
> +
> +  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
> +

This applies to StandaloneMmVariableReadLibConstructor.c as well, the 
constructors could currently return a value other than EFI_SUCCESS.

> +**/
> +EFI_STATUS
> +EFIAPI
> +TraditionalMmVariableReadLibConstructor (
> +  IN EFI_HANDLE         ImageHandle,
> +  IN EFI_SYSTEM_TABLE   *SystemTable
> +  )
> +{
> +  EFI_STATUS    Status;
> +
> +  //
> +  // Locate SmmVariableProtocol.
> +  //
> +  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mVariableReadLibSmmVariable);
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git a/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc b/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
> index 998ee79095..18b5c6f5b1 100644
> --- a/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
> +++ b/Platform/Intel/MinPlatformPkg/MinPlatformPkg.dsc
> @@ -1,7 +1,7 @@
>   ## @file
>   #  Platform description.
>   #
> -# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
>   # Copyright (c) Microsoft Corporation.<BR>
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -120,6 +120,7 @@
>     PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
>     SpiFlashCommonLib|MinPlatformPkg/Flash/Library/SpiFlashCommonLibNull/SpiFlashCommonLibNull.inf
>     StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
> +  VariableReadLib|MinPlatformPkg/Library/SmmVariableReadLib/StandaloneMmVariableReadLib.inf
>   
>   ###################################################################################################
>   #
> 

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

* Re: [edk2-devel] [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib
  2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib Nate DeSimone
@ 2021-04-06 22:01   ` Michael Kubacki
  2021-04-07  3:05     ` Nate DeSimone
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Kubacki @ 2021-04-06 22:01 UTC (permalink / raw)
  To: devel, nathaniel.l.desimone
  Cc: Chasel Chiu, Liming Gao, Eric Dong, Michael Kubacki, Isaac Oram

Hi Nate,

Feedback is inline.

Please carry over applicable feedback to LargeVariableWriteLib, I did 
not duplicate the response there.

Thanks,
Michael

On 4/6/2021 12:24 PM, Nate DeSimone wrote:
> LargeVariableReadLib is used to retrieve large data sets using
> the UEFI Variable Services. At time of writting, most UEFI
> Variable Services implementations to not allow more than 64KB
> of data to be stored in a single UEFI variable. This library
> will split data sets across multiple variables as needed.
> 
> It adds the GetLargeVariable() API to provide this service.
> 
> The primary use for this library is to create binary compatible
> drivers and OpROMs which need to work both with TianoCore and
> other UEFI PI implementations. When customizing and recompiling
> the platform firmware image is possible, adjusting the value of
> PcdMaxVariableSize may provide a simpler solution to this
> problem.
> 
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Michael Kubacki <michael.kubacki@microsoft.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>
> Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
> ---
>   .../Include/Dsc/CoreCommonLib.dsc             |   5 +-
>   .../Include/Library/LargeVariableReadLib.h    |  56 +++++
>   .../BaseLargeVariableReadLib.inf              |  50 +++++
>   .../LargeVariableReadLib.c                    | 199 ++++++++++++++++++
>   4 files changed, 308 insertions(+), 2 deletions(-)
>   create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
> 
> diff --git a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
> index cf2940cf02..5f2ad3f0f0 100644
> --- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
> +++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
> @@ -135,13 +135,14 @@
>     VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
>     PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
>     AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
> -
> +
>   !if gMinPlatformPkgTokenSpaceGuid.PcdUefiSecureBootEnable == TRUE
>     AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
>   !endif
>   
>     SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
>     BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
> +  LargeVariableReadLib|MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
>   
>     #
>     # CryptLib
> @@ -165,4 +166,4 @@
>   
>     SmbusLib|MdePkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.inf
>     VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
> -  VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
> \ No newline at end of file
> +  VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
> diff --git a/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
> new file mode 100644
> index 0000000000..5579492727
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
> @@ -0,0 +1,56 @@
> +/** @file
> +  Large Variable Read Lib
> +
> +  This library is used to retrieve large data sets using the UEFI Variable
> +  Services. At time of writing, most UEFI Variable Services implementations to
> +  not allow more than 64KB of data to be stored in a single UEFI variable. This
> +  library will split data sets across multiple variables as needed.
> +
> +  In the case where more than one variable is needed to store the data, an
> +  integer number will be added to the end of the variable name. This number
> +  will be incremented for each variable as needed to retrieve the entire data
> +  set.
> +
> +  The primary use for this library is to create binary compatible drivers
> +  and OpROMs which need to work both with TianoCore and other UEFI PI
> +  implementations. When customizing and recompiling the platform firmware image
> +  is possible, adjusting the value of PcdMaxVariableSize may provide a simpler
> +  solution to this problem.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +

Similar comment to VariableReadLib/VariableWriteLib, header guard is 
missing.

> +#include <Uefi/UefiBaseType.h>
> +
> +/**
> +  Returns the value of a large 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.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetLargeVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  );
> diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
> new file mode 100644
> index 0000000000..822febd62b
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
> @@ -0,0 +1,50 @@
> +## @file
> +# Component description file for Large Variable Read Library
> +#
> +# This library is used to retrieve large data sets using the UEFI Variable
> +# Services. At time of writing, most UEFI Variable Services implementations to
> +# not allow more than 64KB of data to be stored in a single UEFI variable. This
> +# library will split data sets across multiple variables as needed.
> +#
> +# In the case where more than one variable is needed to store the data, an
> +# integer number will be added to the end of the variable name. This number
> +# will be incremented for each variable as needed to retrieve the entire data
> +# set.
> +#
> +# The primary use for this library is to create binary compatible drivers
> +# and OpROMs which need to work both with TianoCore and other UEFI PI
> +# implementations. When customizing and recompiling the platform firmware image
> +# is possible, adjusting the value of PcdMaxVariableSize may provide a simpler
> +# solution to this problem.
> +#
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = BaseLargeVariableReadLib
> +  FILE_GUID                      = 4E9D7D31-A7A0-4004-AE93-D12F1AB08730
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = LargeVariableReadLib
> +
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 EBC
> +#
> +
> +[Sources]
> +  LargeVariableReadLib.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MinPlatformPkg/MinPlatformPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  PrintLib
> +  VariableReadLib
> diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
> new file mode 100644
> index 0000000000..115f3aeb17
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
> @@ -0,0 +1,199 @@
> +/** @file
> +  Large Variable Read Lib
> +
> +  This library is used to retrieve large data sets using the UEFI Variable
> +  Services. At time of writing, most UEFI Variable Services implementations to
> +  not allow more than 64KB of data to be stored in a single UEFI variable. This
> +  library will split data sets across multiple variables as needed.
> +
> +  In the case where more than one variable is needed to store the data, an
> +  integer number will be added to the end of the variable name. This number
> +  will be incremented for each variable as needed to retrieve the entire data
> +  set.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/VariableReadLib.h>
> +
> +//
> +// 1024 was choosen because this is the size of the SMM communication buffer
> +// used by VariableDxeSmm to transfer the VariableName from DXE to SMM. Choosing
> +// the same size will prevent this library from limiting variable names any
> +// more than the MdeModulePkg implementation of UEFI Variable Services does.
> +//
> +#define MAX_VARIABLE_NAME_SIZE      1024
> +

It would be nice to share a definition of these values with 
LargeVariableWriteLib to prevent the two from potentially getting out of 
sync.

> +//
> +// The 2012 Windows Hardware Requirements specified a minimum variable size of
> +// 32KB. By setting the maximum allowed number of variables to 0x20000, this
> +// allows up to 4GB of data to be stored on most UEFI implementations in
> +// existence. Older UEFI implementations were known to only provide 8KB per
> +// variable. In this case, up to 1GB can be stored. Since 1GB vastly exceeds the
> +// size of any known NvStorage FV, choosing this number should effectively
> +// enable all available NvStorage space to be used to store the given data.
> +//
> +#define MAX_VARIABLE_SPLIT          131072  // 0x20000
> +
> +//
> +// There are 6 digits in the number 131072, which means the length of the string
> +// representation of this number will be at most 6 characters long.
> +//
> +#define MAX_VARIABLE_SPLIT_DIGITS   6
> +
> +/**
> +  Returns the value of a large 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.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetLargeVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  )
> +{
> +  CHAR16        TempVariableName[MAX_VARIABLE_NAME_SIZE];
> +  EFI_STATUS    Status;
> +  UINTN         TotalSize;
> +  UINTN         VarDataSize;
> +  UINTN         Index;
> +  UINTN         VariableSize;
> +  UINTN         BytesRemaining;
> +  UINT8         *OffsetPtr;
> +
> +  VarDataSize = 0;
> +
> +  //
> +  // First check if a variable with the given name exists
> +  //
> +  Status = VarLibGetVariable (VariableName, VendorGuid, NULL, &VarDataSize, NULL);
> +  if (Status == EFI_BUFFER_TOO_SMALL) {
> +    if (*DataSize >= VarDataSize) {
> +      if (Data == NULL) {
> +        Status = EFI_INVALID_PARAMETER;
> +        goto Done;
> +      }
> +      DEBUG ((DEBUG_INFO, "GetLargeVariable: Single Variable Found\n"));

This is somewhat subjective but do you think the message above should 
remain DEBUG_INFO? It seems like DEBUG_VERBOSE might be appropriate 
(same to counterpart messages in other places).

> +      Status = VarLibGetVariable (VariableName, VendorGuid, NULL, DataSize, Data);
> +      goto Done;
> +    } else {
> +      *DataSize = VarDataSize;
> +      Status = EFI_BUFFER_TOO_SMALL;
> +      goto Done;
> +    }
> +
> +  } else if (Status == EFI_NOT_FOUND) {
> +    //
> +    // Check if the first variable of a multi-variable set exists
> +    //
> +    if (StrLen (VariableName) >= (MAX_VARIABLE_NAME_SIZE - MAX_VARIABLE_SPLIT_DIGITS)) {
> +      DEBUG ((DEBUG_ERROR, "GetLargeVariable: Variable name too long\n"));
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto Done;
> +    }
> +
> +    VarDataSize = 0;
> +    Index       = 0;
> +    ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
> +    UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
> +    Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VarDataSize, NULL);
> +
> +    if (Status == EFI_BUFFER_TOO_SMALL) {
> +      //
> +      // The first variable exists. Calculate the total size of all the variables.
> +      //
> +      DEBUG ((DEBUG_INFO, "GetLargeVariable: Multiple Variables Found\n"));
> +      TotalSize = 0;
> +      for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
> +        VarDataSize = 0;
> +        ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
> +        UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
> +        Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VarDataSize, NULL);
> +        if (Status != EFI_BUFFER_TOO_SMALL) {
> +          break;
> +        }
> +        TotalSize += VarDataSize;
> +      }
> +      DEBUG ((DEBUG_INFO, "TotalSize = %d, NumVariables = %d\n", TotalSize, Index));
> +
> +      //
> +      // Check if the user provided a large enough buffer
> +      //
> +      if (*DataSize >= TotalSize) {
> +        if (Data == NULL) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto Done;
> +        }
> +
> +        //
> +        // Read the data from all variables
> +        //
> +        OffsetPtr       = (UINT8 *) Data;
> +        BytesRemaining  = *DataSize;
> +        for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
> +          VarDataSize = 0;
> +          ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
> +          UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
> +          VariableSize = BytesRemaining;
> +          DEBUG ((DEBUG_INFO, "Reading %s, Guid = %g,", TempVariableName, VendorGuid));
> +          Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VariableSize, (VOID *) OffsetPtr);
> +          DEBUG ((DEBUG_INFO, " Size %d\n", VariableSize));
> +          if (EFI_ERROR (Status)) {
> +            if (Status == EFI_NOT_FOUND) {
> +              DEBUG ((DEBUG_INFO, "No more variables found\n"));
> +              Status = EFI_SUCCESS;   // The end has been reached
> +            }
> +            goto Done;
> +          }
> +
> +          if (VariableSize < BytesRemaining) {
> +            BytesRemaining -= VariableSize;
> +            OffsetPtr += VariableSize;
> +          } else {
> +            DEBUG ((DEBUG_INFO, "All data has been read\n"));
> +            BytesRemaining = 0;
> +            break;
> +          }
> +        }   //End of for loop
> +
> +        goto Done;
> +      } else {
> +        *DataSize = TotalSize;
> +        Status = EFI_BUFFER_TOO_SMALL;
> +        goto Done;
> +      }
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +  }
> +
> +Done:
> +  DEBUG ((DEBUG_ERROR, "GetLargeVariable: Status = %r\n", Status));
> +  return Status;
> +}
> 

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

* Re: [edk2-devel] [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib
  2021-04-06 22:01   ` [edk2-devel] " Michael Kubacki
@ 2021-04-07  3:05     ` Nate DeSimone
  0 siblings, 0 replies; 8+ messages in thread
From: Nate DeSimone @ 2021-04-07  3:05 UTC (permalink / raw)
  To: devel@edk2.groups.io, mikuback@linux.microsoft.com
  Cc: Chiu, Chasel, Liming Gao, Dong, Eric, Michael Kubacki,
	Oram, Isaac W

Hi Michael,

Thank you for the great feedback! I believe I have all of it addressed in V4.

Thanks,
Nate

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Michael Kubacki
Sent: Tuesday, April 6, 2021 3:01 PM
To: devel@edk2.groups.io; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>
Cc: Chiu, Chasel <chasel.chiu@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>; Dong, Eric <eric.dong@intel.com>; Michael Kubacki <michael.kubacki@microsoft.com>; Oram, Isaac W <isaac.w.oram@intel.com>
Subject: Re: [edk2-devel] [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib

Hi Nate,

Feedback is inline.

Please carry over applicable feedback to LargeVariableWriteLib, I did not duplicate the response there.

Thanks,
Michael

On 4/6/2021 12:24 PM, Nate DeSimone wrote:
> LargeVariableReadLib is used to retrieve large data sets using the 
> UEFI Variable Services. At time of writting, most UEFI Variable 
> Services implementations to not allow more than 64KB of data to be 
> stored in a single UEFI variable. This library will split data sets 
> across multiple variables as needed.
> 
> It adds the GetLargeVariable() API to provide this service.
> 
> The primary use for this library is to create binary compatible 
> drivers and OpROMs which need to work both with TianoCore and other 
> UEFI PI implementations. When customizing and recompiling the platform 
> firmware image is possible, adjusting the value of PcdMaxVariableSize 
> may provide a simpler solution to this problem.
> 
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Michael Kubacki <michael.kubacki@microsoft.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>
> Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
> ---
>   .../Include/Dsc/CoreCommonLib.dsc             |   5 +-
>   .../Include/Library/LargeVariableReadLib.h    |  56 +++++
>   .../BaseLargeVariableReadLib.inf              |  50 +++++
>   .../LargeVariableReadLib.c                    | 199 ++++++++++++++++++
>   4 files changed, 308 insertions(+), 2 deletions(-)
>   create mode 100644 Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
>   create mode 100644 Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
>   create mode 100644 
> Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVa
> riableReadLib.c
> 
> diff --git 
> a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc 
> b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
> index cf2940cf02..5f2ad3f0f0 100644
> --- a/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
> +++ b/Platform/Intel/MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
> @@ -135,13 +135,14 @@
>     VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
>     PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
>     
> AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableL
> ibNull.inf
> -
> +
>   !if gMinPlatformPkgTokenSpaceGuid.PcdUefiSecureBootEnable == TRUE
>     AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
>   !endif
>   
>     SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
>     
> BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib
> .inf
> +  
> + LargeVariableReadLib|MinPlatformPkg/Library/BaseLargeVariableReadLib
> + /BaseLargeVariableReadLib.inf
>   
>     #
>     # CryptLib
> @@ -165,4 +166,4 @@
>   
>     SmbusLib|MdePkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.inf
>     
> VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolic
> yLib.inf
> -  
> VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/V
> ariablePolicyHelperLib.inf
> \ No newline at end of file
> +  
> + VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib
> + /VariablePolicyHelperLib.inf
> diff --git 
> a/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h 
> b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
> new file mode 100644
> index 0000000000..5579492727
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadL
> +++ ib.h
> @@ -0,0 +1,56 @@
> +/** @file
> +  Large Variable Read Lib
> +
> +  This library is used to retrieve large data sets using the UEFI 
> + Variable  Services. At time of writing, most UEFI Variable Services 
> + implementations to  not allow more than 64KB of data to be stored in 
> + a single UEFI variable. This  library will split data sets across multiple variables as needed.
> +
> +  In the case where more than one variable is needed to store the 
> + data, an  integer number will be added to the end of the variable 
> + name. This number  will be incremented for each variable as needed 
> + to retrieve the entire data  set.
> +
> +  The primary use for this library is to create binary compatible 
> + drivers  and OpROMs which need to work both with TianoCore and other 
> + UEFI PI  implementations. When customizing and recompiling the 
> + platform firmware image  is possible, adjusting the value of 
> + PcdMaxVariableSize may provide a simpler  solution to this problem.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +

Similar comment to VariableReadLib/VariableWriteLib, header guard is missing.

> +#include <Uefi/UefiBaseType.h>
> +
> +/**
> +  Returns the value of a large 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.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetLargeVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  );
> diff --git 
> a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseL
> argeVariableReadLib.inf 
> b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseL
> argeVariableReadLib.inf
> new file mode 100644
> index 0000000000..822febd62b
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/B
> +++ aseLargeVariableReadLib.inf
> @@ -0,0 +1,50 @@
> +## @file
> +# Component description file for Large Variable Read Library # # This 
> +library is used to retrieve large data sets using the UEFI Variable # 
> +Services. At time of writing, most UEFI Variable Services 
> +implementations to # not allow more than 64KB of data to be stored in 
> +a single UEFI variable. This # library will split data sets across multiple variables as needed.
> +#
> +# In the case where more than one variable is needed to store the 
> +data, an # integer number will be added to the end of the variable 
> +name. This number # will be incremented for each variable as needed 
> +to retrieve the entire data # set.
> +#
> +# The primary use for this library is to create binary compatible 
> +drivers # and OpROMs which need to work both with TianoCore and other 
> +UEFI PI # implementations. When customizing and recompiling the 
> +platform firmware image # is possible, adjusting the value of 
> +PcdMaxVariableSize may provide a simpler # solution to this problem.
> +#
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> # # 
> +SPDX-License-Identifier: BSD-2-Clause-Patent # ##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = BaseLargeVariableReadLib
> +  FILE_GUID                      = 4E9D7D31-A7A0-4004-AE93-D12F1AB08730
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = LargeVariableReadLib
> +
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 EBC
> +#
> +
> +[Sources]
> +  LargeVariableReadLib.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MinPlatformPkg/MinPlatformPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  PrintLib
> +  VariableReadLib
> diff --git 
> a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/Large
> VariableReadLib.c 
> b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/Large
> VariableReadLib.c
> new file mode 100644
> index 0000000000..115f3aeb17
> --- /dev/null
> +++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/L
> +++ argeVariableReadLib.c
> @@ -0,0 +1,199 @@
> +/** @file
> +  Large Variable Read Lib
> +
> +  This library is used to retrieve large data sets using the UEFI 
> + Variable  Services. At time of writing, most UEFI Variable Services 
> + implementations to  not allow more than 64KB of data to be stored in 
> + a single UEFI variable. This  library will split data sets across multiple variables as needed.
> +
> +  In the case where more than one variable is needed to store the 
> + data, an  integer number will be added to the end of the variable 
> + name. This number  will be incremented for each variable as needed 
> + to retrieve the entire data  set.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/VariableReadLib.h>
> +
> +//
> +// 1024 was choosen because this is the size of the SMM communication 
> +buffer // used by VariableDxeSmm to transfer the VariableName from 
> +DXE to SMM. Choosing // the same size will prevent this library from 
> +limiting variable names any // more than the MdeModulePkg implementation of UEFI Variable Services does.
> +//
> +#define MAX_VARIABLE_NAME_SIZE      1024
> +

It would be nice to share a definition of these values with LargeVariableWriteLib to prevent the two from potentially getting out of sync.

> +//
> +// The 2012 Windows Hardware Requirements specified a minimum 
> +variable size of // 32KB. By setting the maximum allowed number of 
> +variables to 0x20000, this // allows up to 4GB of data to be stored 
> +on most UEFI implementations in // existence. Older UEFI 
> +implementations were known to only provide 8KB per // variable. In 
> +this case, up to 1GB can be stored. Since 1GB vastly exceeds the // 
> +size of any known NvStorage FV, choosing this number should effectively // enable all available NvStorage space to be used to store the given data.
> +//
> +#define MAX_VARIABLE_SPLIT          131072  // 0x20000
> +
> +//
> +// There are 6 digits in the number 131072, which means the length of 
> +the string // representation of this number will be at most 6 characters long.
> +//
> +#define MAX_VARIABLE_SPLIT_DIGITS   6
> +
> +/**
> +  Returns the value of a large 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.
> +  @param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.
> +                                 On output the size of data returned in Data.
> +  @param[out]      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.
> +
> +  @retval EFI_SUCCESS            The function completed successfully.
> +  @retval EFI_NOT_FOUND          The variable was not found.
> +  @retval EFI_BUFFER_TOO_SMALL   The DataSize is too small for the result.
> +  @retval EFI_INVALID_PARAMETER  VariableName is NULL.
> +  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.
> +  @retval EFI_INVALID_PARAMETER  DataSize is NULL.
> +  @retval EFI_INVALID_PARAMETER  The DataSize is not too small and Data is NULL.
> +  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
> +  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetLargeVariable (
> +  IN     CHAR16                      *VariableName,
> +  IN     EFI_GUID                    *VendorGuid,
> +  IN OUT UINTN                       *DataSize,
> +  OUT    VOID                        *Data           OPTIONAL
> +  )
> +{
> +  CHAR16        TempVariableName[MAX_VARIABLE_NAME_SIZE];
> +  EFI_STATUS    Status;
> +  UINTN         TotalSize;
> +  UINTN         VarDataSize;
> +  UINTN         Index;
> +  UINTN         VariableSize;
> +  UINTN         BytesRemaining;
> +  UINT8         *OffsetPtr;
> +
> +  VarDataSize = 0;
> +
> +  //
> +  // First check if a variable with the given name exists  //  Status 
> + = VarLibGetVariable (VariableName, VendorGuid, NULL, &VarDataSize, 
> + NULL);  if (Status == EFI_BUFFER_TOO_SMALL) {
> +    if (*DataSize >= VarDataSize) {
> +      if (Data == NULL) {
> +        Status = EFI_INVALID_PARAMETER;
> +        goto Done;
> +      }
> +      DEBUG ((DEBUG_INFO, "GetLargeVariable: Single Variable 
> + Found\n"));

This is somewhat subjective but do you think the message above should remain DEBUG_INFO? It seems like DEBUG_VERBOSE might be appropriate (same to counterpart messages in other places).

> +      Status = VarLibGetVariable (VariableName, VendorGuid, NULL, DataSize, Data);
> +      goto Done;
> +    } else {
> +      *DataSize = VarDataSize;
> +      Status = EFI_BUFFER_TOO_SMALL;
> +      goto Done;
> +    }
> +
> +  } else if (Status == EFI_NOT_FOUND) {
> +    //
> +    // Check if the first variable of a multi-variable set exists
> +    //
> +    if (StrLen (VariableName) >= (MAX_VARIABLE_NAME_SIZE - MAX_VARIABLE_SPLIT_DIGITS)) {
> +      DEBUG ((DEBUG_ERROR, "GetLargeVariable: Variable name too long\n"));
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto Done;
> +    }
> +
> +    VarDataSize = 0;
> +    Index       = 0;
> +    ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
> +    UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
> +    Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, 
> + &VarDataSize, NULL);
> +
> +    if (Status == EFI_BUFFER_TOO_SMALL) {
> +      //
> +      // The first variable exists. Calculate the total size of all the variables.
> +      //
> +      DEBUG ((DEBUG_INFO, "GetLargeVariable: Multiple Variables Found\n"));
> +      TotalSize = 0;
> +      for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
> +        VarDataSize = 0;
> +        ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
> +        UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
> +        Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VarDataSize, NULL);
> +        if (Status != EFI_BUFFER_TOO_SMALL) {
> +          break;
> +        }
> +        TotalSize += VarDataSize;
> +      }
> +      DEBUG ((DEBUG_INFO, "TotalSize = %d, NumVariables = %d\n", 
> + TotalSize, Index));
> +
> +      //
> +      // Check if the user provided a large enough buffer
> +      //
> +      if (*DataSize >= TotalSize) {
> +        if (Data == NULL) {
> +          Status = EFI_INVALID_PARAMETER;
> +          goto Done;
> +        }
> +
> +        //
> +        // Read the data from all variables
> +        //
> +        OffsetPtr       = (UINT8 *) Data;
> +        BytesRemaining  = *DataSize;
> +        for (Index = 0; Index < MAX_VARIABLE_SPLIT; Index++) {
> +          VarDataSize = 0;
> +          ZeroMem (TempVariableName, MAX_VARIABLE_NAME_SIZE);
> +          UnicodeSPrint (TempVariableName, MAX_VARIABLE_NAME_SIZE, L"%s%d", VariableName, Index);
> +          VariableSize = BytesRemaining;
> +          DEBUG ((DEBUG_INFO, "Reading %s, Guid = %g,", TempVariableName, VendorGuid));
> +          Status = VarLibGetVariable (TempVariableName, VendorGuid, NULL, &VariableSize, (VOID *) OffsetPtr);
> +          DEBUG ((DEBUG_INFO, " Size %d\n", VariableSize));
> +          if (EFI_ERROR (Status)) {
> +            if (Status == EFI_NOT_FOUND) {
> +              DEBUG ((DEBUG_INFO, "No more variables found\n"));
> +              Status = EFI_SUCCESS;   // The end has been reached
> +            }
> +            goto Done;
> +          }
> +
> +          if (VariableSize < BytesRemaining) {
> +            BytesRemaining -= VariableSize;
> +            OffsetPtr += VariableSize;
> +          } else {
> +            DEBUG ((DEBUG_INFO, "All data has been read\n"));
> +            BytesRemaining = 0;
> +            break;
> +          }
> +        }   //End of for loop
> +
> +        goto Done;
> +      } else {
> +        *DataSize = TotalSize;
> +        Status = EFI_BUFFER_TOO_SMALL;
> +        goto Done;
> +      }
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +  }
> +
> +Done:
> +  DEBUG ((DEBUG_ERROR, "GetLargeVariable: Status = %r\n", Status));
> +  return Status;
> +}
> 






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

end of thread, other threads:[~2021-04-07  3:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-04-06 19:24 [edk2-platforms] [PATCH v3 0/4] Add Large Variable Libraries Nate DeSimone
2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 1/4] MinPlatformPkg: Add VariableReadLib Nate DeSimone
2021-04-06 21:59   ` [edk2-devel] " Michael Kubacki
2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 2/4] MinPlatformPkg: Add VariableWriteLib Nate DeSimone
2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib Nate DeSimone
2021-04-06 22:01   ` [edk2-devel] " Michael Kubacki
2021-04-07  3:05     ` Nate DeSimone
2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 4/4] MinPlatformPkg: Add LargeVariableWriteLib Nate DeSimone

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