Date   

[GSoC proposal] Secure Image Loader

Marvin Häuser
 

Good day everyone,

I'll keep the introduction brief because I've been around for a while now. :)
I'm Marvin Häuser, a third-year Computer Science student from TU Kaiserslautern, Germany. Late last year, my colleague Vitaly from ISP RAS and me introduced a formally verified Image Loader for UEFI usage at ISP RAS Open[1] due to various defects we outlined in the corresponding paper. Thank you once again Laszlo for your *incredible* review work on the publication part.

I now want to make an effort to mainline it, preferably as part of the current Google Summer of Code event. To be clear, my internship at ISP RAS has concluded, and while Vitaly will be available for design discussion, he has other priorities at the moment and the practical part will be on me. I have previously submitted a proposal via the GSoC website for your review.

There are many things to consider:
1. The Image Loader is a core component, and there needs to be a significant level of quality and security assurance.
2. Being consumed by many packages, the proposed patch set will take a lot of time to review and integrate.
3. During my initial exploration, I discovered defective PPIs and protocols (e.g. returning data with no corresponding size) originating from the UEFI PI and UEFI specifications. Changes need to be discussed, settled on, and submitted to the UEFI Forum.
4. Some UEFI APIs like the Security Architecture protocols are inconveniently abstract, see 5.
5. Some of the current code does not use the existing context, or accesses it outside of the exposed APIs. The control flow of the dispatchers may need to be adapted to make the context available to appropriate APIs.

But obviously there are not only unpleasant considerations:
A. The Image Loader is mostly formally verified, and only very few changes will be required from the last proven state. This gives a lot of trust in its correctness and safety.
B. All outlined defects that are of critical nature have been fixed successfully.
C. The Image Loader has been tested with real-world code loading real-world OSes on thousands of machines in the past few months, including rejecting malformed images (configurable by PCD).
D. The new APIs will centralise everything PE, reducing code duplication and potentially unsafe operations.
E. Centralising and reduced parse duplication may improve overall boot performance.
F. The code has been coverage-tested to not contain dead code.
G. The code has been fuzz-tested including sanitizers to not invoke undefined behaviour.
H. I already managed to identify a malformed image in OVMF with its help (incorrectly reported section alignment of an Intel IPXE driver). A fix will be submitted shortly.
I. I plan to support PE section permissions, allowing for read-only data segments when enabled.

There are likely more points for both lists, but I hope this gives a decent starting point for discussion. What are your thoughts on the matter? I strongly encourage everyone to read the section regarding defects of our publication[2] to better understand the motivation. The vague points above can of course be elaborated in due time, as you see fit.

Thank you for your time!

Best regards,
Marvin


[1] https://github.com/mhaeuser/ISPRASOpen-SecurePE
[2] https://arxiv.org/pdf/2012.05471.pdf


Re: VirtIO Sound Driver (GSoC 2021)

Marvin Häuser
 

Good day Ethin and all,

I'd recommend you taking a look at our audio implementation at Acidanthera: https://github.com/acidanthera/OpenCorePkg/tree/master/Staging/AudioDxe
It was tested on at least a few hundred, possibly a few thousand machines to work adequately. This includes preboot accessibility voice assistance in both text UI and GUI. Please note that there was no thorough review and there may be minor reliability or security defects left.

Best regards,
Marvin

On 29.03.21 22:28, Ethin Probst wrote:
Hello everyone,

This is the first time I've ever contributed to EDK2. As part of GSoC
2021, I have submitted a proposal to implement a UEFI audio output
protocol that will utilize the VirtIO sound driver. I've already
submitted a draft proposal, and apologize if I've done things out of
order. This is my first time doing GSoC 2021, and contributing to EDK2
felt like a really fun thing to do!

I look forward to working with you guys on this and any future projects! :-)


Re: uefi building for fu-540

Andrew Fish
 

You should probably just chmod the directory permissions so you can build from the git repo vs. trying to build with sudo or some such.

For each terminal window there is a onetime setup of sourcing . ./edksetup.sh (not extra dot to source command). That should setup your path. That looks missing in your 2nd failure.


On Apr 4, 2021, at 8:52 AM, Pullannagari Babu <Pullannagari.babu@...> wrote:


Hello Andrew,


Thanks for replying early,

If I build as root permissions, I'm facing the issue attached below.

<Screenshot from 2021-04-04 21-19-34.png>



Thanks
Babu P


