From: "Michael Kubacki" <mikuback@linux.microsoft.com>
To: devel@edk2.groups.io, nathaniel.l.desimone@intel.com
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: Re: [edk2-devel] [edk2-platforms] [PATCH v3 3/4] MinPlatformPkg: Add LargeVariableReadLib
Date: Tue, 6 Apr 2021 15:01:03 -0700 [thread overview]
Message-ID: <88afacdc-4b7c-bf0f-dd88-591ef640330e@linux.microsoft.com> (raw)
In-Reply-To: <20210406192411.6888-4-nathaniel.l.desimone@intel.com>
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;
> +}
>
next prev parent reply other threads:[~2021-04-06 22:01 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Michael Kubacki [this message]
2021-04-07 3:05 ` [edk2-devel] " Nate DeSimone
2021-04-06 19:24 ` [edk2-platforms] [PATCH v3 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=88afacdc-4b7c-bf0f-dd88-591ef640330e@linux.microsoft.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