From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga04.intel.com (mga04.intel.com []) by mx.groups.io with SMTP id smtpd.web11.25392.1617411658556829068 for ; Fri, 02 Apr 2021 18:00:58 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: nathaniel.l.desimone@intel.com) IronPort-SDR: bTwQEDCqK5stffdBxeUXfzvKG0ucv2oTimZYnIcLNXzLWXVnKE7ZNgShRttG4Lv61CZixELtcv 9LSimHf7lieg== X-IronPort-AV: E=McAfee;i="6000,8403,9942"; a="190327240" X-IronPort-AV: E=Sophos;i="5.81,300,1610438400"; d="scan'208";a="190327240" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Apr 2021 18:00:58 -0700 IronPort-SDR: skDmu7gidI+fDiEhXQc1Z0leu1NvgnYq4FyZk7nVh1tQ2E23wPj67UpcZE2guZntzS2PceEaGK cgsd/dWjoVyA== X-IronPort-AV: E=Sophos;i="5.81,300,1610438400"; d="scan'208";a="611473879" Received: from nldesimo-desk1.amr.corp.intel.com ([10.209.65.169]) by fmsmga005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Apr 2021 18:00:57 -0700 From: "Nate DeSimone" To: devel@edk2.groups.io Cc: Chasel Chiu , Liming Gao , Eric Dong , Michael Kubacki , Isaac Oram Subject: [edk2-platforms] [PATCH v1 3/4] MinPlatformPkg: Add LargeVariableReadLib Date: Fri, 2 Apr 2021 18:00:34 -0700 Message-Id: <20210403010035.1906-4-nathaniel.l.desimone@intel.com> X-Mailer: git-send-email 2.27.0.windows.1 In-Reply-To: <20210403010035.1906-1-nathaniel.l.desimone@intel.com> References: <20210403010035.1906-1-nathaniel.l.desimone@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 Cc: Liming Gao Cc: Eric Dong Cc: Michael Kubacki Cc: Isaac Oram Signed-off-by: Nate DeSimone --- .../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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + 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.
+# +# 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#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