From: devel@edk2.groups.io <devel@edk2.groups.io> on behalf of Andrew Fish via groups.io <afish@...>
Sent: Sunday, April 4, 2021 9:10 PM
To: edk2-devel-groups-io <devel@edk2.groups.io>; Pullannagari Babu <Pullannagari.babu@...>
Subject: Re: [edk2-devel] uefi building for fu-540
 
Babu,

The `Build` directory is created by the build for the build output. Looks like your problem is you don’t have privilege to add a directory in `/work/git/tianocore` Did you have to use `sudo` to add the directory? Seem like you need to fix the permissions of the tiancore directory.

Thanks,

Andrew Fish 

On Apr 4, 2021, at 8:21 AM, Pullannagari Babu <Pullannagari.babu@...> wrote:

Hello All,


I'm trying to build UEFI for freedom-u540 board, I cloned these sources : edk2, edk2-non-osi , edk2-platforms. in my build directory 

then I'm facing the below issue 

build.py... : 
error 0005: Could not create directory /work/git/tianocore/Build/FreedomU500VC707/DEBUG_GCC5/RISCV64

then i craeted Build/FreedomU500VC707/DEBUG_GCC5/RISCV64 directory manually.
after i facing below issue please can you help out this.


build -a RISCV64 -p Platform/SiFive/U5SeriesPkg/FreedomU500VC707Board/U500.dsc -t GCC5

<Outlook-ie2qxiud.png>


Thanks
Babu P

[EXT]


Re: uefi building for fu-540

Pullannagari Babu <Pullannagari.babu@...>
 

Hello Andrew,


Thanks for replying early,

If I build as root permissions, I'm facing the issue attached below.




Thanks
Babu P


From: devel@edk2.groups.io <devel@edk2.groups.io> on behalf of Andrew Fish via groups.io <afish@...>
Sent: Sunday, April 4, 2021 9:10 PM
To: edk2-devel-groups-io <devel@edk2.groups.io>; Pullannagari Babu <Pullannagari.babu@...>
Subject: Re: [edk2-devel] uefi building for fu-540
 
Babu,

The `Build` directory is created by the build for the build output. Looks like your problem is you don’t have privilege to add a directory in `/work/git/tianocore` Did you have to use `sudo` to add the directory? Seem like you need to fix the permissions of the tiancore directory.

Thanks,

Andrew Fish 

On Apr 4, 2021, at 8:21 AM, Pullannagari Babu <Pullannagari.babu@...> wrote:

Hello All,


I'm trying to build UEFI for freedom-u540 board, I cloned these sources : edk2, edk2-non-osi , edk2-platforms. in my build directory 

then I'm facing the below issue 

build.py... : 
error 0005: Could not create directory /work/git/tianocore/Build/FreedomU500VC707/DEBUG_GCC5/RISCV64

then i craeted Build/FreedomU500VC707/DEBUG_GCC5/RISCV64 directory manually.
after i facing below issue please can you help out this.


build -a RISCV64 -p Platform/SiFive/U5SeriesPkg/FreedomU500VC707Board/U500.dsc -t GCC5

<Outlook-ie2qxiud.png>


Thanks
Babu P

[EXT]


Re: uefi building for fu-540

Andrew Fish
 

Babu,

The `Build` directory is created by the build for the build output. Looks like your problem is you don’t have privilege to add a directory in `/work/git/tianocore` Did you have to use `sudo` to add the directory? Seem like you need to fix the permissions of the tiancore directory.

Thanks,

Andrew Fish 

On Apr 4, 2021, at 8:21 AM, Pullannagari Babu <Pullannagari.babu@...> wrote:

Hello All,


I'm trying to build UEFI for freedom-u540 board, I cloned these sources : edk2, edk2-non-osi , edk2-platforms. in my build directory 

then I'm facing the below issue 

build.py... : 
error 0005: Could not create directory /work/git/tianocore/Build/FreedomU500VC707/DEBUG_GCC5/RISCV64

then i craeted Build/FreedomU500VC707/DEBUG_GCC5/RISCV64 directory manually.
after i facing below issue please can you help out this.


build -a RISCV64 -p Platform/SiFive/U5SeriesPkg/FreedomU500VC707Board/U500.dsc -t GCC5

<Outlook-ie2qxiud.png>


Thanks
Babu P


uefi building for fu-540

Pullannagari Babu <Pullannagari.babu@...>
 

Hello All,


I'm trying to build UEFI for freedom-u540 board, I cloned these sources : edk2, edk2-non-osi , edk2-platforms. in my build directory

