public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: devel@edk2.groups.io
Cc: Chasel Chiu <chasel.chiu@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Eric Dong <eric.dong@intel.com>,
	Michael Kubacki <michael.kubacki@microsoft.com>,
	Isaac Oram <isaac.w.oram@intel.com>
Subject: [edk2-platforms] [PATCH v1 3/4] MinPlatformPkg: Add LargeVariableReadLib
Date: Fri,  2 Apr 2021 18:00:34 -0700	[thread overview]
Message-ID: <20210403010035.1906-4-nathaniel.l.desimone@intel.com> (raw)
In-Reply-To: <20210403010035.1906-1-nathaniel.l.desimone@intel.com>

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.

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>
---
 .../Include/Dsc/CoreCommonLib.dsc             |   5 +-
 .../Include/Library/LargeVariableReadLib.h    |  45 +++++
 .../BaseLargeVariableReadLib.inf              |  41 +++++
 .../LargeVariableReadLib.c                    | 164 ++++++++++++++++++
 4 files changed, 253 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..5f4912575c
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
@@ -0,0 +1,45 @@
+/** @file
+  Large Variable Read 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.
+
+  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..46a07707fc
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
@@ -0,0 +1,41 @@
+## @file
+# Component description file for Large Variable Read 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.
+#
+# 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
+
+[Pcd]
diff --git a/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
new file mode 100644
index 0000000000..f1733616e1
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/LargeVariableReadLib.c
@@ -0,0 +1,164 @@
+/** @file
+  Large Variable Read 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.
+
+  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>
+
+#define MAX_VARIABLE_NAME_SIZE      1024
+#define MAX_VARIABLE_SPLIT          131072
+#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 = MinGetVariable (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 = MinGetVariable (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 = MinGetVariable (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 = MinGetVariable (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 = MinGetVariable (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;
+          }
+        }
+        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


  parent reply	other threads:[~2021-04-03  1:00 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-03  1:00 [edk2-platforms] [PATCH v1 0/4] Add Large Variable Libraries Nate DeSimone
2021-04-03  1:00 ` [edk2-platforms] [PATCH v1 1/4] MinPlatformPkg: Add VariableReadLib Nate DeSimone
2021-04-03  1:00 ` [edk2-platforms] [PATCH v1 2/4] MinPlatformPkg: Add VariableWriteLib Nate DeSimone
2021-04-03  1:00 ` Nate DeSimone [this message]
2021-04-03  1:00 ` [edk2-platforms] [PATCH v1 4/4] MinPlatformPkg: Add LargeVariableWriteLib Nate DeSimone

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20210403010035.1906-4-nathaniel.l.desimone@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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