then I'm facing the below issue

build.py... :
error 0005: Could not create directory /work/git/tianocore/Build/FreedomU500VC707/DEBUG_GCC5/RISCV64

then i craeted Build/FreedomU500VC707/DEBUG_GCC5/RISCV64 directory manually.
after i facing below issue please can you help out this.


build -a RISCV64 -p Platform/SiFive/U5SeriesPkg/FreedomU500VC707Board/U500.dsc -t GCC5



Thanks
Babu P


Re: GSoC 2021 (MinPlatform, Ext2, ACPICA, etc)

Andrew Fish
 



On Apr 4, 2021, at 3:50 AM, Pedro Falcato <pedro.falcato@...> wrote:

Hi,

Sounds great! You may be right about that, although I believe I read somewhere that you need to set a milestone for each evaluation? If so, I'm out of ideas as to what can be tangible enough to be a milestone; if not, specifying a read-only driver as project's objective and having write support as a stretch goal is certainly the way to go.


Pedro,

Just an idea but but you could have a milestone to feature complete  of the driver, and have a milestone to develop a test strategy, and test suite to validate the driver. Documentation could also be a milestone. For example I’ve worked on some proprietary EFI File System drivers (HFS+, apfs) and we chose not to implement certain features like compressed files. So you would want to have good documentation about that and tests to make sure the driver gracefully fails in these cases. The test cases don’t only need to be tests as you could create a file system disk image that you could mount in OVMF that contains a lot of file system end case constructs (max size file, links, etc.) to make testing easier. It is not just about leaving a driver behind, but a driver that is easy to maintain and modify over the years. For bonus points that would probably look good on your CV. 

Historical note: EFI did not start with the FAT32 file system as it required a license. EFI started with a made-up file system. The Microsoft file system team rejected this as it turns out testing file systems for all the possible end cases, across the range of produces and consumers is very very complicated. Microsoft ended up contributing FAT32 to EFI so that another new file system would not end up in the world that needed to be validated. So that is probably a good argument to invest in testing this new driver. 

Thanks,

Andrew Fish

Thanks,
Pedro


Re: GSoC 2021 (MinPlatform, Ext2, ACPICA, etc)

Pedro Falcato
 

Hi,

Sounds great! You may be right about that, although I believe I read somewhere that you need to set a milestone for each evaluation? If so, I'm out of ideas as to what can be tangible enough to be a milestone; if not, specifying a read-only driver as project's objective and having write support as a stretch goal is certainly the way to go.

Thanks,
Pedro


[edk2-platforms] [PATCH v2 4/4] MinPlatformPkg: Add LargeVariableWriteLib

Nate DeSimone
 

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.

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 | 1 +
.../Include/Library/LargeVariableWriteLib.h | 58 +++
.../BaseLargeVariableWriteLib.inf | 44 ++
.../LargeVariableWriteLib.c | 479 ++++++++++++++++++
4 files changed, 582 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..d23232ba07
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableWriteLib.h
@@ -0,0 +1,58 @@
+/** @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/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..c52718296c
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableWriteLib/BaseLargeVariableWriteLib.inf
@@ -0,0 +1,44 @@
+## @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.
+#
+# 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


[edk2-platforms] [PATCH v2 3/4] MinPlatformPkg: Add LargeVariableReadLib

Nate DeSimone
 

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 | 50 +++++
.../BaseLargeVariableReadLib.inf | 44 ++++
.../LargeVariableReadLib.c | 199 ++++++++++++++++++
4 files changed, 296 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..adcfff7a34
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Include/Library/LargeVariableReadLib.h
@@ -0,0 +1,50 @@
+/** @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 <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..d522aa84ab
--- /dev/null
+++ b/Platform/Intel/MinPlatformPkg/Library/BaseLargeVariableReadLib/BaseLargeVariableReadLib.inf
@@ -0,0 +1,44 @@
+## @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.
+#
+# 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


[edk2-platforms] [PATCH v2 2/4] MinPlatformPkg: Add VariableWriteLib

Nate DeSimone
 

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>
---
.../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


[edk2-platforms] [PATCH v2 1/4] MinPlatformPkg: Add VariableReadLib

Nate DeSimone
 

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>
---
.../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


[edk2-platforms] [PATCH v2 0/4] Add Large Variable Libraries

Nate DeSimone
 

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 | 50 ++
.../Include/Library/LargeVariableWriteLib.h | 58 +++
.../Include/Library/VariableReadLib.h | 87 ++++
.../Include/Library/VariableWriteLib.h | 129 +++++
.../BaseLargeVariableReadLib.inf | 44 ++
.../LargeVariableReadLib.c | 199 ++++++++
.../BaseLargeVariableWriteLib.inf | 44 ++
.../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, 2428 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


Re: MinPlatform Board port (GSoC 2021)

Benjamin Doron
 

On Wed, Mar 31, 2021 at 07:58 PM, Nate DeSimone wrote:

Hi Benjamin,

 

Great to meet you and welcome to the TianoCore project! Glad you hear you are interested! Doing a board port to the Acer Aspire VN7-572G laptop sounds like a great GSoC project! I presume that since you already did a coreboot port that boot guard is disabled on this laptop and you have figured out how to flash images onto it 😊.

Hi Nate,
Nice to meet you too, and thanks!

Yes, Boot Guard is disabled on this laptop (and fused, which is a slight shame). While SPI PRRs cover most of flash and BIOS control bits are partially enabled by the vendor firmware (perhaps the lock wasn't set by default, defeating the point), after one modification to the setup's (HII) IFR, these can be disabled. Flashing externally is fairly straightforward - after the keyboard comes off the flash chip is visible - but I try to avoid it because I've started having issues with the keyboard connector. It's fine once it's in and closed again...

The only thing that might be a little challenging is getting a 2nd copy of that laptop for your mentor, so the possibility exists that when it comes to debugging problems you might be a little more on your own than you would be otherwise. I’m not too worried about that looking at your CB:35523, it seems like you know what you are doing.

...but this might not be relevant to anyone after all. :-)

Is that how this normally works? Who would organise it? (It sounds needlessly expensive, for someone... *shrug*)

For sure our conventions and infrastructure are different, but there are more parallels between MinPlatform and coreboot than might initially meet the eye. For example:

 

BoardInitBeforeMemoryInit() is roughly equivalent to bootblock_mainboard_init().

BoardInitBeforeSiliconInit() is roughly equivalent to mainboard_init().

SiliconPolicyUpdatePreMem() is roughly equivalent to mainboard_memory_init_params().

 

https://github.com/tianocore/edk2-platforms/blob/master/Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/Library/BoardInitLib/PeiBoardInitPreMemLib.c

https://github.com/tianocore/edk2-platforms/blob/master/Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/Library/BoardInitLib/PeiBoardInitPostMemLib.c

FSP Dispatch Mode Policy Init: https://github.com/tianocore/edk2-platforms/blob/master/Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/Policy/Library/PeiSiliconPolicyUpdateLib/PeiSiliconPolicyUpdateLib.c

FSP API Mode Policy Init: https://github.com/tianocore/edk2-platforms/blob/master/Platform/Intel/KabylakeOpenBoardPkg/KabylakeRvp3/FspWrapper/Library/PeiSiliconPolicyUpdateLibFsp/PeiFspPolicyUpdateLib.c

 

I’d recommend only implementing dispatch mode for new boards. We only had the API mode version because we were busy making a version of Kaby Lake FSP that supports dispatch mode (aka AmberLakeFspBinPkg) at the same time we were developing KabyLakeOpenBoardPkg back in 2019.

 

One difference is we group our board ports based on the SOC they use. So your new board port would go under Platform/Intel/KabylakeOpenBoardPkg/AspireVn7Dash572G for example.

Thanks for these pointers and references, I will look at them more.

As I understand it, the objective of dispatch mode was to remove code duplication in flash and possibly save boot time by minimising phase transitions. But it makes the PeiCore module non-updateable. From a board initialisation perspective, they're probably the same, so this can be figured out later.

I will give you the same caution that I gave Pedro that you will need to be careful about IP cross-contamination. Since coreboot is a GPL project and TianoCore is a BSD+Patent project, we can’t use any of their code. So you need to be careful to NOT read the coreboot Kaby Lake code (with the one exception being your patch to add the VN7-572G, since you are the exclusive author of that work you can choose to re-license it as BSD.) In general, on the days you are doing TianoCore work don’t look at any coreboot code. That way the cycle of sleep and dreams clears your head of influence.

Understood. So, there will be two similar commits of board initialisation? I doubt I can truly dual-license the code, "BSD+GPL" might be a contradiction. However, I'm not a lawyer.

As to your questions:

 

  1. I wrote the prompt to be a bit more general. I’d recommend talking about your specific project to get MinPlatform working on the Acer Aspire VN7-572G. What specific additions or changes are you planning to make to KabylakeOpenBoardPkg to get the VN7-572G working for example? Also, talk a bit about timeline. The GSoC program breaks the summer up into two half’s: June 7 – July 16 and July 16 – August 16. What should your mentor expect to be done on July 16th? What should your mentor to expect to be done on August 16th?
  2. I’m not 100% sure, but my guess is your email address can be whatever you want. But the application form should contain your full legal name for tax purposes. That doesn’t mean we won’t use your preferred nickname when conversing.
On timeline, I think I'll have more to do in the first half. Because I can't solder to the UART pins, I'll need it to boot first. (However, I was very wrong about in this when working on my coreboot port. The OS booted as soon as, if I understand correctly, FSP-T wasn't misconfigured and I set the FSP UPD for display correctly. It took a lot more time to improve the port.)

Sorry, I'll just write something up.

Hope this helps and welcome to the project!

Yes, thanks!

Regarding your second email, yes, that makes sense. I was just nervous about getting it wrong.

Best regards,
Benjamin Doron


Re: [edk2-platforms][PATCH 1/1] Platform/RaspberryPi: Fix mini UART baud divisor calculation

Mario Bălănică
 

Okay, I've tested the patch with the firmware from the commit mentioned above and it doesn't work. The VPU clock divisor bit needs PcdSerialClockRate to be set to 1 GHz (so that the quotient becomes equal to the core clock). 

The mailbox on the other hand always returns 200 MHz for the core clock. This is definitely a bug, which got fixed it in a later commit.

There isn't any reliable way to support the firmwares with a broken mailbox interface as well in this case, and I really doubt anyone would want to use them with the UEFI in the first place. Your build scripts always include the latest version.

I can resend the patch with a more detailed commit message if you wish.


Re: [edk2-platforms][PATCH 1/1] Platform/RaspberryPi: Fix mini UART baud divisor calculation

Pete Batard
 

On 2021.04.03 17:55, Mario Bălănică wrote:
Can you tell me which commit in the firmware repo breaks the mini UART divisor calculation, so that I can test the final changes against it too?
That would be one of the start4.elf/fixup4.dat combination around the time when the commit that added the divisor was introduced. You should be able to find that commit through git blame and then work your way down.

If you need more information than that, I can try to dig it up, but it won't happen until at least Tuesday.

Regards,

/Pete


Re: [edk2-platforms][PATCH 1/1] Platform/RaspberryPi: Fix mini UART baud divisor calculation

Mario Bălănică
 


Re: [edk2-platforms][PATCH 1/1] Platform/RaspberryPi: Fix mini UART baud divisor calculation

Mario Bălănică
 

Can you tell me which commit in the firmware repo breaks the mini UART divisor calculation, so that I can test the final changes against it too?


Re: [edk2-platforms][PATCH 1/1] Platform/RaspberryPi: Fix mini UART baud divisor calculation

Pete Batard
 

On 2021.04.03 17:15, Mario Bălănică wrote:
> -#if (RPI_MODEL == 4)
> -  Divisor = MmioRead32(BCM2836_CM_BASE +
BCM2836_CM_VPU_CLOCK_DIVISOR) & 0xFFFFFF;
> -  if (Divisor != 0)
> -    BaseClockRate = (BaseClockRate << 12) / Divisor;
> -#endif
Keeping this doesn't interfere with the rest of the patch. I've removed it only because it's useless on the latest firmware.
Okay, then can you please send a v2 of your patch that leaves this in? I believe this divisor arithmetic is still needed with older versions of start4.elf, and we may have people using choosing to use an older start4.elf for whatever reason.

In general, if it doesn't interfere with your proposal, it's better to leave existing code in, as overzealous code removal may have unintended consequences, unless you are confident that the code is superfluous.

Also make sure you update the commit message to mention what issue you are fixing.

Thanks,

/Pete


Re: [edk2-platforms][PATCH 1/1] Platform/RaspberryPi: Fix mini UART baud divisor calculation

Mario Bălănică
 

> -#if (RPI_MODEL == 4)
> -  Divisor = MmioRead32(BCM2836_CM_BASE +
BCM2836_CM_VPU_CLOCK_DIVISOR) & 0xFFFFFF;
> -  if (Divisor != 0)
> -    BaseClockRate = (BaseClockRate << 12) / Divisor;
> -#endif
Keeping this doesn't interfere with the rest of the patch. I've removed it only because it's useless on the latest firmware.

10421 - 10440 of 84035