summaryrefslogtreecommitdiff
path: root/Silicon/BroxtonSoC
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/BroxtonSoC')
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/AcpiS3Context.h71
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/ConsoleOutDevice.h25
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/MemoryTypeInformation.h38
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/Capsule.h125
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmAccess.h145
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmControl.h95
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Protocol/SmmVariable.h41
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariable.unibin0 -> 1950 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.unibin0 -> 1358 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c1383
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h152
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf75
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c260
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c93
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c407
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c161
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c4818
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h841
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c436
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c291
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf129
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.unibin0 -> 3158 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.unibin0 -> 1370 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c911
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf114
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.unibin0 -> 4462 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.unibin0 -> 1344 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c1228
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf81
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.unibin0 -> 3028 bytes
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.unibin0 -> 1384 bytes
31 files changed, 11920 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/AcpiS3Context.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/AcpiS3Context.h
new file mode 100644
index 0000000000..26f3133213
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/AcpiS3Context.h
@@ -0,0 +1,71 @@
+/** @file
+ Get Pci Express address library implementation.
+
+ Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ACPI_S3_DATA_H_
+#define _ACPI_S3_DATA_H_
+
+#include <Library/BaseLib.h>
+
+#define SMM_S3_RESUME_SMM_32 SIGNATURE_64 ('S','M','M','S','3','_','3','2')
+#define SMM_S3_RESUME_SMM_64 SIGNATURE_64 ('S','M','M','S','3','_','6','4')
+
+#pragma pack(1)
+
+typedef struct {
+ UINT64 Signature;
+ EFI_PHYSICAL_ADDRESS SmmS3ResumeEntryPoint;
+ EFI_PHYSICAL_ADDRESS SmmS3StackBase;
+ UINT64 SmmS3StackSize;
+ UINT64 SmmS3Cr0;
+ UINT64 SmmS3Cr3;
+ UINT64 SmmS3Cr4;
+ UINT16 ReturnCs;
+ EFI_PHYSICAL_ADDRESS ReturnEntryPoint;
+ EFI_PHYSICAL_ADDRESS ReturnContext1;
+ EFI_PHYSICAL_ADDRESS ReturnContext2;
+ EFI_PHYSICAL_ADDRESS ReturnStackPointer;
+ EFI_PHYSICAL_ADDRESS Smst;
+} SMM_S3_RESUME_STATE;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS AcpiFacsTable;
+ EFI_PHYSICAL_ADDRESS IdtrProfile;
+ EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
+ EFI_PHYSICAL_ADDRESS BootScriptStackBase;
+ UINT64 BootScriptStackSize;
+ EFI_PHYSICAL_ADDRESS S3DebugBufferAddress;
+} ACPI_S3_CONTEXT;
+
+typedef struct {
+ UINT16 ReturnCs;
+ UINT64 ReturnStatus;
+ EFI_PHYSICAL_ADDRESS ReturnEntryPoint;
+ EFI_PHYSICAL_ADDRESS ReturnStackPointer;
+ EFI_PHYSICAL_ADDRESS AsmTransferControl;
+ IA32_DESCRIPTOR Idtr;
+} PEI_S3_RESUME_STATE;
+
+#pragma pack()
+
+#define EFI_ACPI_S3_CONTEXT_GUID \
+ { \
+ 0xef98d3a, 0x3e33, 0x497a, {0xa4, 0x1, 0x77, 0xbe, 0x3e, 0xb7, 0x4f, 0x38} \
+ }
+
+extern EFI_GUID gEfiAcpiS3ContextGuid;
+extern EFI_GUID gEfiAcpiVariableGuid;
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/ConsoleOutDevice.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/ConsoleOutDevice.h
new file mode 100644
index 0000000000..3284418edf
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/ConsoleOutDevice.h
@@ -0,0 +1,25 @@
+/** @file
+ This GUID can be installed to the device handle to specify that the device is the console-out device.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __CONSOLE_OUT_DEVICE_H__
+#define __CONSOLE_OUT_DEVICE_H__
+
+#define EFI_CONSOLE_OUT_DEVICE_GUID \
+ { 0xd3b36f2c, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
+
+extern EFI_GUID gEfiConsoleOutDeviceGuid;
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/MemoryTypeInformation.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/MemoryTypeInformation.h
new file mode 100644
index 0000000000..c441fff6ff
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Guid/MemoryTypeInformation.h
@@ -0,0 +1,38 @@
+/** @file
+ This file defines:
+ * Memory Type Information GUID for HOB and Variable.
+ * Memory Type Information Variable Name.
+ * Memory Type Information GUID HOB data structure.
+
+ The memory type information HOB and variable can
+ be used to store the information for each memory type in Variable or HOB.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __MEMORY_TYPE_INFORMATION_GUID_H__
+#define __MEMORY_TYPE_INFORMATION_GUID_H__
+
+#define EFI_MEMORY_TYPE_INFORMATION_GUID \
+ { 0x4c19049f,0x4137,0x4dd3, { 0x9c,0x10,0x8b,0x97,0xa8,0x3f,0xfd,0xfa } }
+
+#define EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME L"MemoryTypeInformation"
+
+extern EFI_GUID gEfiMemoryTypeInformationGuid;
+
+typedef struct {
+ UINT32 Type; ///< EFI memory type defined in UEFI specification.
+ UINT32 NumberOfPages; ///< The pages of this type memory.
+} EFI_MEMORY_TYPE_INFORMATION;
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/Capsule.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/Capsule.h
new file mode 100644
index 0000000000..b46056970b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/Capsule.h
@@ -0,0 +1,125 @@
+/** @file
+ Defines the APIs that enable PEI services to work with
+ the underlying capsule capabilities of the platform.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_CAPSULE_PPI_H_
+#define _PEI_CAPSULE_PPI_H_
+
+///
+/// Global ID for the PEI_CAPSULE_PPI.
+///
+#define PEI_CAPSULE_PPI_GUID \
+ { \
+ 0x3acf33ee, 0xd892, 0x40f4, {0xa2, 0xfc, 0x38, 0x54, 0xd2, 0xe1, 0x32, 0x3d } \
+ }
+
+///
+/// Forward declaration for the PEI_CAPSULE_PPI.
+///
+typedef struct _PEI_CAPSULE_PPI PEI_CAPSULE_PPI;
+
+/**
+ Upon determining that there is a capsule to operate on, this service
+ will use a series of EFI_CAPSULE_BLOCK_DESCRIPTOR entries to determine
+ the current location of the various capsule fragments and coalesce them
+ into a contiguous region of system memory.
+
+ @param[in] PeiServices Pointer to the PEI Services Table.
+ @param[out] MemoryBase Pointer to the base of a block of memory into which the buffers will be coalesced.
+ On output, this variable will hold the base address
+ of a coalesced capsule.
+ @param[out] MemorySize Size of the memory region pointed to by MemoryBase.
+ On output, this variable will contain the size of the
+ coalesced capsule.
+
+ @retval EFI_NOT_FOUND If: boot modecould not be determined, or the
+ boot mode is not flash-update, or the capsule descriptors were not found.
+ @retval EFI_BUFFER_TOO_SMALL The capsule could not be coalesced in the provided memory region.
+ @retval EFI_SUCCESS There was no capsule, or the capsule was processed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_CAPSULE_COALESCE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN OUT VOID **MemoryBase,
+ IN OUT UINTN *MemSize
+ );
+
+/**
+ Determine if a capsule needs to be processed.
+ The means by which the presence of a capsule is determined is platform
+ specific. For example, an implementation could be driven by the presence
+ of a Capsule EFI Variable containing a list of EFI_CAPSULE_BLOCK_DESCRIPTOR
+ entries. If present, return EFI_SUCCESS, otherwise return EFI_NOT_FOUND.
+
+ @param[in] PeiServices Pointer to the PEI Services Table.
+
+ @retval EFI_SUCCESS If a capsule is available.
+ @retval EFI_NOT_FOUND No capsule detected.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_CAPSULE_CHECK_CAPSULE_UPDATE)(
+ IN EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ The Capsule PPI service that gets called after memory is available. The
+ capsule coalesce function, which must be called first, returns a base
+ address and size. Once the memory init PEIM has discovered memory,
+ it should call this function and pass in the base address and size
+ returned by the Coalesce() function. Then this function can create a
+ capsule HOB and return.
+
+ @par Notes:
+ This function assumes it will not be called until the
+ actual capsule update.
+
+ @param[in] PeiServices Pointer to the PEI Services Table.
+ @param[in] CapsuleBase Address returned by the capsule coalesce function.
+ @param[in] CapsuleSize Value returned by the capsule coalesce function.
+
+ @retval EFI_VOLUME_CORRUPTED CapsuleBase does not appear to point to a
+ coalesced capsule.
+ @retval EFI_SUCCESS Capsule HOB was created successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_CAPSULE_CREATE_STATE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN VOID *CapsuleBase,
+ IN UINTN CapsuleSize
+ );
+
+///
+/// This PPI provides several services in PEI to work with the underlying
+/// capsule capabilities of the platform. These services include the ability
+/// for PEI to coalesce a capsule from a scattered set of memory locations
+/// into a contiguous space in memory, detect if a capsule is present for
+/// processing, and once memory is available, create a HOB for the capsule.
+///
+struct _PEI_CAPSULE_PPI {
+ PEI_CAPSULE_COALESCE Coalesce;
+ PEI_CAPSULE_CHECK_CAPSULE_UPDATE CheckCapsuleUpdate;
+ PEI_CAPSULE_CREATE_STATE CreateState;
+};
+
+extern EFI_GUID gPeiCapsulePpiGuid;
+
+#endif // #ifndef _PEI_CAPSULE_PPI_H_
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmAccess.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmAccess.h
new file mode 100644
index 0000000000..2a4af449f2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmAccess.h
@@ -0,0 +1,145 @@
+/** @file
+ EFI SMM Access PPI definition.
+
+ This PPI is used to control the visibility of the SMRAM on the platform.
+ It abstracts the location and characteristics of SMRAM. The expectation is
+ that the north bridge or memory controller would publish this PPI.
+
+ The principal functionality found in the memory controller includes the following:
+ - Exposing the SMRAM to all non-SMM agents, or the "open" state
+ - Shrouding the SMRAM to all but the SMM agents, or the "closed" state
+ - Preserving the system integrity, or "locking" the SMRAM, such that the settings cannot be
+ perturbed by either boot service or runtime agents
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SMM_ACCESS_PPI_H_
+#define _SMM_ACCESS_PPI_H_
+
+#define PEI_SMM_ACCESS_PPI_GUID \
+ { 0x268f33a9, 0xcccd, 0x48be, { 0x88, 0x17, 0x86, 0x5, 0x3a, 0xc3, 0x2e, 0xd6 }}
+
+typedef struct _PEI_SMM_ACCESS_PPI PEI_SMM_ACCESS_PPI;
+
+/**
+ Opens the SMRAM area to be accessible by a PEIM driver.
+
+ This function "opens" SMRAM so that it is visible while not inside of SMM. The function should
+ return EFI_UNSUPPORTED if the hardware does not support hiding of SMRAM. The function
+ should return EFI_DEVICE_ERROR if the SMRAM configuration is locked.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This The pointer to the SMM Access Interface.
+ @param[in] DescriptorIndex The region of SMRAM to Open.
+
+ @retval EFI_SUCCESS The region was successfully opened.
+ @retval EFI_DEVICE_ERROR The region could not be opened because locked by chipset.
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_OPEN)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ );
+
+/**
+ Inhibits access to the SMRAM.
+
+ This function "closes" SMRAM so that it is not visible while outside of SMM. The function should
+ return EFI_UNSUPPORTED if the hardware does not support hiding of SMRAM.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This The pointer to the SMM Access Interface.
+ @param[in] DescriptorIndex The region of SMRAM to Close.
+
+ @retval EFI_SUCCESS The region was successfully closed.
+ @retval EFI_DEVICE_ERROR The region could not be closed because locked by chipset.
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_CLOSE)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ );
+
+/**
+ Inhibits access to the SMRAM.
+
+ This function prohibits access to the SMRAM region. This function is usually implemented such
+ that it is a write-once operation.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This The pointer to the SMM Access Interface.
+ @param[in] DescriptorIndex The region of SMRAM to Close.
+
+ @retval EFI_SUCCESS The region was successfully locked.
+ @retval EFI_DEVICE_ERROR The region could not be locked because at least
+ one range is still open.
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_LOCK)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ );
+
+/**
+ Queries the memory controller for the possible regions that will support SMRAM.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This The pointer to the SmmAccessPpi Interface.
+ @param[in, out] SmramMapSize The pointer to the variable containing size of the
+ buffer to contain the description information.
+ @param[in, out] SmramMap The buffer containing the data describing the Smram
+ region descriptors.
+
+ @retval EFI_BUFFER_TOO_SMALL The user did not provide a sufficient buffer.
+ @retval EFI_SUCCESS The user provided a sufficiently-sized buffer.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_CAPABILITIES)(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN OUT UINTN *SmramMapSize,
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
+ );
+
+///
+/// EFI SMM Access PPI is used to control the visibility of the SMRAM on the platform.
+/// It abstracts the location and characteristics of SMRAM. The expectation is
+/// that the north bridge or memory controller would publish this PPI.
+///
+struct _PEI_SMM_ACCESS_PPI {
+ PEI_SMM_OPEN Open;
+ PEI_SMM_CLOSE Close;
+ PEI_SMM_LOCK Lock;
+ PEI_SMM_CAPABILITIES GetCapabilities;
+ BOOLEAN LockState;
+ BOOLEAN OpenState;
+};
+
+extern EFI_GUID gPeiSmmAccessPpiGuid;
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmControl.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmControl.h
new file mode 100644
index 0000000000..e7b67c5a6f
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Ppi/SmmControl.h
@@ -0,0 +1,95 @@
+/** @file
+ EFI SMM Control PPI definition.
+
+ This PPI is used to initiate SMI/PMI activations. This protocol could be published by either:
+ - A processor driver to abstract the SMI/PMI IPI
+ - The driver that abstracts the ASIC that is supporting the APM port, such as the ICH in an
+ Intel chipset
+ Because of the possibility of performing SMI or PMI IPI transactions, the ability to generate this
+ event from a platform chipset agent is an optional capability for both IA-32 and Itanium-based
+ systems.
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SMM_CONTROL_PPI_H_
+#define _SMM_CONTROL_PPI_H_
+
+#define PEI_SMM_CONTROL_PPI_GUID \
+ { 0x61c68702, 0x4d7e, 0x4f43, 0x8d, 0xef, 0xa7, 0x43, 0x5, 0xce, 0x74, 0xc5 }
+
+typedef struct _PEI_SMM_CONTROL_PPI PEI_SMM_CONTROL_PPI;
+
+/**
+ Invokes SMI activation from either the preboot or runtime environment.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This The PEI_SMM_CONTROL_PPI instance.
+ @param[in] ArgumentBuffer The optional sized data to pass into the protocol activation.
+ @param[in] ArgumentBufferSize The optional size of the data.
+ @param[in] Periodic An optional mechanism to periodically repeat activation.
+ @param[in] ActivationInterval An optional parameter to repeat at this period one
+ time or, if the Periodic Boolean is set, periodically.
+
+ @retval EFI_SUCCESS The SMI/PMI has been engendered.
+ @retval EFI_DEVICE_ERROR The timing is unsupported.
+ @retval EFI_INVALID_PARAMETER The activation period is unsupported.
+ @retval EFI_NOT_STARTED The SMM base service has not been initialized.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_ACTIVATE) (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI * This,
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN UINTN ActivationInterval OPTIONAL
+ );
+
+/**
+ Clears any system state that was created in response to the Active call.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This The PEI_SMM_CONTROL_PPI instance.
+ @param[in] Periodic Optional parameter to repeat at this period one
+ time or, if the Periodic Boolean is set, periodically.
+
+ @retval EFI_SUCCESS The SMI/PMI has been engendered.
+ @retval EFI_DEVICE_ERROR The source could not be cleared.
+ @retval EFI_INVALID_PARAMETER The service did not support the Periodic input argument.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PEI_SMM_DEACTIVATE) (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI * This,
+ IN BOOLEAN Periodic OPTIONAL
+ );
+
+///
+/// PEI SMM Control PPI is used to initiate SMI/PMI activations. This protocol could be published by either:
+/// - A processor driver to abstract the SMI/PMI IPI
+/// - The driver that abstracts the ASIC that is supporting the APM port, such as the ICH in an
+/// Intel chipset
+///
+struct _PEI_SMM_CONTROL_PPI {
+ PEI_SMM_ACTIVATE Trigger;
+ PEI_SMM_DEACTIVATE Clear;
+};
+
+extern EFI_GUID gPeiSmmControlPpiGuid;
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Protocol/SmmVariable.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Protocol/SmmVariable.h
new file mode 100644
index 0000000000..f46073c561
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Include/Protocol/SmmVariable.h
@@ -0,0 +1,41 @@
+/** @file
+ EFI SMM Variable Protocol is related to EDK II-specific implementation of variables
+ and intended for use as a means to store data in the EFI SMM environment.
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SMM_VARIABLE_H__
+#define __SMM_VARIABLE_H__
+
+#define EFI_SMM_VARIABLE_PROTOCOL_GUID \
+ { \
+ 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 } \
+ }
+
+typedef struct _EFI_SMM_VARIABLE_PROTOCOL EFI_SMM_VARIABLE_PROTOCOL;
+
+///
+/// EFI SMM Variable Protocol is intended for use as a means
+/// to store data in the EFI SMM environment.
+///
+struct _EFI_SMM_VARIABLE_PROTOCOL {
+ EFI_GET_VARIABLE SmmGetVariable;
+ EFI_GET_NEXT_VARIABLE_NAME SmmGetNextVariableName;
+ EFI_SET_VARIABLE SmmSetVariable;
+ EFI_QUERY_VARIABLE_INFO SmmQueryVariableInfo;
+};
+
+extern EFI_GUID gEfiSmmVariableProtocolGuid;
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni
new file mode 100644
index 0000000000..91194881dd
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariable.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni
new file mode 100644
index 0000000000..b52ff23520
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/PeiVariableExtra.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c
new file mode 100644
index 0000000000..f6c4227069
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -0,0 +1,1383 @@
+/** @file
+ Implement ReadOnly Variable Services required by PEIM and install
+ PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+
+//
+// Module globals
+//
+EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
+ PeiGetVariable,
+ PeiGetNextVariableName
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ &mVariablePpi
+};
+
+
+/**
+ Provide the functionality of the variable services.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param[in] PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN Instance;
+ READ_ONLY_VARIABLE_PRE_MEMORY_DESCRIPTOR_PPI *PreMemoryDescriptorPpi;
+ EFI_PEI_PPI_DESCRIPTOR *PreMemoryDescriptorPpiDesc;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *OldReadOnlyVariable2Ppi;
+ EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
+ BOOLEAN InPermanentMemory;
+
+ InPermanentMemory = FALSE;
+ Status = PeiServicesRegisterForShadow (FileHandle);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ALREADY_STARTED) {
+ InPermanentMemory = TRUE;
+ } else {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ //
+ // The PI spec does not require that there only be one instance of
+ // EFI_PEI_READ_ONLY_VARIABLE2_PPI. Therefore one must assume that a
+ // scenario exists where there is a platform specific instance of
+ // EFI_PEI_READ_ONLY_VARIABLE2_PPI. Therefore, this driver must keep track
+ // of which instance of EFI_PEI_READ_ONLY_VARIABLE2_PPI it installs so that
+ // the correct instance is reinstalled after PEI is shadowed to permanent
+ // memory.
+ //
+ if (!InPermanentMemory) {
+ //
+ // If system is still in Pre-Memory, store the temporary address to the
+ // PPI descriptor in a separate unique PPI. Then when permanent memory is
+ // installed, the old PPI instance can be located and reinstalled with the
+ // new address
+ //
+ PreMemoryDescriptorPpi = (READ_ONLY_VARIABLE_PRE_MEMORY_DESCRIPTOR_PPI *)
+ AllocateZeroPool (
+ sizeof (
+ READ_ONLY_VARIABLE_PRE_MEMORY_DESCRIPTOR_PPI
+ )
+ );
+ PreMemoryDescriptorPpiDesc = (EFI_PEI_PPI_DESCRIPTOR *)
+ AllocateZeroPool (
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ if (PreMemoryDescriptorPpiDesc == NULL || PreMemoryDescriptorPpi == NULL) {
+ ASSERT (PreMemoryDescriptorPpiDesc != NULL);
+ ASSERT (PreMemoryDescriptorPpi != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ PreMemoryDescriptorPpi->PreMemoryDescriptor = &mPpiListVariable;
+ PreMemoryDescriptorPpiDesc->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI |
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+ PreMemoryDescriptorPpiDesc->Guid = &gReadOnlyVariablePreMemoryDescriptorPpiGuid;
+ PreMemoryDescriptorPpiDesc->Ppi = PreMemoryDescriptorPpi;
+ Status = PeiServicesInstallPpi (PreMemoryDescriptorPpiDesc);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ //
+ // Now that the descriptor address is saved,
+ // install EFI_PEI_READ_ONLY_VARIABLE2_PPI
+ //
+ Status = PeiServicesInstallPpi (&mPpiListVariable);
+ } else {
+ Status = PeiServicesLocatePpi (
+ &gReadOnlyVariablePreMemoryDescriptorPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PreMemoryDescriptorPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The previous descriptor pointer has been found, locate the old PPI
+ // and reinstall it.
+ //
+ for (Instance = 0; Status != EFI_NOT_FOUND; Instance++) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ Instance,
+ &OldDescriptor,
+ (VOID **) &OldReadOnlyVariable2Ppi
+ );
+ if (!EFI_ERROR (Status)) {
+ if (OldDescriptor == PreMemoryDescriptorPpi->PreMemoryDescriptor) {
+ Status = PeiServicesReInstallPpi (OldDescriptor, &mPpiListVariable);
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ } else if (Status != EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+ //
+ // This implementation of EFI_PEI_READ_ONLY_VARIABLE2_PPI
+ // was never installed. Install it for the first time
+ //
+ Status = PeiServicesInstallPpi (&mPpiListVariable);
+ } else {
+ //
+ // This implementation of EFI_PEI_READ_ONLY_VARIABLE2_PPI
+ // was never installed. Install it for the first time
+ //
+ Status = PeiServicesInstallPpi (&mPpiListVariable);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+
+/**
+ This code gets the pointer to the last variable memory pointer byte.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return VARIABLE_HEADER* pointer to last unavailable Variable Header.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ This code gets the size of variable header.
+
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ if (AuthFlag) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+
+/**
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->NameSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+ }
+}
+
+
+/**
+ This code gets the size of data of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return Size of variable in bytes in type UINTN.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->DataSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+ }
+}
+
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A CHAR16* pointer to Variable Name.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize (AuthFlag));
+}
+
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN BOOLEAN AuthFlag
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (AuthFlag) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] AuthFlag Authenticated variable flag.
+
+ @return A UINT8* pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN BOOLEAN AuthFlag
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable, AuthFlag);
+ Value += NameSizeOfVariable (VariableHeader, AuthFlag);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));
+
+ return (UINT8 *) Value;
+}
+
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+
+ @return A VARIABLE_HEADER* pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
+ )
+{
+ UINTN Value;
+
+ Value = (UINTN) GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);
+ Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = HEADER_ALIGN (Value);
+
+ return (VARIABLE_HEADER *) Value;
+}
+
+
+/**
+ Get variable store status.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store is raw
+ @retval EfiValid Variable store is valid
+ @retval EfiInvalid Variable store is invalid
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gPeiVariableCacheHobGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
+ VarStoreHeader->State == VARIABLE_STORE_HEALTHY
+ ) {
+
+ return EfiValid;
+ }
+
+ if (((UINT32 *) (&VarStoreHeader->Signature))[0] == 0xffffffff &&
+ ((UINT32 *) (&VarStoreHeader->Signature))[1] == 0xffffffff &&
+ ((UINT32 *) (&VarStoreHeader->Signature))[2] == 0xffffffff &&
+ ((UINT32 *) (&VarStoreHeader->Signature))[3] == 0xffffffff &&
+ VarStoreHeader->Size == 0xffffffff &&
+ VarStoreHeader->Format == 0xff &&
+ VarStoreHeader->State == 0xff
+ ) {
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+
+/**
+ Compare two variable names, one of them may be inconsecutive.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Name1 Pointer to one variable name.
+ @param[in] Name2 Pointer to another variable name.
+ @param[in] NameSize Variable name size.
+
+ @retval TRUE Name1 and Name2 are identical.
+ @retval FALSE Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *Name1,
+ IN CONST CHAR16 *Name2,
+ IN UINTN NameSize
+ )
+{
+
+ //
+ // Both Name1 and Name2 are consecutive.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ This function compares a variable with variable entries in database.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the variable in our database
+ @param[in] VariableHeader Pointer to the Variable Header that has consecutive content.
+ @param[in] VariableName Name of the variable to compare to 'Variable'
+ @param[in] VendorGuid GUID of the variable to compare to 'Variable'
+ @param[out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Found match variable
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VOID *Point;
+ EFI_GUID *TempVendorGuid;
+
+ TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);
+
+ if (VariableName[0] == 0) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Don't use CompareGuid function here for performance reasons.
+ // Instead we compare the GUID a UINT32 at a time and branch
+ // on the first failed comparison.
+ //
+ if ((((INT32 *) VendorGuid)[0] == ((INT32 *) TempVendorGuid)[0]) &&
+ (((INT32 *) VendorGuid)[1] == ((INT32 *) TempVendorGuid)[1]) &&
+ (((INT32 *) VendorGuid)[2] == ((INT32 *) TempVendorGuid)[2]) &&
+ (((INT32 *) VendorGuid)[3] == ((INT32 *) TempVendorGuid)[3])
+ ) {
+ ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);
+ Point = (VOID *) GetVariableNamePtr (Variable, StoreInfo->AuthFlag);
+ if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {
+ PtrTrack->CurrPtr = Variable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Return the variable HOB header and the store info for the given HOB type
+
+ @param[in] Type The type of the variable HOB.
+ @param[out] StoreInfo Return the store info.
+
+ @return Pointer to the variable HOB header.
+
+**/
+VARIABLE_STORE_HEADER *
+GetHobVariableStore (
+ IN VARIABLE_HOB_TYPE Type,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ StoreInfo->IndexTable = NULL;
+ StoreInfo->AuthFlag = FALSE;
+
+ switch (Type) {
+ case VariableHobTypeCache:
+ GuidHob = GetFirstGuidHob (&gPeiVariableCacheHobGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->AuthFlag = FALSE;
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ return StoreInfo->VariableStoreHeader;
+ }
+ break;
+ case VariableHobTypeDefault:
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->AuthFlag = TRUE;
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ return StoreInfo->VariableStoreHeader;
+ }
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->AuthFlag = FALSE;
+ StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ return StoreInfo->VariableStoreHeader;
+ }
+ break;
+ }
+ return NULL;
+}
+
+
+/**
+ Get variable header that has consecutive content.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] Variable Pointer to the Variable Header.
+ @param[out] VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ )
+{
+
+ if (Variable == NULL) {
+ return FALSE;
+ }
+
+ //
+ // First assume variable header pointed by Variable is consecutive.
+ //
+ *VariableHeader = Variable;
+
+ if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
+ //
+ // Reach the end of variable store.
+ //
+ return FALSE;
+ }
+
+ return IsValidVariableHeader (*VariableHeader);
+}
+
+
+/**
+ Get variable name or data to output buffer.
+
+ @param[in] StoreInfo Pointer to variable store info structure.
+ @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param[in] Size Variable name/data size.
+ @param[out] Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ )
+{
+
+ //
+ // Variable name/data is consecutive.
+ //
+ CopyMem (Buffer, NameOrData, Size);
+}
+
+
+/**
+ Find the variable in the specified variable store.
+
+ @param[in] StoreInfo Pointer to the store info structure.
+ @param[in] VariableName Name of the variable to be found
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableInHobsInternal (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *InDeletedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_HEADER *VariableHeader;
+
+ VariableStoreHeader = StoreInfo->VariableStoreHeader;
+
+ if (VariableStoreHeader == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (~VariableStoreHeader->Size == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);
+
+ InDeletedVariable = NULL;
+
+ //
+ // No Variable Address equals zero, so 0 as initial value is safe.
+ //
+ VariableHeader = NULL;
+
+ //
+ // Start at the beginning of the HOB
+ //
+ Variable = PtrTrack->StartPtr;
+
+ //
+ // Find the variable by walking through the variable store
+ //
+ while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
+ }
+ PtrTrack->CurrPtr = InDeletedVariable;
+
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+
+/**
+ Find the variable in HOB variable storages.
+
+ @param[in] VariableName Name of the variable to be found
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param[out] StoreInfo Return the store info.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+ @retval EFI_INVALID_PARAMETER Invalid variable name
+
+**/
+EFI_STATUS
+FindVariableInHobs (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ OUT VARIABLE_STORE_INFO *StoreInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_HOB_TYPE Type;
+
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Type = (VARIABLE_HOB_TYPE) 0; Type < VariableHobTypeMax; Type++) {
+ if (GetHobVariableStore (Type, StoreInfo) != NULL) {
+ Status = FindVariableInHobsInternal (
+ StoreInfo,
+ VariableName,
+ VendorGuid,
+ PtrTrack
+ );
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Retrieves a variable value from HOB resources.
+
+ Read the specified variable from the UEFI variable store in the HOB. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param[in] VariableName A pointer to a null-terminated string that is the variable's name.
+ @param[in] VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param[out] Attributes If non-NULL, on return, points to the variable's attributes.
+ @param[in, out] DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param[out] Data Points to the buffer which will hold the returned variable value.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetHobVariable (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN HobVariableDataSize;
+ VARIABLE_HEADER *HobVariableHeader;
+ VARIABLE_HOB_TYPE Type;
+ VARIABLE_POINTER_TRACK HobVariable;
+ VARIABLE_STORE_INFO HobStoreInfo;
+
+ //
+ // Check the HOB variable stores if they exist
+ //
+ for (Type = (VARIABLE_HOB_TYPE) 0; Type < VariableHobTypeMax; Type++) {
+ if (GetHobVariableStore (Type, &HobStoreInfo) != NULL) {
+ DEBUG ((EFI_D_INFO, "Temp Debug: Found a HOB variable store in PeiGetVariable()\n"));
+ Status = FindVariableInHobsInternal (
+ &HobStoreInfo,
+ VariableName,
+ VariableGuid,
+ &HobVariable
+ );
+ if (HobVariable.CurrPtr == NULL || EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Check the next HOB
+ //
+ continue;
+ }
+ DEBUG ((EFI_D_ERROR, "Temp Debug: HobVariable found was null or had an error\n"));
+ return Status;
+ }
+
+ GetVariableHeader (&HobStoreInfo, HobVariable.CurrPtr, &HobVariableHeader);
+
+ //
+ // Get data size
+ //
+ HobVariableDataSize = DataSizeOfVariable (HobVariableHeader, HobStoreInfo.AuthFlag);
+ if (*DataSize >= HobVariableDataSize) {
+ DEBUG ((EFI_D_INFO, "Temp Debug: Data buffer passed for variable data is large enough\n"));
+ if (Data == NULL) {
+ DEBUG ((EFI_D_ERROR, "Temp Debug: Data in the variable is NULL (invalid)\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetVariableNameOrData (&HobStoreInfo, GetVariableDataPtr (HobVariable.CurrPtr, HobVariableHeader, HobStoreInfo.AuthFlag), HobVariableDataSize, Data);
+
+ if (Attributes != NULL) {
+ *Attributes = HobVariableHeader->Attributes;
+ }
+
+ *DataSize = HobVariableDataSize;
+
+ DEBUG ((EFI_D_INFO, "Temp Debug: Variable was found in the HOB. No need to check storage PPIs. Returning success.\n\n"));
+
+ //
+ // Variable was found in the HOB
+ //
+ return EFI_SUCCESS;
+ } else {
+ DEBUG ((EFI_D_ERROR, "Temp Debug: Data buffer provided for variable data is too small!\n"));
+ *DataSize = HobVariableDataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param[in] This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param[in] VariableName A pointer to a null-terminated string that is the variable's name.
+ @param[in] VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param[out] Attributes If non-NULL, on return, points to the variable's attributes.
+ @param[in, out] DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param[out] Data Points to the buffer which will hold the returned variable value.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ EFI_GUID DiscoveredInstanceGuid;
+ EFI_GUID VariableStorageInstanceId;
+ EFI_PEI_PPI_DESCRIPTOR *VariableStoragePpiDescriptor;
+ EFI_STATUS Status;
+ UINTN Instance;
+ VARIABLE_STORAGE_PPI *VariableStoragePpi;
+
+ if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {
+ DEBUG ((EFI_D_ERROR, "Temp Debug: Invalid parameter passed to PeiGetVariable()\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if the variable can be found in a HOB store
+ //
+ Status = GetHobVariable (VariableName, VariableGuid, Attributes, DataSize, Data);
+
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((EFI_D_INFO, "Temp Debug: Could not find the variable in the HOBs. Checking storage PPIs...\n"));
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Temp Debug: Error occurred checking the HOBs for the variable.\n"));
+ } else {
+ return Status;
+ }
+
+ //
+ // Determine which PPI instance should be used for this variable
+ //
+ Status = GetVariableStorageId (VariableName, VariableGuid, FALSE, &VariableStorageInstanceId);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Temp Debug: Could not find the Variable Storage PPI ID for this variable!\n"));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ for (Instance = 0; Status != EFI_NOT_FOUND; Instance++) {
+ Status = PeiServicesLocatePpi (
+ &gVariableStoragePpiGuid,
+ Instance,
+ &VariableStoragePpiDescriptor,
+ (VOID **) &VariableStoragePpi
+ );
+
+ if (!EFI_ERROR (Status) && !EFI_ERROR (VariableStoragePpi->GetId (&DiscoveredInstanceGuid))) {
+ DEBUG ((EFI_D_INFO, "Correct VariableStorageId GUID = %g\nDiscoveredGuid = %g\n", &VariableStorageInstanceId, &DiscoveredInstanceGuid));
+
+ if (CompareGuid (&VariableStorageInstanceId, &DiscoveredInstanceGuid)) {
+ //
+ // Found the appropriate Variable Storage PPI. Now use it to get the variable.
+ //
+ DEBUG ((EFI_D_INFO, "Temp Debug: Found the appropriate Variable Storage PPI. Calling VariableStoragePpi->GetVariable()...\n"));
+
+ return VariableStoragePpi->GetVariable (VariableStoragePpi, VariableName, VariableGuid, Attributes, DataSize, Data);
+ }
+ } else if (Status != EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Return the next variable name and GUID in the HOB data store.
+
+ @param[in] VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param[in] VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param[in] VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetHobNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ VARIABLE_HOB_TYPE Type;
+ VARIABLE_POINTER_TRACK Variable;
+ VARIABLE_POINTER_TRACK VariableInDefaultHob;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ UINTN VarNameSize;
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableHobTypeMax];
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_INFO StoreInfoForDefault;
+ VARIABLE_STORE_INFO StoreInfoForCache;
+
+ if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableHeader = NULL;
+
+ Status = FindVariableInHobs (VariableName, VariableGuid, &Variable, &StoreInfo);
+ if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not NULL, get next variable
+ //
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+
+ VariableStoreHeader[VariableHobTypeDefault] = GetHobVariableStore (VariableHobTypeDefault, &StoreInfoForDefault);
+ VariableStoreHeader[VariableHobTypeCache] = GetHobVariableStore (VariableHobTypeCache, &StoreInfoForCache);
+
+ while (TRUE) {
+ //
+ // Switch from HOB to Non-Volatile.
+ //
+ while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
+ //
+ // Find current storage index
+ //
+ for (Type = (VARIABLE_HOB_TYPE) 0; Type < VariableHobTypeMax; Type++) {
+ if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+ break;
+ }
+ }
+ ASSERT (Type < VariableHobTypeMax);
+ //
+ // Switch to next storage
+ //
+ for (Type++; Type < VariableHobTypeMax; Type++) {
+ if (VariableStoreHeader[Type] != NULL) {
+ break;
+ }
+ }
+ //
+ // Capture the case that
+ // 1. current storage is the last one, or
+ // 2. no further storage
+ //
+ if (Type == VariableHobTypeMax) {
+ return EFI_NOT_FOUND;
+ }
+ Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ Variable.CurrPtr = Variable.StartPtr;
+ GetHobVariableStore (Type, &StoreInfo);
+ }
+
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is also a same ADDED one at the same time,
+ // don't return it.
+ //
+ Status = FindVariableInHobsInternal (
+ &StoreInfo,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ //
+ // Don't return cache HOB variable when default HOB overrides it
+ //
+ if ((VariableStoreHeader[VariableHobTypeDefault] != NULL) && (VariableStoreHeader[VariableHobTypeCache] != NULL) &&
+ (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableHobTypeCache]))
+ ) {
+ Status = FindVariableInHobsInternal (
+ &StoreInfoForDefault,
+ GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
+ GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
+ &VariableInDefaultHob
+ );
+ if (!EFI_ERROR (Status)) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ continue;
+ }
+ }
+
+ VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
+ ASSERT (VarNameSize != 0);
+
+ if (VarNameSize <= *VariableNameSize) {
+ GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *) VariableName);
+
+ CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
+
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ //
+ // Variable is found
+ //
+ return Status;
+ } else {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
+ }
+ }
+}
+
+
+/**
+ Determines if a variable exists in the variable store HOBs
+
+ @param[in] VariableName A pointer to a null-terminated string that is the variable's name.
+ @param[in] VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+
+ @retval TRUE The variable exists in the HOBs
+ @retval FALSE The variable does not exist in the HOBs
+
+**/
+BOOLEAN
+EFIAPI
+VariableExistsInHob (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK HobVariable;
+ VARIABLE_STORE_INFO HobStoreInfo;
+
+ Status = FindVariableInHobs (VariableName, VariableGuid, &HobVariable, &HobStoreInfo);
+ if ((HobVariable.CurrPtr != NULL) && (!EFI_ERROR (Status))) {
+ return TRUE;
+ } else {
+ if (Status == EFI_NOT_FOUND) {
+ return FALSE;
+ }
+ ASSERT_EFI_ERROR (Status);
+ return FALSE;
+ }
+}
+
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param[in] VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ On return, the size of the variable name buffer.
+ @param[in] VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+ @param[in] VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ EFI_GUID DiscoveredInstanceGuid;
+ EFI_GUID VariableStorageInstanceId;
+ EFI_PEI_PPI_DESCRIPTOR *VariableStoragePpiDescriptor;
+ EFI_STATUS Status;
+ VARIABLE_STORAGE_PPI *VariableStoragePpi;
+ BOOLEAN SearchComplete;
+ UINTN Instance;
+ UINT32 VarAttributes;
+
+ if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the HOBs first
+ //
+ Status = PeiGetHobNextVariableName (VariableNameSize, VariableName, VariableGuid);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ } else if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ //
+ // If VariableName is an empty string or we reached the end of the HOBs,
+ // get the first variable from the first Variable Storage PPI
+ //
+ if (VariableName[0] == 0 || (Status == EFI_NOT_FOUND && VariableExistsInHob (VariableName, VariableGuid))) {
+ ZeroMem ((VOID *) VariableName, *VariableNameSize);
+ ZeroMem ((VOID *) VariableGuid, sizeof (VariableGuid));
+ Status = PeiServicesLocatePpi (
+ &gVariableStoragePpiGuid,
+ 0,
+ &VariableStoragePpiDescriptor,
+ (VOID **) &VariableStoragePpi
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = VariableStoragePpi->GetNextVariableName (
+ VariableStoragePpi,
+ VariableNameSize,
+ VariableName,
+ VariableGuid,
+ &VarAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "VariableStoragePpi->GetNextVariableName status %r\n", Status));
+ }
+ }
+ return Status;
+ }
+
+ //
+ // All of the HOB variables have been already enumerated, enumerate the Variable Storage PPIs
+ //
+ SearchComplete = FALSE;
+ while (!SearchComplete) {
+ Status = GetVariableStorageId (VariableName, VariableGuid, FALSE, &VariableStorageInstanceId);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ for (Instance = 0; Status != EFI_NOT_FOUND; Instance++) {
+ Status = PeiServicesLocatePpi (
+ &gVariableStoragePpiGuid,
+ Instance,
+ &VariableStoragePpiDescriptor,
+ (VOID **) &VariableStoragePpi
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = VariableStoragePpi->GetId (&DiscoveredInstanceGuid);
+ if (!EFI_ERROR (Status)) {
+ if (CompareGuid (&VariableStorageInstanceId, &DiscoveredInstanceGuid)) {
+ Status = VariableStoragePpi->GetNextVariableName (
+ VariableStoragePpi,
+ VariableNameSize,
+ VariableName,
+ VariableGuid,
+ &VarAttributes
+ );
+ if (!EFI_ERROR (Status)) {
+ if (VariableExistsInHob (VariableName, VariableGuid)) {
+ //
+ // Don't return this variable if there is a HOB variable that overrides it
+ // advance to the next variable
+ //
+ break;
+ }
+ return Status;
+ } else if (Status == EFI_NOT_FOUND) {
+ //
+ // If we reached the end of the variables in the current variable
+ // storage PPI, get the first variable in the next variable storage PPI
+ //
+ ZeroMem ((VOID *) VariableName, *VariableNameSize);
+ ZeroMem ((VOID *) VariableGuid, sizeof (VariableGuid));
+ Status = PeiServicesLocatePpi (
+ &gVariableStoragePpiGuid,
+ Instance + 1,
+ &VariableStoragePpiDescriptor,
+ (VOID **) &VariableStoragePpi
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = VariableStoragePpi->GetNextVariableName (
+ VariableStoragePpi,
+ VariableNameSize,
+ VariableName,
+ VariableGuid,
+ &VarAttributes
+ );
+ if (!EFI_ERROR (Status)) {
+ if (VariableExistsInHob (VariableName, VariableGuid)) {
+ //
+ // Don't return this variable if there is a HOB variable that overrides it
+ // advance to the next variable
+ //
+ break;
+ }
+ }
+ return Status;
+ } else if (Status == EFI_NOT_FOUND) {
+ // This is the last variable
+ SearchComplete = TRUE;
+ break;
+ } else {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ } else {
+ return Status;
+ }
+ }
+ } else {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ } else if (Status == EFI_NOT_FOUND) {
+ SearchComplete = TRUE;
+ } else {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h
new file mode 100644
index 0000000000..916664e67f
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/Variable.h
@@ -0,0 +1,152 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by PeiVariable module.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_VARIABLE_H_
+#define _PEI_VARIABLE_H_
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/ReadOnlyVariablePreMemoryDescriptorPpi.h>
+#include <Ppi/VariableStoragePpi.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/VariableStorageSelectorLib.h>
+#include <Library/PeiVariableCacheLib.h>
+#include <Guid/VariableFormat.h>
+#include <Guid/VariableIndexTable.h>
+#include <Guid/SystemNvDataGuid.h>
+
+typedef enum {
+ VariableHobTypeDefault,
+ VariableHobTypeCache,
+ VariableHobTypeMax
+} VARIABLE_HOB_TYPE;
+
+typedef struct {
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ //
+ // If it is not NULL, it means there may be an inconsecutive variable whose
+ // partial content is still in NV storage, but another partial content is backed up
+ // in spare block.
+ //
+ BOOLEAN AuthFlag;
+} VARIABLE_STORE_INFO;
+
+//
+// Functions
+//
+/**
+ Provide the functionality of the variable services.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
+ @param[in] PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS If the interface could be successfully installed
+ @retval Others Returned from PeiServicesInstallPpi()
+
+**/
+EFI_STATUS
+EFIAPI
+PeimInitializeVariableServices (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ This service retrieves a variable's value using its name and GUID.
+
+ Read the specified variable from the UEFI variable store. If the Data
+ buffer is too small to hold the contents of the variable, the error
+ EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
+ size to obtain the data.
+
+ @param[in] This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+ @param[in] VariableName A pointer to a null-terminated string that is the variable's name.
+ @param[in] VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+ @param[in] Attributes If non-NULL, on return, points to the variable's attributes.
+ @param[in] DataSize On entry, points to the size in bytes of the Data buffer.
+ On return, points to the size of the data returned in Data.
+ @param[in] Data Points to the buffer which will hold the returned variable value.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
+ DataSize is updated with the size required for
+ the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetVariable (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid,
+ OUT UINT32 *Attributes,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ Return the next variable name and GUID.
+
+ This function is called multiple times to retrieve the VariableName
+ and VariableGuid of all variables currently available in the system.
+ On each call, the previous results are passed into the interface,
+ and, on return, the interface returns the data for the next
+ interface. When the entire variable list has been returned,
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
+
+ @param[in] VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.
+ @param[in] VariableName On entry, a pointer to a null-terminated string that is the variable's name.
+ On return, points to the next variable's null-terminated name string.
+
+ @param[in] VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID.
+ On return, a pointer to the next variable's GUID.
+
+ @retval EFI_SUCCESS The variable was read successfully.
+ @retval EFI_NOT_FOUND The variable could not be found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting
+ data. VariableNameSize is updated with the size
+ required for the specified variable.
+ @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
+ VariableNameSize is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNextVariableName (
+ IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
new file mode 100644
index 0000000000..24f64c21b9
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -0,0 +1,75 @@
+## @file
+# Implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiVariable
+ MODULE_UNI_FILE = PeiVariable.uni
+ FILE_GUID = 34C8C28F-B61C-45a2-8F2E-89E46BECC63B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimInitializeVariableServices
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ Variable.c
+ Variable.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ BroxtonPlatformPkg/PlatformPkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ MemoryAllocationLib
+ PcdLib
+ HobLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ PeiVariableCacheLib
+ VariableStorageSelectorLib
+
+[Guids]
+ ## CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiAuthenticatedVariableGuid
+ ## SOMETIMES_CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableGuid
+ ## SOMETIMES_PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiVariableIndexTableGuid
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
+ gReadOnlyVariablePreMemoryDescriptorPpiGuid ## PRODUCES
+ gVariableStoragePpiGuid ## CONSUMES
+
+[Pcd]
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PeiVariableExtra.uni
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c
new file mode 100644
index 0000000000..a0ad4c26dc
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c
@@ -0,0 +1,260 @@
+/** @file
+ Measure TrEE required variable.
+
+ Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/ImageAuthentication.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Protocol/TrEEProtocol.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE mVariableType[] = {
+ {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid},
+ {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid},
+ {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
+};
+
+/**
+ This function will return if this variable is SecureBootPolicy 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.
+
+ @retval TRUE This is SecureBootPolicy Variable.
+ @retval FALSE This is not SecureBootPolicy Variable.
+
+**/
+BOOLEAN
+IsSecureBootPolicyVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof (mVariableType) / sizeof (mVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ Measure and log an EFI variable, and extend the measurement result into a specific PCR.
+
+ @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] VarData The content of the variable data.
+ @param[in] VarSize The size of the variable data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *VarData,
+ IN UINTN VarSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarNameLength;
+ EFI_VARIABLE_DATA_TREE *VarLog;
+ UINT32 VarLogSize;
+
+ ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL));
+
+ VarNameLength = StrLen (VarName);
+ VarLogSize = (UINT32) (sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
+ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
+
+ VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
+ if (VarLog == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (&VarLog->VariableName, VendorGuid, sizeof (VarLog->VariableName));
+ VarLog->UnicodeNameLength = VarNameLength;
+ VarLog->VariableDataLength = VarSize;
+ CopyMem (
+ VarLog->UnicodeName,
+ VarName,
+ VarNameLength * sizeof (*VarName)
+ );
+ if (VarSize != 0) {
+ CopyMem (
+ (CHAR16 *) VarLog->UnicodeName + VarNameLength,
+ VarData,
+ VarSize
+ );
+ }
+
+ DEBUG ((EFI_D_INFO, "AuthVariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN) 7, (UINTN) EV_EFI_VARIABLE_AUTHORITY));
+ DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+ Status = TpmMeasureAndLogData (
+ 7,
+ EV_EFI_VARIABLE_DRIVER_CONFIG,
+ VarLog,
+ VarLogSize,
+ VarLog,
+ VarLogSize
+ );
+ FreePool (VarLog);
+ return Status;
+}
+
+
+/**
+ Returns the status whether get the variable success. The function retrieves
+ variable through the UEFI Runtime Service GetVariable(). The
+ returned buffer is allocated using AllocatePool(). The caller is responsible
+ for freeing this buffer with FreePool().
+
+ This API is only invoked in boot time. It may NOT be invoked at runtime.
+
+ @param[in] Name The pointer to a Null-terminated Unicode string.
+ @param[in] Guid The pointer to an EFI_GUID structure
+ @param[out] Value The buffer point saved the variable info.
+ @param[out] Size The buffer size of the variable.
+
+ @return EFI_OUT_OF_RESOURCES Allocate buffer failed.
+ @return EFI_SUCCESS Find the specified variable.
+ @return Others Errors Return errors from call to gRT->GetVariable.
+
+**/
+EFI_STATUS
+InternalGetVariable (
+ IN CONST CHAR16 *Name,
+ IN CONST EFI_GUID *Guid,
+ OUT VOID **Value,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ //
+ // Try to get the variable size.
+ //
+ BufferSize = 0;
+ *Value = NULL;
+ if (Size != NULL) {
+ *Size = 0;
+ }
+
+ Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ //
+ // Allocate buffer to get the variable.
+ //
+ *Value = AllocatePool (BufferSize);
+ ASSERT (*Value != NULL);
+ if (*Value == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get the variable data.
+ //
+ Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
+ if (EFI_ERROR (Status)) {
+ FreePool(*Value);
+ *Value = NULL;
+ }
+
+ if (Size != NULL) {
+ *Size = BufferSize;
+ }
+
+ return Status;
+}
+
+
+/**
+ SecureBoot Hook for SetVariable.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableDataSize;
+ VOID *VariableData;
+
+ if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) {
+ return ;
+ }
+
+ //
+ // We should NOT use Data and DataSize here,because it may include signature,
+ // or is just partial with append attributes, or is deleted.
+ // We should GetVariable again, to get full variable content.
+ //
+ Status = InternalGetVariable (
+ VariableName,
+ VendorGuid,
+ &VariableData,
+ &VariableDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ VariableData = NULL;
+ VariableDataSize = 0;
+ }
+
+ Status = MeasureVariable (
+ VariableName,
+ VendorGuid,
+ VariableData,
+ VariableDataSize
+ );
+ DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
+
+ if (VariableData != NULL) {
+ FreePool (VariableData);
+ }
+
+ return ;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c
new file mode 100644
index 0000000000..26de9bf9c1
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockDxe.c
@@ -0,0 +1,93 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control support (DXE version).
+
+ This module clears MemoryOverwriteRequestControlLock variable to indicate
+ MOR lock control unsupported.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "Variable.h"
+
+extern EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
+
+
+/**
+ This service is an MOR/MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName The name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable.
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
+ Variable driver can just return EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ //
+ // Just let it pass. No need provide protection for DXE version.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialization for MOR Lock Control.
+
+ @retval EFI_SUCEESS MorLock initialization success.
+ @retval Others Some error occurs.
+
+**/
+EFI_STATUS
+MorLockInit (
+ VOID
+ )
+{
+ //
+ // Always clear variable to report unsupported to OS.
+ // The reason is that the DXE version is not proper to provide *protection*.
+ // BIOS should use SMM version variable driver to provide such capability.
+ //
+ VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+
+ //
+ // Need set this variable to be read-only to prevent other module set it.
+ //
+ VariableLockRequestToLock (&mVariableLock, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid);
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
new file mode 100644
index 0000000000..2a500401d3
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
@@ -0,0 +1,407 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control support (SMM version).
+
+ This module initilizes MemoryOverwriteRequestControlLock variable.
+ This module adds Variable Hook and check MemoryOverwriteRequestControlLock.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "Variable.h"
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE mMorVariableType[] = {
+ {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid},
+ {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid},
+};
+
+#define MOR_LOCK_DATA_UNLOCKED 0x0
+#define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1
+#define MOR_LOCK_DATA_LOCKED_WITH_KEY 0x2
+
+#define MOR_LOCK_V1_SIZE 1
+#define MOR_LOCK_V2_KEY_SIZE 8
+
+typedef enum {
+ MorLockStateUnlocked = 0,
+ MorLockStateLocked = 1,
+} MOR_LOCK_STATE;
+
+UINT8 mMorLockKey[MOR_LOCK_V2_KEY_SIZE];
+BOOLEAN mMorLockKeyEmpty = TRUE;
+BOOLEAN mMorLockPassThru = FALSE;
+MOR_LOCK_STATE mMorLockState = MorLockStateUnlocked;
+
+
+/**
+ Returns if this is MOR related variable.
+
+ @param[in] VariableName The name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR related.
+ @retval FALSE The variable is NOT MOR related.
+
+**/
+BOOLEAN
+IsAnyMorVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof (mMorVariableType) / sizeof (mMorVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ Returns if this is MOR lock variable.
+
+ @param[in] VariableName The name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR lock variable.
+ @retval FALSE The variable is NOT MOR lock variable.
+
+**/
+BOOLEAN
+IsMorLockVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&
+ (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid))) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Set MOR lock variable.
+
+ @param[in] Data MOR Lock variable data.
+
+ @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 was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode 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 saved due to a hardware failure.
+ @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_AUTHENTICATED_WRITE_ACCESS
+ 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
+SetMorLockVariable (
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+
+ mMorLockPassThru = TRUE;
+ Status = VariableServiceSetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (Data),
+ &Data
+ );
+ mMorLockPassThru = FALSE;
+
+ return Status;
+}
+
+
+/**
+ This service is an MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName The name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MorLock check pass, and Variable driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MorLock data or data size or attributes is not allowed.
+ @retval EFI_ACCESS_DENIED The MorLock is locked.
+ @retval EFI_WRITE_PROTECTED The MorLock deletion is not allowed.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
+ Variable driver can just return EFI_SUCCESS.
+**/
+EFI_STATUS
+SetVariableCheckHandlerMorLock (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Basic Check
+ //
+ if (Attributes == 0 || DataSize == 0 || Data == NULL) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+ ((DataSize != MOR_LOCK_V1_SIZE) && (DataSize != MOR_LOCK_V2_KEY_SIZE))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Do not check if the request is passthru.
+ //
+ if (mMorLockPassThru) {
+ return EFI_SUCCESS;
+ }
+
+ if (mMorLockState == MorLockStateUnlocked) {
+ //
+ // In Unlocked State
+ //
+ if (DataSize == MOR_LOCK_V1_SIZE) {
+ //
+ // V1 - lock permenantly
+ //
+ if (*(UINT8 *) Data == MOR_LOCK_DATA_UNLOCKED) {
+ //
+ // Unlock
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
+ if (!EFI_ERROR (Status)) {
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ } else {
+ //
+ // SetVar fail
+ //
+ return Status;
+ }
+ } else if (*(UINT8 *) Data == MOR_LOCK_DATA_LOCKED_WITHOUT_KEY) {
+ //
+ // Lock without key
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Lock success
+ //
+ mMorLockState = MorLockStateLocked;
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ } else {
+ //
+ // SetVar fail
+ //
+ return Status;
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (DataSize == MOR_LOCK_V2_KEY_SIZE) {
+ //
+ // V2 lock and provision the key
+ //
+
+ //
+ // Need set here because the data value on flash is different
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY);
+ if (EFI_ERROR(Status)) {
+ //
+ // SetVar fail, do not provision the key
+ //
+ return Status;
+ } else {
+ //
+ // Lock success, provision the key
+ //
+ mMorLockKeyEmpty = FALSE;
+ CopyMem (mMorLockKey, Data, MOR_LOCK_V2_KEY_SIZE);
+ mMorLockState = MorLockStateLocked;
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // In Locked State
+ //
+ if (mMorLockKeyEmpty || (DataSize != MOR_LOCK_V2_KEY_SIZE)) {
+ return EFI_ACCESS_DENIED;
+ }
+ if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) == 0)) {
+ //
+ // Key match - unlock
+ //
+
+ //
+ // Need set here because the data value on flash is different
+ //
+ Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);
+ if (EFI_ERROR (Status)) {
+ //
+ // SetVar fail
+ //
+ return Status;
+ } else {
+ //
+ // Unlock Success
+ //
+ mMorLockState = MorLockStateUnlocked;
+ mMorLockKeyEmpty = TRUE;
+ ZeroMem (mMorLockKey, sizeof (mMorLockKey));
+ //
+ // return EFI_ALREADY_STARTED to skip variable set.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+ } else {
+ //
+ // Key mismatch - Prevent Dictionary Attack
+ //
+ mMorLockState = MorLockStateLocked;
+ mMorLockKeyEmpty = TRUE;
+ ZeroMem (mMorLockKey, sizeof (mMorLockKey));
+ return EFI_ACCESS_DENIED;
+ }
+ }
+}
+
+
+/**
+ This service is an MOR/MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName The name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable.
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
+ Variable driver can just return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ //
+ // do not handle non-MOR variable
+ //
+ if (!IsAnyMorVariable (VariableName, VendorGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // MorLock variable
+ //
+ if (IsMorLockVariable (VariableName, VendorGuid)) {
+ return SetVariableCheckHandlerMorLock (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ }
+
+ //
+ // Mor Variable
+ //
+ //
+ // Basic Check
+ //
+ if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||
+ (DataSize != sizeof (UINT8)) ||
+ (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (mMorLockState == MorLockStateLocked) {
+ //
+ // If lock, deny access
+ //
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // grant access
+ //
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialization for MOR Lock Control.
+
+ @retval EFI_SUCEESS MorLock initialization success.
+ @retval Others Some error occurs.
+
+**/
+EFI_STATUS
+MorLockInit (
+ VOID
+ )
+{
+ //
+ // Set variable to report capability to OS
+ //
+ return SetMorLockVariable (0);
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c
new file mode 100644
index 0000000000..bd0dc0ca42
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VarCheck.c
@@ -0,0 +1,161 @@
+/** @file
+ Implementation functions and structures for var check protocol
+ and variable lock protocol based on VarCheckLib.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+
+
+/**
+ 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 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
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Status = VarCheckLibVariablePropertyGet (VariableName, VendorGuid, &Property);
+ if (!EFI_ERROR (Status)) {
+ Property.Property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ } else {
+ Property.Revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ Property.Property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ Property.Attributes = 0;
+ Property.MinSize = 1;
+ Property.MaxSize = MAX_UINTN;
+ }
+ Status = VarCheckLibVariablePropertySet (VariableName, VendorGuid, &Property);
+
+ DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s %r\n", VendorGuid, VariableName, Status));
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @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 for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ )
+{
+ EFI_STATUS Status;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ Status = VarCheckLibRegisterSetVariableCheckHandler (Handler);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @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 for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ Status = VarCheckLibVariablePropertySet (Name, Guid, VariableProperty);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ Status = VarCheckLibVariablePropertyGet (Name, Guid, VariableProperty);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
new file mode 100644
index 0000000000..43687dafe8
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -0,0 +1,4818 @@
+/** @file
+ The common variable operation routines shared by DXE_RUNTIME variable
+ module and DXE_SMM variable module.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. They may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
+ They need check input parameter.
+
+ VariableServiceGetVariable() and VariableServiceSetVariable() are external API
+ to receive datasize and data buffer. The size should be checked carefully.
+
+ VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
+ integer overflow. It should also check attribute to avoid authentication bypass.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+
+///
+/// A flag which indicates whether all variables should be treated as volatile
+///
+BOOLEAN mForceVolatileVariable;
+
+///
+/// Define a memory cache that improves the search performance for a variable.
+///
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
+
+///
+/// The memory entry used for variable statistics data.
+///
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+///
+/// Buffer for temporary storage of variable contents when copying to NV cache
+///
+VOID *mVariableDataBuffer = NULL;
+
+///
+/// It indicates the var check request source.
+/// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
+///
+VAR_CHECK_REQUEST_SOURCE mRequestSource = VarCheckFromUntrusted;
+CHAR16 mVariableNameBuffer[MAX_VARIABLE_NAME_SIZE];
+
+//
+// It will record the current boot error flag before EndOfDxe.
+//
+VAR_ERROR_FLAG mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;
+
+VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {
+ {
+ &gEdkiiVarErrorFlagGuid,
+ VAR_ERROR_FLAG_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (VAR_ERROR_FLAG),
+ sizeof (VAR_ERROR_FLAG)
+ }
+ },
+};
+
+AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {
+ AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,
+ //
+ // StructSize, TO BE FILLED
+ //
+ 0,
+ //
+ // MaxAuthVariableSize, TO BE FILLED
+ //
+ 0,
+ VariableExLibFindVariable,
+ VariableExLibFindNextVariable,
+ VariableExLibUpdateVariable,
+ VariableExLibGetScratchBuffer,
+ VariableExLibCheckRemainingSpaceForConsistency,
+ VariableExLibAtRuntime,
+};
+
+AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
+
+
+/**
+ SecureBoot Hook for auth variable update.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+
+/**
+ Initialization for MOR Lock Control.
+
+ @retval EFI_SUCEESS MorLock initialization success.
+ @retval Others Some error occurs.
+
+**/
+EFI_STATUS
+MorLockInit (
+ VOID
+ );
+
+
+/**
+ This service is an MOR/MorLock checker handler for the SetVariable().
+
+ @param[in] VariableName The name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data.
+ @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable.
+ @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
+ @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
+ Variable driver can just return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+
+/**
+ Routine used to track statistical information about variable usage.
+ The data is stored in the EFI system table so it can be accessed later.
+ VariableInfo.efi can dump out the table. Only Boot Services variable
+ accesses are tracked by this code. The PcdVariableCollectStatistics
+ build flag controls if this feature is enabled.
+
+ A read that hits in the cache will have Read and Cache true for
+ the transaction. Data is allocated by this routine, but never
+ freed.
+
+ @param[in] VariableName Name of the Variable to track.
+ @param[in] VendorGuid Guid of the Variable to track.
+ @param[in] Volatile TRUE if volatile FALSE if non-volatile.
+ @param[in] Read TRUE if GetVariable() was called.
+ @param[in] Write TRUE if SetVariable() was called.
+ @param[in] Delete TRUE if deleted via SetVariable().
+ @param[in] Cache TRUE for a cache hit.
+
+**/
+VOID
+UpdateVariableInfo (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN Read,
+ IN BOOLEAN Write,
+ IN BOOLEAN Delete,
+ IN BOOLEAN Cache
+ )
+{
+ VARIABLE_INFO_ENTRY *Entry;
+
+ if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+
+ if (AtRuntime ()) {
+ //
+ // Don't collect statistics at runtime.
+ //
+ return;
+ }
+
+ if (gVariableInfo == NULL) {
+ //
+ // On the first call allocate a entry and place a pointer to it in
+ // the EFI System Table.
+ //
+ gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+
+ if (gVariableInfo == NULL) {
+ ASSERT (gVariableInfo != NULL);
+ return;
+ }
+
+ CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
+ gVariableInfo->Name = AllocateZeroPool (StrSize (VariableName));
+
+ if (gVariableInfo->Name == NULL) {
+ ASSERT (gVariableInfo->Name != NULL);
+ return;
+ }
+
+ StrCpyS (gVariableInfo->Name, StrSize (VariableName) / sizeof (CHAR16), VariableName);
+ gVariableInfo->Volatile = Volatile;
+ }
+
+
+ for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
+ if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
+ if (StrCmp (VariableName, Entry->Name) == 0) {
+ if (Read) {
+ Entry->ReadCount++;
+ }
+ if (Write) {
+ Entry->WriteCount++;
+ }
+ if (Delete) {
+ Entry->DeleteCount++;
+ }
+ if (Cache) {
+ Entry->CacheCount++;
+ }
+ return;
+ }
+ }
+
+ if (Entry->Next == NULL) {
+ //
+ // If the entry is not in the table add it.
+ // Next iteration of the loop will fill in the data.
+ //
+ Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+
+ if (Entry->Next == NULL) {
+ ASSERT (Entry->Next != NULL);
+ return;
+ }
+
+ CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
+ Entry->Next->Name = AllocateZeroPool (StrSize (VariableName));
+ ASSERT (Entry->Next->Name != NULL);
+ StrCpyS (Entry->Next->Name, StrSize (VariableName) /sizeof (CHAR16), VariableName);
+ Entry->Next->Volatile = Volatile;
+ }
+
+ }
+ }
+}
+
+
+/**
+ This code checks if variable header is valid or not.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] VariableStoreEnd Pointer to the Variable Store End.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableStoreEnd
+ )
+{
+ if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {
+ //
+ // Variable is NULL or has reached the end of variable store,
+ // or the StartId is not correct.
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ This function writes data to the FWH at the correct LBA even if the LBAs
+ are fragmented.
+
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Volatile Point out the Variable is Volatile or Non-Volatile.
+ @param[in] SetByIndex TRUE if target pointer is given as index.
+ FALSE if target pointer is absolute.
+ @param[in] DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
+ structure.
+ @param[in] DataSize Size of data to be written.
+ @param[in] Buffer Pointer to the buffer from which data is written.
+
+ @retval EFI_INVALID_PARAMETER Parameters not valid.
+ @retval EFI_SUCCESS Variable store successfully updated.
+
+**/
+EFI_STATUS
+UpdateVariableStore (
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN SetByIndex,
+ IN UINTN DataPtrIndex,
+ IN UINT32 DataSize,
+ IN UINT8 *Buffer
+ )
+{
+ VARIABLE_STORE_HEADER *VolatileBase;
+ EFI_PHYSICAL_ADDRESS DataPtr;
+
+ DataPtr = DataPtrIndex;
+ //
+ // Check if the Data is Volatile.
+ //
+ if (!Volatile) {
+ //
+ // Data Pointer should point to the actual Address where data is to be
+ // written.
+ //
+ if (SetByIndex) {
+ DataPtr += (UINTN) mNvVariableCache;
+ }
+
+ if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) mNvVariableCache + mNvVariableCache->Size))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // Data Pointer should point to the actual Address where data is to be
+ // written.
+ //
+ VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+ if (SetByIndex) {
+ DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ }
+
+ if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ CopyMem ((UINT8 *) (UINTN) DataPtr, Buffer, DataSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This code gets the current status of Variable Store.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @retval EfiRaw Variable store status is raw.
+ @retval EfiValid Variable store status is valid.
+ @retval EfiInvalid Variable store status is invalid.
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
+ CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
+ VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
+ VarStoreHeader->State == VARIABLE_STORE_HEALTHY
+ ) {
+
+ return EfiValid;
+ } else if (((UINT32 *) (&VarStoreHeader->Signature))[0] == 0xffffffff &&
+ ((UINT32 *) (&VarStoreHeader->Signature))[1] == 0xffffffff &&
+ ((UINT32 *) (&VarStoreHeader->Signature))[2] == 0xffffffff &&
+ ((UINT32 *) (&VarStoreHeader->Signature))[3] == 0xffffffff &&
+ VarStoreHeader->Size == 0xffffffff &&
+ VarStoreHeader->Format == 0xff &&
+ VarStoreHeader->State == 0xff
+ ) {
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+
+/**
+ This code gets the size of variable header.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ VOID
+ )
+{
+ UINTN Value;
+
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ Value = sizeof (VARIABLE_HEADER);
+ }
+
+ return Value;
+}
+
+
+/**
+ This code gets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->NameSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+ }
+}
+
+
+/**
+ This code sets the size of name of variable.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] NameSize Name size to set.
+
+**/
+VOID
+SetNameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN NameSize
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable->NameSize = (UINT32) NameSize;
+ } else {
+ Variable->NameSize = (UINT32) NameSize;
+ }
+}
+
+
+/**
+ This code gets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ if (AuthVariable->State == (UINT8) (-1) ||
+ AuthVariable->DataSize == (UINT32) (-1) ||
+ AuthVariable->NameSize == (UINT32) (-1) ||
+ AuthVariable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) AuthVariable->DataSize;
+ } else {
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) (-1) ||
+ Variable->NameSize == (UINT32) (-1) ||
+ Variable->Attributes == (UINT32) (-1)) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+ }
+}
+
+
+/**
+ This code sets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+ @param[in] DataSize Data size to set.
+
+**/
+VOID
+SetDataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable,
+ IN UINTN DataSize
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable->DataSize = (UINT32) DataSize;
+ } else {
+ Variable->DataSize = (UINT32) DataSize;
+ }
+}
+
+
+/**
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize ());
+}
+
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ return &AuthVariable->VendorGuid;
+ } else {
+ return &Variable->VendorGuid;
+ }
+}
+
+
+/**
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+
+/**
+ This code gets the variable data offset related to variable header.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return Variable Data offset.
+
+**/
+UINTN
+GetVariableDataOffset (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment
+ //
+ Value = GetVariableHeaderSize ();
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return Value;
+}
+
+
+/**
+ This code gets the pointer to the next variable header.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+
+/**
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+
+/**
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+ Gets the VARIABLE_STORAGE_PROTOCOL for the NV Storage that should store
+ a variable with the given name and GUID
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] VariableStorageProtocol The found VARIABLE_STORAGE_PROTOCOL
+
+ @retval EFI_INVALID_PARAMETER If VariableName is an empty string, or
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS VARIABLE_STORAGE_PROTOCOL successfully found.
+ @retval EFI_NOT_FOUND VARIABLE_STORAGE_PROTOCOL not found
+
+**/
+EFI_STATUS
+GetVariableStorageProtocol (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_STORAGE_PROTOCOL **VariableStorageProtocol
+ )
+{
+ EFI_GUID VariableStorageId;
+ EFI_GUID InstanceGuid;
+ VARIABLE_STORAGE_PROTOCOL *CurrentInstance;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *VariableStorageProtocol = NULL;
+ ZeroMem ((VOID *) &VariableStorageId, sizeof (EFI_GUID));
+ Status = GetVariableStorageId (VariableName, VendorGuid, TRUE, &VariableStorageId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ CurrentInstance = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ ZeroMem ((VOID *) &InstanceGuid, sizeof (EFI_GUID));
+ Status = CurrentInstance->GetId (&InstanceGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CompareGuid (&VariableStorageId, &InstanceGuid)) {
+ *VariableStorageProtocol = CurrentInstance;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Record variable error flag.
+
+ @param[in] Flag Variable error flag to record.
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] VariableSize Size of the variable.
+
+**/
+VOID
+RecordVarErrorFlag (
+ IN VAR_ERROR_FLAG Flag,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN VariableSize
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ VAR_ERROR_FLAG *VarErrFlag;
+ VAR_ERROR_FLAG TempFlag;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+
+ DEBUG_CODE (
+ DEBUG ((EFI_D_ERROR, " Variable Driver: RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));
+ if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {
+ if (AtRuntime ()) {
+ DEBUG ((EFI_D_ERROR, " Variable Driver: CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
+ } else {
+ DEBUG ((EFI_D_ERROR, " Variable Driver: CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, " Variable Driver: CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));
+ }
+ );
+
+ if (!mEndOfDxe) {
+ //
+ // Before EndOfDxe, just record the current boot variable error flag to local variable,
+ // and leave the variable error flag in NV flash as the last boot variable error flag.
+ // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
+ // will be initialized to this local current boot variable error flag.
+ //
+ mCurrentBootVarErrFlag &= Flag;
+ return;
+ }
+
+ //
+ // Record error flag (it should have be initialized).
+ //
+ Status = FindVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr);
+ TempFlag = *VarErrFlag;
+ TempFlag &= Flag;
+ if (TempFlag == *VarErrFlag) {
+ return;
+ }
+ VariableStorageProtocol = NULL;
+ Status = GetVariableStorageProtocol (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &VariableStorageProtocol
+ );
+ if (!EFI_ERROR (Status) && VariableStorageProtocol != NULL) {
+ //
+ // Update the data in NV
+ //
+ if (VariableStorageProtocol->WriteServiceIsReady (
+ VariableStorageProtocol)) {
+ Status = VariableStorageProtocol->SetVariable (
+ VariableStorageProtocol,
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (TempFlag),
+ &TempFlag,
+ AtRuntime (),
+ 0,
+ 0,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update the data in NV cache.
+ //
+ *VarErrFlag = TempFlag;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ Initialize variable error flag.
+
+ Before EndOfDxe, the variable indicates the last boot variable error flag,
+ then it means the last boot variable error flag must be got before EndOfDxe.
+ After EndOfDxe, the variable indicates the current boot variable error flag,
+ then it means the current boot variable error flag must be got after EndOfDxe.
+
+**/
+VOID
+InitializeVarErrorFlag (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ VAR_ERROR_FLAG Flag;
+ VAR_ERROR_FLAG VarErrFlag;
+
+ if (!mEndOfDxe) {
+ return;
+ }
+
+ Flag = mCurrentBootVarErrFlag;
+ DEBUG ((EFI_D_INFO, " Variable Driver: Initialize variable error flag (%02x)\n", Flag));
+
+ Status = FindVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr));
+ if (VarErrFlag == Flag) {
+ return;
+ }
+ }
+
+ UpdateVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ &Flag,
+ sizeof (Flag),
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+}
+
+
+/**
+ Is user variable?
+
+ @param[in] Variable Pointer to variable header.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ //
+ // Only after End Of Dxe, the variables belong to system variable are fixed.
+ // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
+ // then no need to check if the variable is user variable or not specially.
+ //
+ if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
+ if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ Calculate common user variable total size.
+
+**/
+VOID
+CalculateCommonUserVariableTotalSize (
+ VOID
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *NextVariable;
+ UINTN VariableSize;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ //
+ // Only after End Of Dxe, the variables belong to system variable are fixed.
+ // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
+ // then no need to calculate the common user variable total size specially.
+ //
+ if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
+ Variable = GetStartPointer (mNvVariableCache);
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
+ NextVariable = GetNextVariablePtr (Variable);
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {
+ //
+ // No property, it is user variable.
+ //
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+
+ Variable = NextVariable;
+ }
+ }
+}
+
+
+/**
+ Initialize variable quota.
+
+**/
+VOID
+InitializeVariableQuota (
+ VOID
+ )
+{
+ if (!mEndOfDxe) {
+ return;
+ }
+
+ InitializeVarErrorFlag ();
+ CalculateCommonUserVariableTotalSize ();
+}
+
+
+/**
+ Find the variable in the specified variable store.
+
+ @param[in] VariableName Name of the variable to be found
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+ @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
+
+ @retval EFI_SUCCESS Variable found successfully
+ @retval EFI_NOT_FOUND Variable not found
+**/
+EFI_STATUS
+FindVariableEx (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN IgnoreRtCheck,
+ IN OUT VARIABLE_POINTER_TRACK *PtrTrack
+ )
+{
+ VARIABLE_HEADER *InDeletedVariable;
+ VOID *Point;
+
+ PtrTrack->InDeletedTransitionPtr = NULL;
+
+ //
+ // Find the variable by walk through HOB, volatile and non-volatile variable store.
+ //
+ InDeletedVariable = NULL;
+
+ for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
+ ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
+ ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)
+ ) {
+ if (PtrTrack->CurrPtr->State == VAR_ADDED ||
+ PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
+ ) {
+ if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+ if (VariableName[0] == 0) {
+ if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
+ return EFI_SUCCESS;
+ }
+ } else {
+ if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr))) {
+ Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);
+
+ ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);
+ if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {
+ if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ InDeletedVariable = PtrTrack->CurrPtr;
+ } else {
+ PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ PtrTrack->CurrPtr = InDeletedVariable;
+ return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+
+/**
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not;
+ if it is non-volatile, need FTW.
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
+ @param[in] NewVariable Pointer to new variable.
+ @param[in] NewVariableSize New variable size.
+
+ @return EFI_SUCCESS Reclaim operation has finished successfully.
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
+ @return Others Unexpect error happened during reclaim operation.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
+ IN VARIABLE_HEADER *NewVariable,
+ IN UINTN NewVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *AddedVariable;
+ VARIABLE_HEADER *NextVariable;
+ VARIABLE_HEADER *NextAddedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT8 *ValidBuffer;
+ UINTN MaximumBufferSize;
+ UINTN VariableSize;
+ UINTN NameSize;
+ UINT8 *CurrPtr;
+ VOID *Point0;
+ VOID *Point1;
+ BOOLEAN FoundAdded;
+ EFI_STATUS Status;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ VARIABLE_HEADER *UpdatingVariable;
+ VARIABLE_HEADER *UpdatingInDeletedTransition;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+ VARIABLE_POINTER_TRACK VarErrFlagPtr;
+
+ Status = EFI_SUCCESS;
+
+ UpdatingVariable = NULL;
+ UpdatingInDeletedTransition = NULL;
+
+ if (UpdatingPtrTrack != NULL) {
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;
+ UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
+
+ CommonVariableTotalSize = 0;
+ CommonUserVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if (IsVolatile || mForceVolatileVariable) {
+ //
+ // Start Pointers for the variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable);
+ if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
+ Variable != UpdatingVariable &&
+ Variable != UpdatingInDeletedTransition
+ ) {
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ MaximumBufferSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ if (NewVariable != NULL) {
+ //
+ // Add the new variable size.
+ //
+ MaximumBufferSize += NewVariableSize;
+ }
+
+ //
+ // Reserve the 1 Bytes with Oxff to identify the
+ // end of the variable buffer.
+ //
+ MaximumBufferSize += 1;
+ ValidBuffer = AllocatePool (MaximumBufferSize);
+ if (ValidBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+ //
+ // Copy variable store header.
+ //
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
+ CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
+
+ //
+ // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable);
+ if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
+ CurrPtr += VariableSize;
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ HwErrVariableTotalSize += VariableSize;
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ Variable = NextVariable;
+ }
+
+ //
+ // Reinstall all in delete transition variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable);
+ if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // Buffer has cached all ADDED variable.
+ // Per IN_DELETED variable, we have to guarantee that
+ // no ADDED one in previous buffer.
+ //
+ FoundAdded = FALSE;
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
+ while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) {
+ NextAddedVariable = GetNextVariablePtr (AddedVariable);
+ NameSize = NameSizeOfVariable (AddedVariable);
+ if (CompareGuid (GetVendorGuidPtr (AddedVariable), GetVendorGuidPtr (Variable)) &&
+ NameSize == NameSizeOfVariable (Variable)
+ ) {
+ Point0 = (VOID *) GetVariableNamePtr (AddedVariable);
+ Point1 = (VOID *) GetVariableNamePtr (Variable);
+ if (CompareMem (Point0, Point1, NameSize) == 0) {
+ FoundAdded = TRUE;
+ break;
+ }
+ }
+ AddedVariable = NextAddedVariable;
+ }
+ if (!FoundAdded) {
+ //
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
+ //
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
+ ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
+ CurrPtr += VariableSize;
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ HwErrVariableTotalSize += VariableSize;
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ CommonVariableTotalSize += VariableSize;
+ if (IsUserVariable (Variable)) {
+ CommonUserVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ }
+
+ Variable = NextVariable;
+ }
+ } else {
+ //
+ // If we are reclaiming the NV cache, just clear it out. The cache will be rebuilt from NV as needed
+ //
+ ValidBuffer = (UINT8 *) mNvVariableCache;
+ VarErrFlagPtr.CurrPtr = NULL;
+
+ //
+ // Compute the changes to NV storage usage
+ //
+ HwErrVariableTotalSize = mVariableModuleGlobal->HwErrVariableTotalSize;
+ CommonVariableTotalSize = mVariableModuleGlobal->CommonVariableTotalSize;
+ CommonUserVariableTotalSize = mVariableModuleGlobal->CommonUserVariableTotalSize;
+ if (NewVariable != NULL && UpdatingVariable != NULL) {
+ NextVariable = GetNextVariablePtr (UpdatingPtrTrack->CurrPtr);
+ VariableSize = (UINTN) NextVariable - (UINTN) UpdatingPtrTrack->CurrPtr;
+ if ((UpdatingPtrTrack->CurrPtr->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize -= VariableSize;
+ } else if ((UpdatingPtrTrack->CurrPtr->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ CommonVariableTotalSize -= VariableSize;
+ if (IsUserVariable (UpdatingPtrTrack->CurrPtr)) {
+ CommonUserVariableTotalSize -= VariableSize;
+ }
+ }
+ }
+
+ //
+ // Retain VarErrorFlag in the NV cache
+ //
+ if (mEndOfDxe) {
+ VarErrFlagPtr.StartPtr = GetStartPointer (VariableStoreHeader);
+ VarErrFlagPtr.EndPtr = GetEndPointer (VariableStoreHeader);
+ VarErrFlagPtr.Volatile = FALSE;
+ if (IsValidVariableHeader (VarErrFlagPtr.StartPtr, VarErrFlagPtr.EndPtr)) {
+ Status = FindVariableEx (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ TRUE,
+ &VarErrFlagPtr
+ );
+ if (!EFI_ERROR (Status) && VarErrFlagPtr.CurrPtr != NULL) {
+ NextVariable = GetNextVariablePtr (VarErrFlagPtr.CurrPtr);
+ VariableSize = (UINTN) NextVariable - (UINTN) VarErrFlagPtr.CurrPtr;
+ } else {
+ VarErrFlagPtr.CurrPtr = NULL;
+ }
+ }
+ }
+
+ //
+ // Delete all existing data
+ //
+ Point0 = (VOID *) GetStartPointer (VariableStoreHeader);
+ Point1 = (VOID *) GetEndPointer (VariableStoreHeader);
+ CurrPtr = (UINT8 *) Point0;
+ if (VarErrFlagPtr.CurrPtr != NULL && IsValidVariableHeader (Point0, Point1)) {
+ CopyMem (Point0, VarErrFlagPtr.CurrPtr, VariableSize);
+ Point0 = (UINT8 *) GetNextVariablePtr ((VARIABLE_HEADER *) Point0);
+ }
+
+ if (Point1 > Point0) {
+ MaximumBufferSize = (UINTN) Point1 - (UINTN) Point0;
+ SetMem (Point0, MaximumBufferSize, 0xff);
+ }
+ }
+
+ //
+ // Install the new variable if it is not NULL.
+ //
+ if (NewVariable != NULL) {
+ if ((UINTN) (CurrPtr - ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
+ //
+ // No enough space to store the new variable.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ if (!IsVolatile) {
+ if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += NewVariableSize;
+ } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ CommonVariableTotalSize += NewVariableSize;
+ if (IsUserVariable (NewVariable)) {
+ CommonUserVariableTotalSize += NewVariableSize;
+ }
+ }
+ if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
+ (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
+ (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
+ //
+ // No enough space to store the new variable by NV or NV+HR attribute.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Update the data in NV
+ //
+ if (!mForceVolatileVariable) {
+ VariableStorageProtocol = NULL;
+ Status = GetVariableStorageProtocol (
+ GetVariableNamePtr (NewVariable),
+ GetVendorGuidPtr (NewVariable),
+ &VariableStorageProtocol
+ );
+ if (!EFI_ERROR (Status) && VariableStorageProtocol != NULL) {
+ if (VariableStorageProtocol->WriteServiceIsReady (VariableStorageProtocol)) {
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) NewVariable;
+ Status = VariableStorageProtocol->SetVariable (
+ VariableStorageProtocol,
+ GetVariableNamePtr (NewVariable),
+ GetVendorGuidPtr (NewVariable),
+ NewVariable->Attributes,
+ DataSizeOfVariable (NewVariable),
+ GetVariableDataPtr (NewVariable),
+ AtRuntime (),
+ AuthVariable->PubKeyIndex,
+ ReadUnaligned64 (&(AuthVariable->MonotonicCount)),
+ &AuthVariable->TimeStamp
+ );
+ } else {
+ Status = VariableStorageProtocol->SetVariable (
+ VariableStorageProtocol,
+ GetVariableNamePtr (NewVariable),
+ GetVendorGuidPtr (NewVariable),
+ NewVariable->Attributes,
+ DataSizeOfVariable (NewVariable),
+ GetVariableDataPtr (NewVariable),
+ AtRuntime (),
+ 0,
+ 0,
+ NULL
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ } else {
+ Status = EFI_NOT_AVAILABLE_YET;
+ goto Done;
+ }
+ } else {
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ }
+ goto Done;
+ }
+ }
+ }
+
+ CopyMem (CurrPtr, (UINT8 *) NewVariable, NewVariableSize);
+ ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
+ if (UpdatingVariable != NULL) {
+ UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));
+ UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
+ }
+ CurrPtr += NewVariableSize;
+ }
+
+ *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);
+ if (IsVolatile) {
+ //
+ // If volatile variable store, just copy valid buffer.
+ //
+ SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
+ CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - ValidBuffer));
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // If non-volatile variable store, update NV storage usage
+ //
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
+ }
+
+Done:
+ if (IsVolatile || mForceVolatileVariable) {
+ FreePool (ValidBuffer);
+ }
+
+ return Status;
+}
+
+
+/**
+ Get index from supported language codes according to language string.
+
+ This code is used to get corresponding index in supported language codes. It can handle
+ RFC4646 and ISO639 language tags.
+ In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
+ In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Lang = "eng"
+ Iso639Language = TRUE
+ The return value is "0".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Lang = "fr-FR"
+ Iso639Language = FALSE
+ The return value is "3".
+
+ @param[in] SupportedLang Platform supported language codes.
+ @param[in] Lang Configured language.
+ @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+ @retval The index of language in the language codes.
+
+**/
+UINTN
+GetIndexFromSupportedLangCodes (
+ IN CHAR8 *SupportedLang,
+ IN CHAR8 *Lang,
+ IN BOOLEAN Iso639Language
+ )
+{
+ UINTN Index;
+ UINTN CompareLength;
+ UINTN LanguageLength;
+
+ if (Iso639Language) {
+ CompareLength = ISO_639_2_ENTRY_SIZE;
+ for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
+ if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
+ //
+ // Successfully find the index of Lang string in SupportedLang string.
+ //
+ Index = Index / CompareLength;
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+ } else {
+ //
+ // Compare RFC4646 language code
+ //
+ Index = 0;
+ for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
+
+ for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
+ //
+ // Skip ';' characters in SupportedLang
+ //
+ for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
+ //
+ // Determine the length of the next language code in SupportedLang
+ //
+ for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
+
+ if ((CompareLength == LanguageLength) &&
+ (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
+ //
+ // Successfully find the index of Lang string in SupportedLang string.
+ //
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+ }
+}
+
+
+/**
+ Get language string from supported language codes according to index.
+
+ This code is used to get corresponding language strings in supported language codes. It can handle
+ RFC4646 and ISO639 language tags.
+ In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
+ In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Index = "1"
+ Iso639Language = TRUE
+ The return value is "fra".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Index = "1"
+ Iso639Language = FALSE
+ The return value is "fr".
+
+ @param[in] SupportedLang Platform supported language codes.
+ @param[in] Index The index in supported language codes.
+ @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+ @retval The language string in the language codes.
+
+**/
+CHAR8 *
+GetLangFromSupportedLangCodes (
+ IN CHAR8 *SupportedLang,
+ IN UINTN Index,
+ IN BOOLEAN Iso639Language
+ )
+{
+ UINTN SubIndex;
+ UINTN CompareLength;
+ CHAR8 *Supported;
+
+ SubIndex = 0;
+ Supported = SupportedLang;
+ if (Iso639Language) {
+ //
+ // According to the index of Lang string in SupportedLang string to get the language.
+ // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+ //
+ CompareLength = ISO_639_2_ENTRY_SIZE;
+ mVariableModuleGlobal->Lang[CompareLength] = '\0';
+ return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
+
+ } else {
+ while (TRUE) {
+ //
+ // Take semicolon as delimitation, sequentially traverse supported language codes.
+ //
+ for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
+ Supported++;
+ }
+ if ((*Supported == '\0') && (SubIndex != Index)) {
+ //
+ // Have completed the traverse, but not find corrsponding string.
+ // This case is not allowed to happen.
+ //
+ ASSERT(FALSE);
+ return NULL;
+ }
+ if (SubIndex == Index) {
+ //
+ // According to the index of Lang string in SupportedLang string to get the language.
+ // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+ //
+ mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
+ return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
+ }
+ SubIndex++;
+
+ //
+ // Skip ';' characters in Supported
+ //
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);
+ }
+ }
+}
+
+
+/**
+ Returns a pointer to an allocated buffer that contains the best matching language
+ from a set of supported languages.
+
+ This function supports both ISO 639-2 and RFC 4646 language codes, but language
+ code types may not be mixed in a single call to this function. This function
+ supports a variable argument list that allows the caller to pass in a prioritized
+ list of language codes to test against all the language codes in SupportedLanguages.
+
+ If SupportedLanguages is NULL, then ASSERT().
+
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
+ contains a set of language codes in the format
+ specified by Iso639Language.
+ @param[in] Iso639Language If TRUE, then all language codes are assumed to be
+ in ISO 639-2 format. If FALSE, then all language
+ codes are assumed to be in RFC 4646 language format
+ @param[in] ... A variable argument list that contains pointers to
+ Null-terminated ASCII strings that contain one or more
+ language codes in the format specified by Iso639Language.
+ The first language code from each of these language
+ code lists is used to determine if it is an exact or
+ close match to any of the language codes in
+ SupportedLanguages. Close matches only apply to RFC 4646
+ language codes, and the matching algorithm from RFC 4647
+ is used to determine if a close match is present. If
+ an exact or close match is found, then the matching
+ language code from SupportedLanguages is returned. If
+ no matches are found, then the next variable argument
+ parameter is evaluated. The variable argument list
+ is terminated by a NULL.
+
+ @retval NULL The best matching language could not be found in SupportedLanguages.
+ @retval NULL There are not enough resources available to return the best matching
+ language.
+ @retval Other A pointer to a Null-terminated ASCII string that is the best matching
+ language in SupportedLanguages.
+
+**/
+CHAR8 *
+EFIAPI
+VariableGetBestLanguage (
+ IN CONST CHAR8 *SupportedLanguages,
+ IN BOOLEAN Iso639Language,
+ ...
+ )
+{
+ VA_LIST Args;
+ CHAR8 *Language;
+ UINTN CompareLength;
+ UINTN LanguageLength;
+ CONST CHAR8 *Supported;
+ CHAR8 *Buffer;
+
+ if (SupportedLanguages == NULL) {
+ return NULL;
+ }
+
+ VA_START (Args, Iso639Language);
+ while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
+ //
+ // Default to ISO 639-2 mode
+ //
+ CompareLength = 3;
+ LanguageLength = MIN (3, AsciiStrLen (Language));
+
+ //
+ // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
+ //
+ if (!Iso639Language) {
+ for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
+ }
+
+ //
+ // Trim back the length of Language used until it is empty
+ //
+ while (LanguageLength > 0) {
+ //
+ // Loop through all language codes in SupportedLanguages
+ //
+ for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
+ //
+ // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
+ //
+ if (!Iso639Language) {
+ //
+ // Skip ';' characters in Supported
+ //
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);
+ //
+ // Determine the length of the next language code in Supported
+ //
+ for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
+ //
+ // If Language is longer than the Supported, then skip to the next language
+ //
+ if (LanguageLength > CompareLength) {
+ continue;
+ }
+ }
+ //
+ // See if the first LanguageLength characters in Supported match Language
+ //
+ if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
+ VA_END (Args);
+
+ Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
+ Buffer[CompareLength] = '\0';
+ return CopyMem (Buffer, Supported, CompareLength);
+ }
+ }
+
+ if (Iso639Language) {
+ //
+ // If ISO 639 mode, then each language can only be tested once
+ //
+ LanguageLength = 0;
+ } else {
+ //
+ // If RFC 4646 mode, then trim Language from the right to the next '-' character
+ //
+ for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
+ }
+ }
+ }
+ VA_END (Args);
+
+ //
+ // No matches were found
+ //
+ return NULL;
+}
+
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param[in] Marker VA_LIST style variable argument list.
+ The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistencyInternal (
+ IN UINT32 Attributes,
+ IN VA_LIST Marker
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ VARIABLE_ENTRY_CONSISTENCY *VariableEntry;
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+ UINTN TotalNeededSize;
+ UINTN OriginalVarSize;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ VARIABLE_HEADER *NextVariable;
+ UINTN VarNameSize;
+ UINTN VarDataSize;
+
+ //
+ // Non-Volatile related.
+ //
+ VariableStoreHeader = mNvVariableCache;
+
+ Status = VariableServiceQueryVariableInfoInternal (
+ Attributes,
+ &MaximumVariableStorageSize,
+ &RemainingVariableStorageSize,
+ &MaximumVariableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ TotalNeededSize = 0;
+ Args = Marker;
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ while (VariableEntry != NULL) {
+ //
+ // Calculate variable total size.
+ //
+ VarNameSize = StrSize (VariableEntry->Name);
+ VarNameSize += GET_PAD_SIZE (VarNameSize);
+ VarDataSize = VariableEntry->VariableSize;
+ VarDataSize += GET_PAD_SIZE (VarDataSize);
+ VariableEntry->VariableSize = HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize + VarDataSize);
+
+ TotalNeededSize += VariableEntry->VariableSize;
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ }
+
+ if (RemainingVariableStorageSize >= TotalNeededSize) {
+ //
+ // Already have enough space.
+ //
+ return TRUE;
+ } else if (AtRuntime ()) {
+ //
+ // At runtime, no reclaim.
+ // The original variable space of Variables can't be reused.
+ //
+ return FALSE;
+ }
+
+ Args = Marker;
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ while (VariableEntry != NULL) {
+ //
+ // Check if Variable[Index] has been present and get its size.
+ //
+ OriginalVarSize = 0;
+ VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
+ VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
+ Status = FindVariableEx (
+ VariableEntry->Name,
+ VariableEntry->Guid,
+ FALSE,
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get size of Variable[Index].
+ //
+ NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr);
+ OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;
+ //
+ // Add the original size of Variable[Index] to remaining variable storage size.
+ //
+ RemainingVariableStorageSize += OriginalVarSize;
+ }
+ if (VariableEntry->VariableSize > RemainingVariableStorageSize) {
+ //
+ // No enough space for Variable[Index].
+ //
+ return FALSE;
+ }
+ //
+ // Sub the (new) size of Variable[Index] from remaining variable storage size.
+ //
+ RemainingVariableStorageSize -= VariableEntry->VariableSize;
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistency (
+ IN UINT32 Attributes,
+ ...
+ )
+{
+ VA_LIST Marker;
+ BOOLEAN Return;
+
+ VA_START (Marker, Attributes);
+
+ Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
+
+ VA_END (Marker);
+
+ return Return;
+}
+
+
+/**
+ Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
+
+ When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
+
+ According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
+ and are read-only. Therefore, in variable driver, only store the original value for other use.
+
+ @param[in] VariableName Name of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+
+ @retval EFI_SUCCESS The update operation is successful or ignored.
+ @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
+ @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
+ @retval Others Other errors happened during the update operation.
+
+**/
+EFI_STATUS
+AutoUpdateLangVariable (
+ IN CHAR16 *VariableName,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT32 Attributes;
+ VARIABLE_POINTER_TRACK Variable;
+ BOOLEAN SetLanguageCodes;
+ VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];
+ CHAR8 *BestLang;
+ CHAR8 *BestPlatformLang;
+
+ BestLang = NULL;
+ BestPlatformLang = NULL;
+
+ //
+ // Don't do updates for delete operation
+ //
+ if (DataSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ SetLanguageCodes = FALSE;
+
+ if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {
+ //
+ // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
+ //
+ if (AtRuntime ()) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ SetLanguageCodes = TRUE;
+
+ //
+ // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
+ // Therefore, in variable driver, only store the original value for other use.
+ //
+ if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
+ FreePool (mVariableModuleGlobal->PlatformLangCodes);
+ }
+ mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
+ ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
+
+ //
+ // PlatformLang holds a single language from PlatformLangCodes,
+ // so the size of PlatformLangCodes is enough for the PlatformLang.
+ //
+ if (mVariableModuleGlobal->PlatformLang != NULL) {
+ FreePool (mVariableModuleGlobal->PlatformLang);
+ }
+ mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
+ ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
+
+ } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {
+ //
+ // LangCodes is a volatile variable, so it can not be updated at runtime.
+ //
+ if (AtRuntime ()) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ SetLanguageCodes = TRUE;
+
+ //
+ // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
+ // Therefore, in variable driver, only store the original value for other use.
+ //
+ if (mVariableModuleGlobal->LangCodes != NULL) {
+ FreePool (mVariableModuleGlobal->LangCodes);
+ }
+ mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
+ ASSERT (mVariableModuleGlobal->LangCodes != NULL);
+ }
+
+ if (SetLanguageCodes
+ && (mVariableModuleGlobal->PlatformLangCodes != NULL)
+ && (mVariableModuleGlobal->LangCodes != NULL)) {
+ //
+ // Update Lang if PlatformLang is already set
+ // Update PlatformLang if Lang is already set
+ //
+ Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update Lang
+ //
+ VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;
+ Data = GetVariableDataPtr (Variable.CurrPtr);
+ DataSize = DataSizeOfVariable (Variable.CurrPtr);
+ } else {
+ Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update PlatformLang
+ //
+ VariableName = EFI_LANG_VARIABLE_NAME;
+ Data = GetVariableDataPtr (Variable.CurrPtr);
+ DataSize = DataSizeOfVariable (Variable.CurrPtr);
+ } else {
+ //
+ // Neither PlatformLang nor Lang is set, directly return
+ //
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
+ //
+ Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+
+ if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {
+ //
+ // Update Lang when PlatformLangCodes/LangCodes were set.
+ //
+ if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
+ //
+ // When setting PlatformLang, firstly get most matched language string from supported language codes.
+ //
+ BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
+ if (BestPlatformLang != NULL) {
+ //
+ // Get the corresponding index in language codes.
+ //
+ Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
+
+ //
+ // Get the corresponding ISO639 language tag according to RFC4646 language tag.
+ //
+ BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
+
+ //
+ // Check the variable space for both Lang and PlatformLang variable.
+ //
+ VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
+ VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;
+
+ VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);
+ VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
+ if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+ //
+ // No enough variable space to set both Lang and PlatformLang successfully.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
+ //
+ FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+
+ Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,
+ ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);
+ }
+
+ DEBUG ((EFI_D_INFO, " Variable Driver: Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));
+ }
+ }
+
+ } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {
+ //
+ // Update PlatformLang when PlatformLangCodes/LangCodes were set.
+ //
+ if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
+ //
+ // When setting Lang, firstly get most matched language string from supported language codes.
+ //
+ BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
+ if (BestLang != NULL) {
+ //
+ // Get the corresponding index in language codes.
+ //
+ Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
+
+ //
+ // Get the corresponding RFC4646 language tag according to ISO639 language tag.
+ //
+ BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
+
+ if (BestPlatformLang == NULL) {
+ ASSERT (BestPlatformLang != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check the variable space for both PlatformLang and Lang variable.
+ //
+ VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);
+ VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
+
+ VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
+ VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
+ VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;
+ if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+ //
+ // No enough variable space to set both PlatformLang and Lang successfully.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
+ //
+ FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+
+ Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,
+ AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);
+ }
+
+ DEBUG ((EFI_D_INFO, " Variable Driver: Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));
+ }
+ }
+ }
+
+ if (SetLanguageCodes) {
+ //
+ // Continue to set PlatformLangCodes or LangCodes.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
+
+
+/**
+ Compare two EFI_TIME data.
+
+ @param[in] FirstTime A pointer to the first EFI_TIME data.
+ @param[in] SecondTime A pointer to the second EFI_TIME data.
+
+ @retval TRUE The FirstTime is not later than the SecondTime.
+ @retval FALSE The FirstTime is later than the SecondTime.
+
+**/
+BOOLEAN
+VariableCompareTimeStampInternal (
+ IN EFI_TIME *FirstTime,
+ IN EFI_TIME *SecondTime
+ )
+{
+ if (FirstTime->Year != SecondTime->Year) {
+ return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
+ } else if (FirstTime->Month != SecondTime->Month) {
+ return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
+ } else if (FirstTime->Day != SecondTime->Day) {
+ return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
+ } else if (FirstTime->Hour != SecondTime->Hour) {
+ return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
+ } else if (FirstTime->Minute != SecondTime->Minute) {
+ return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
+ }
+
+ return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
+}
+
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
+ @param[in] TimeStamp Value of associated TimeStamp.
+ @param[in] OnlyUpdateNvCache TRUE if only the NV cache should be written to, not the VARIABLE_STORAGE_PROTOCOLs
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariableInternal (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
+ IN EFI_TIME *TimeStamp OPTIONAL,
+ IN BOOLEAN OnlyUpdateNvCache
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_HEADER *NextVariable;
+ UINTN ScratchSize;
+ UINTN MaxDataSize;
+ UINTN VarNameOffset;
+ UINTN VarDataOffset;
+ UINTN VarNameSize;
+ UINTN VarSize;
+ BOOLEAN Volatile;
+ UINT8 State;
+ VARIABLE_POINTER_TRACK *Variable;
+ VARIABLE_HEADER *LastVariable;
+ VARIABLE_HEADER *OldVariable;
+ UINTN OldVariableSize;
+ UINTN CacheOffset;
+ UINT8 *BufferForMerge;
+ UINTN MergedBufSize;
+ BOOLEAN DataReady;
+ UINTN DataOffset;
+ BOOLEAN IsCommonVariable;
+ BOOLEAN IsCommonUserVariable;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+ EFI_PHYSICAL_ADDRESS HobVariableBase;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+
+ if (!mVariableModuleGlobal->WriteServiceReady) {
+ //
+ // NV Variable writes are not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
+ //
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ //
+ DEBUG ((EFI_D_ERROR, " Variable Driver: Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
+ return EFI_NOT_AVAILABLE_YET;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ //
+ // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
+ // The authenticated variable perhaps is not initialized, just return here.
+ //
+ DEBUG ((EFI_D_ERROR, " Variable Driver: Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "+-+-> Variable Driver: UpdateVariable.\n Variable Name: %s.\n Guid: %g.\n", VariableName, VendorGuid));
+
+ //
+ // Check if CacheVariable points to the variable in variable HOB.
+ // If yes, let CacheVariable points to the variable in NV variable cache.
+ //
+ if ((CacheVariable->CurrPtr != NULL) &&
+ (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
+ (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase))
+ ) {
+ HobVariableBase = mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+ Status = FindVariable (VariableName, VendorGuid, CacheVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = HobVariableBase;
+ if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) {
+ //
+ // There is no matched variable in NV variable cache.
+ //
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // It is to delete variable,
+ // go to delete this variable in variable HOB and
+ // try to flush other variables from HOB to flash.
+ //
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Variable = CacheVariable;
+
+ //
+ // Tricky part: Use scratch data area at the end of volatile variable store
+ // as a temporary storage.
+ //
+ NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
+ ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
+ SetMem (NextVariable, ScratchSize, 0xff);
+ DataReady = FALSE;
+
+ if (Variable->CurrPtr != NULL) {
+ DEBUG ((DEBUG_INFO, " Variable Driver: Updating an existing variable (found in the cache).\n"));
+ //
+ // Update/Delete existing variable.
+ //
+ if (AtRuntime ()) {
+ //
+ // If AtRuntime and the variable is Volatile and Runtime Access,
+ // the volatile is ReadOnly, and SetVariable should be aborted and
+ // return EFI_WRITE_PROTECTED.
+ //
+ if (Variable->Volatile) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+ //
+ // Only variable that have NV attributes can be updated/deleted in Runtime.
+ //
+ if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Only variable that have RT attributes can be updated/deleted in Runtime.
+ //
+ if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ //
+ // Setting a data variable with no access, or zero DataSize attributes
+ // causes it to be deleted.
+ // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
+ // not delete the variable.
+ //
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) ||
+ ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
+ DEBUG ((DEBUG_INFO, " Variable Driver: Variable is being deleted.\n"));
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ //
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ Variable->InDeletedTransitionPtr->State &= VAR_DELETED;
+ }
+ Variable->CurrPtr->State &= VAR_DELETED;
+ Status = EFI_SUCCESS;
+ if (!Variable->Volatile && !OnlyUpdateNvCache) {
+ DEBUG ((DEBUG_INFO, " Variable Driver: Variable is being deleted from NV storage.\n"));
+ //
+ // Delete the variable from the NV storage
+ //
+ Status = GetVariableStorageProtocol (
+ VariableName,
+ VendorGuid,
+ &VariableStorageProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ if (VariableStorageProtocol == NULL) {
+ ASSERT (VariableStorageProtocol != NULL);
+ return EFI_NOT_FOUND;
+ }
+ Status = VariableStorageProtocol->SetVariable (
+ VariableStorageProtocol,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ 0,
+ NULL,
+ AtRuntime (),
+ 0,
+ 0,
+ TimeStamp
+ );
+ DEBUG ((DEBUG_INFO, " Variable Driver: Value returned from storage protocol = %r.\n", Status));
+ }
+ OldVariable = GetNextVariablePtr (Variable->CurrPtr);
+ OldVariableSize = (UINTN) OldVariable - (UINTN) Variable->CurrPtr;
+ if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->HwErrVariableTotalSize -= OldVariableSize;
+ } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->CommonVariableTotalSize -= OldVariableSize;
+ if (IsUserVariable (Variable->CurrPtr)) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize -= OldVariableSize;
+ }
+ }
+ }
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ goto Done;
+ }
+ //
+ // If the variable is marked valid, and the same data has been passed in,
+ // then return to the caller immediately.
+ //
+ if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&
+ (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&
+ ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
+ (TimeStamp == NULL)) {
+ //
+ // Variable content unchanged and no need to update timestamp, just return.
+ //
+ UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else if ((Variable->CurrPtr->State == VAR_ADDED) ||
+ (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
+
+ //
+ // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
+ //
+ if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
+ //
+ // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
+ // From DataOffset of NextVariable is to save the existing variable data.
+ //
+ DataOffset = GetVariableDataOffset (Variable->CurrPtr);
+ BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);
+ CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), DataSizeOfVariable (Variable->CurrPtr));
+
+ //
+ // Set Max Common/Auth Variable Data Size as default MaxDataSize.
+ // Max Harware error record variable data size is different from common/auth variable.
+ //
+ if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
+ } else {
+ MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
+ }
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
+ }
+
+ if (DataSizeOfVariable (Variable->CurrPtr) + DataSize > MaxDataSize) {
+ //
+ // Existing data size + new data size exceed maximum variable size limitation.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Append the new data to the end of existing data.
+ //
+ CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (Variable->CurrPtr)), Data, DataSize);
+ MergedBufSize = DataSizeOfVariable (Variable->CurrPtr) + DataSize;
+
+ //
+ // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
+ //
+ Data = BufferForMerge;
+ DataSize = MergedBufSize;
+ DataReady = TRUE;
+ }
+
+ //
+ // Mark the old variable as in delete transition.
+ //
+ Variable->CurrPtr->State &= VAR_IN_DELETED_TRANSITION;
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, " Variable Driver: New variable being written.\n"));
+ //
+ // Not found existing variable. Create a new variable.
+ //
+
+ if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Make sure we are trying to create a new variable.
+ // Setting a data variable with zero DataSize or no access attributes means to delete it.
+ //
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Only variable have NV|RT attribute can be created in Runtime.
+ //
+ if (AtRuntime () &&
+ (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ //
+ // Function part - create a new variable and copy the data.
+ // Both update a variable and create a variable will come here.
+ //
+ NextVariable->StartId = VARIABLE_DATA;
+ //
+ // NextVariable->State = VAR_ADDED;
+ //
+ NextVariable->Reserved = 0;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) NextVariable;
+ AuthVariable->PubKeyIndex = KeyIndex;
+ AuthVariable->MonotonicCount = MonotonicCount;
+ ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
+
+ if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
+ (TimeStamp != NULL)) {
+ if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
+ CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ } else {
+ //
+ // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
+ // when the new TimeStamp value is later than the current timestamp associated
+ // with the variable, we need associate the new timestamp with the updated value.
+ //
+ if (Variable->CurrPtr != NULL) {
+ if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) Variable->CurrPtr)->TimeStamp), TimeStamp)) {
+ CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
+ // Attributes bitmask parameter of a GetVariable() call.
+ //
+ NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
+
+ VarNameOffset = GetVariableHeaderSize ();
+ VarNameSize = StrSize (VariableName);
+ CopyMem (
+ (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
+ VariableName,
+ VarNameSize
+ );
+ VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
+
+ //
+ // If DataReady is TRUE, it means the variable data has been saved into
+ // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
+ //
+ if (!DataReady) {
+ CopyMem (
+ (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
+ Data,
+ DataSize
+ );
+ }
+
+ CopyMem (GetVendorGuidPtr (NextVariable), VendorGuid, sizeof (EFI_GUID));
+ //
+ // There will be pad bytes after Data, the NextVariable->NameSize and
+ // NextVariable->DataSize should not include pad size so that variable
+ // service can get actual size in GetVariable.
+ //
+ SetNameSizeOfVariable (NextVariable, VarNameSize);
+ SetDataSizeOfVariable (NextVariable, DataSize);
+
+ //
+ // The actual size of the variable that stores in storage should
+ // include pad size.
+ //
+ VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Create a nonvolatile variable.
+ //
+ Volatile = FALSE;
+
+ IsCommonVariable = FALSE;
+ IsCommonUserVariable = FALSE;
+ LastVariable = GetStartPointer (mNvVariableCache);
+ while (IsValidVariableHeader (LastVariable, GetEndPointer (mNvVariableCache))) {
+ LastVariable = GetNextVariablePtr (LastVariable);
+ }
+ CacheOffset = (UINTN) LastVariable - (UINTN) mNvVariableCache;
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
+ IsCommonVariable = TRUE;
+ IsCommonUserVariable = IsUserVariable (NextVariable);
+ }
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
+ && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
+ || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))
+ || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))
+ || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace))
+ || (UINT32) (VarSize + CacheOffset) > mNvVariableCache->Size) {
+ if (AtRuntime ()) {
+ if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) mNvVariableCache,
+ &CacheOffset,
+ FALSE,
+ Variable,
+ NextVariable,
+ HEADER_ALIGN (VarSize)
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The new variable has been integrated successfully during reclaiming.
+ //
+ if (Variable->CurrPtr != NULL) {
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
+ CacheVariable->InDeletedTransitionPtr = NULL;
+ }
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE);
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ } else {
+ if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {
+ RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
+ }
+ }
+ goto Done;
+ }
+ //
+ // Write the variable to NV
+ //
+ if (!OnlyUpdateNvCache) {
+ Status = GetVariableStorageProtocol (
+ VariableName,
+ VendorGuid,
+ &VariableStorageProtocol
+ );
+ if (EFI_ERROR (Status) || VariableStorageProtocol == NULL) {
+ goto Done;
+ }
+ Status = VariableStorageProtocol->SetVariable (
+ VariableStorageProtocol,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data,
+ AtRuntime (),
+ KeyIndex,
+ MonotonicCount,
+ TimeStamp
+ );
+ DEBUG ((DEBUG_INFO, " Variable Driver: Variable was written to NV via the storage protocol. Status = %r.\n", Status));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
+ } else {
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
+ if (IsCommonUserVariable) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
+ }
+ }
+ }
+ //
+ // Update the NV Cache
+ //
+ NextVariable->State = VAR_ADDED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE,
+ TRUE,
+ CacheOffset,
+ (UINT32) VarSize,
+ (UINT8 *) NextVariable
+ );
+ DEBUG ((DEBUG_INFO, " Variable Driver: Wrote the variable to the NV cache in UpdateVariable().\n"));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ } else {
+ //
+ // Create a volatile variable.
+ //
+ Volatile = TRUE;
+
+ DEBUG ((DEBUG_INFO, " Variable Driver: Creating a volatile variable.\n"));
+
+ if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
+ //
+ // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
+ //
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
+ &mVariableModuleGlobal->VolatileLastVariableOffset,
+ TRUE,
+ Variable,
+ NextVariable,
+ HEADER_ALIGN (VarSize)
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The new variable has been integrated successfully during reclaiming.
+ //
+ if (Variable->CurrPtr != NULL) {
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *) ((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
+ CacheVariable->InDeletedTransitionPtr = NULL;
+ }
+ UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE);
+ }
+ goto Done;
+ }
+
+ NextVariable->State = VAR_ADDED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ TRUE,
+ TRUE,
+ mVariableModuleGlobal->VolatileLastVariableOffset,
+ (UINT32) VarSize,
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
+ }
+
+ //
+ // Mark the old variable as deleted.
+ //
+ if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
+ //
+ // Reduce the current NV storage usage counts by the old variable's size
+ //
+ if (!OnlyUpdateNvCache) {
+ OldVariable = GetNextVariablePtr (Variable->CurrPtr);
+ OldVariableSize = (UINTN) OldVariable - (UINTN) Variable->CurrPtr;
+ if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->HwErrVariableTotalSize -= OldVariableSize;
+ } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ mVariableModuleGlobal->CommonVariableTotalSize -= OldVariableSize;
+ if (IsUserVariable (Variable->CurrPtr)) {
+ mVariableModuleGlobal->CommonUserVariableTotalSize -= OldVariableSize;
+ }
+ }
+ }
+ if (Variable->InDeletedTransitionPtr != NULL) {
+ //
+ // Both ADDED and IN_DELETED_TRANSITION old variable are present,
+ // set IN_DELETED_TRANSITION one to DELETED state first.
+ //
+ State = Variable->InDeletedTransitionPtr->State;
+ State &= VAR_DELETED;
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ (UINTN) &Variable->InDeletedTransitionPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ State = Variable->CurrPtr->State;
+ State &= VAR_DELETED;
+
+ Status = UpdateVariableStore (
+ &mVariableModuleGlobal->VariableGlobal,
+ Variable->Volatile,
+ FALSE,
+ (UINTN) &Variable->CurrPtr->State,
+ sizeof (UINT8),
+ &State
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
+ if (!Volatile) {
+ FlushHobVariableToFlash (VariableName, VendorGuid);
+ }
+ }
+
+Done:
+ return Status;
+}
+
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
+ IN EFI_TIME *TimeStamp OPTIONAL
+ )
+{
+ return UpdateVariableInternal (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ CacheVariable,
+ TimeStamp,
+ mForceVolatileVariable
+ );
+}
+
+/**
+ Finds the first variable from the first NV storage.
+
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found.
+
+**/
+EFI_STATUS
+FindFirstNvVariable (
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN IgnoreRtCheck
+ )
+{
+ VARIABLE_STORAGE_PROTOCOL *VariableStorage;
+ UINTN VariableNameBufferSize;
+ UINT32 VariableAttributes;
+ EFI_GUID TempGuid;
+ EFI_STATUS Status;
+
+ if (mVariableModuleGlobal->VariableGlobal.VariableStoresCount <= 0) {
+ return EFI_NOT_FOUND;
+ }
+ VariableNameBufferSize = sizeof (mVariableNameBuffer);
+ ZeroMem ((VOID *) &mVariableNameBuffer[0], VariableNameBufferSize);
+ ZeroMem ((VOID *) &TempGuid, sizeof (EFI_GUID));
+ VariableStorage = mVariableModuleGlobal->VariableGlobal.VariableStores[0];
+ Status = VariableStorage->GetNextVariableName (
+ VariableStorage,
+ &VariableNameBufferSize,
+ &mVariableNameBuffer[0],
+ &TempGuid,
+ &VariableAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "VariableStorageProtocol->GetNextVariableName status %r\n", Status));
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+ return Status;
+ }
+ return FindVariable (&mVariableNameBuffer[0], &TempGuid, PtrTrack, Global, IgnoreRtCheck);
+}
+
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+ If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
+ at runtime when searching existing variable, only VariableName and VendorGuid are compared.
+ Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found.
+
+**/
+EFI_STATUS
+FindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN IgnoreRtCheck
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ EFI_GUID VariableStorageId;
+ EFI_GUID InstanceGuid;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+ VARIABLE_STORAGE_PROTOCOL *CorrectVariableStorageProtocol;
+ UINTN Index;
+ VARIABLE_STORE_TYPE Type;
+ EFI_TIME TimeStamp;
+ UINT64 MonotonicCount;
+ UINTN DataSize;
+ UINT32 Attributes;
+ UINT32 KeyIndex;
+ BOOLEAN FailedRtCheck;
+
+ FailedRtCheck = FALSE;
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile Cache.
+ // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
+ // make use of this mapping to implement search algorithm.
+ //
+ VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;
+ VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;
+ VariableStoreHeader[VariableStoreTypeNvCache] = mNvVariableCache;
+
+ DEBUG ((DEBUG_INFO, "+-+-> Variable Driver: FindVariable.\n Variable Name: %s.\n Guid: %g.\n", VariableName, VendorGuid));
+
+ //
+ // Find the variable by walk through HOB, volatile and non-volatile variable store.
+ //
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
+ if (VariableStoreHeader[Type] == NULL) {
+ continue;
+ }
+
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);
+
+ Status = FindVariableEx (VariableName, VendorGuid, TRUE, PtrTrack);
+ if (!EFI_ERROR (Status)) {
+ FailedRtCheck = FALSE;
+ if (!IgnoreRtCheck &&
+ ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) &&
+ AtRuntime ()) {
+ FailedRtCheck = TRUE;
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "Variable Driver: Found the variable in store type %d before going to protocols.\n", Type));
+ return Status;
+ }
+ }
+ if (FailedRtCheck) {
+ PtrTrack->CurrPtr = NULL;
+ PtrTrack->InDeletedTransitionPtr = NULL;
+ return EFI_NOT_FOUND;
+ }
+ if (mForceVolatileVariable) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If VariableName is an empty string get the first variable from the first NV storage
+ //
+ if (VariableName[0] == 0) {
+ return FindFirstNvVariable (PtrTrack, Global, IgnoreRtCheck);
+ }
+ //
+ // Search the VARIABLE_STORAGE_PROTOCOLs
+ // first, try the protocol instance which the VariableStorageSelectorLib suggests
+ //
+ ASSERT (mVariableDataBuffer != NULL);
+ if (mVariableDataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CorrectVariableStorageProtocol = NULL;
+ ZeroMem ((VOID *) &VariableStorageId, sizeof (EFI_GUID));
+ Status = GetVariableStorageId (VariableName, VendorGuid, TRUE, &VariableStorageId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ ZeroMem ((VOID *) &InstanceGuid, sizeof (EFI_GUID));
+ Status = VariableStorageProtocol->GetId (&InstanceGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CompareGuid (&VariableStorageId, &InstanceGuid)) {
+ CorrectVariableStorageProtocol = VariableStorageProtocol;
+ DataSize = mVariableModuleGlobal->ScratchBufferSize;
+ ZeroMem (mVariableDataBuffer, DataSize);
+ Status = VariableStorageProtocol->GetAuthenticatedVariable (
+ VariableStorageProtocol,
+ VariableName,
+ VendorGuid,
+ &Attributes,
+ &DataSize,
+ mVariableDataBuffer,
+ &KeyIndex,
+ &MonotonicCount,
+ &TimeStamp
+ );
+ DEBUG ((DEBUG_INFO, " Variable Driver: Variable storage protocol GetAuthenticatedVariable status = %r.\n", Status));
+
+ if (!EFI_ERROR (Status)) {
+ goto UpdateNvCache;
+ }
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ break;
+ }
+ }
+ //
+ // As a fallback, try searching the remaining VARIABLE_STORAGE_PROTOCOLs even
+ // though the variable shouldn't actually be stored in there
+ //
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ ZeroMem ((VOID *) &InstanceGuid, sizeof (EFI_GUID));
+ Status = VariableStorageProtocol->GetId (&InstanceGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (!CompareGuid (&VariableStorageId, &VariableStorageId)) {
+ DataSize = mVariableModuleGlobal->ScratchBufferSize;
+ ZeroMem (mVariableDataBuffer, DataSize);
+ Status = VariableStorageProtocol->GetAuthenticatedVariable (
+ VariableStorageProtocol,
+ VariableName,
+ VendorGuid,
+ &Attributes,
+ &DataSize,
+ mVariableDataBuffer,
+ &KeyIndex,
+ &MonotonicCount,
+ &TimeStamp
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The variable isn't being stored in the correct VariableStorage,
+ // attempt to move it to the correct VariableStorage
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "Variable %s is not being stored in the correct NV storage!\n",
+ VariableName
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ "Expected StorageId = %g, Actual StorageId = %g\n",
+ &VariableStorageId,
+ &VariableStorageId
+ ));
+ if (CorrectVariableStorageProtocol != NULL) {
+ if (CorrectVariableStorageProtocol->WriteServiceIsReady (
+ CorrectVariableStorageProtocol) &&
+ VariableStorageProtocol->WriteServiceIsReady (
+ VariableStorageProtocol)) {
+ Status2 = CorrectVariableStorageProtocol->SetVariable (
+ CorrectVariableStorageProtocol,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ mVariableDataBuffer,
+ AtRuntime (),
+ KeyIndex,
+ MonotonicCount,
+ &TimeStamp
+ );
+ if (EFI_ERROR (Status2)) {
+ DEBUG ((DEBUG_INFO, "Failed to copy variable to correct VariableStorage!\n"));
+ goto UpdateNvCache;
+ }
+ //
+ // Delete the redundant copy that is incorrectly stored
+ //
+ Status2 = VariableStorageProtocol->SetVariable (
+ VariableStorageProtocol,
+ VariableName,
+ VendorGuid,
+ Attributes,
+ 0,
+ NULL,
+ AtRuntime (),
+ 0,
+ 0,
+ &TimeStamp
+ );
+ if (EFI_ERROR (Status2)) {
+ DEBUG ((DEBUG_INFO, " Variable Driver: Failed to delete redundant copy of variable in the incorrect VariableStorage!\n"));
+ }
+ DEBUG ((DEBUG_INFO, " Variable Driver: Variable has been moved to the correct VariableStorage.\n"));
+ } else {
+ DEBUG ((DEBUG_INFO, " Variable Driver: VariableStorage is not ready to write, unable to move variable.\n"));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, " Variable Driver: Expected VariableStorage does not exist!\n"));
+ }
+ goto UpdateNvCache;
+ }
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ }
+ }
+ return EFI_NOT_FOUND;
+UpdateNvCache:
+ DEBUG ((DEBUG_INFO, " Variable Driver: Updating the cache for this variable.\n"));
+
+ PtrTrack->CurrPtr = NULL;
+ PtrTrack->InDeletedTransitionPtr = NULL;
+ PtrTrack->StartPtr = GetStartPointer (mNvVariableCache);
+ PtrTrack->EndPtr = GetEndPointer (mNvVariableCache);
+ PtrTrack->Volatile = FALSE;
+ Status = UpdateVariableInternal (
+ VariableName,
+ VendorGuid,
+ mVariableDataBuffer,
+ DataSize,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ PtrTrack,
+ &TimeStamp,
+ TRUE
+ );
+ DEBUG ((DEBUG_INFO, " Variable Driver: UpdateVariable status = %r.\n", Status));
+ if (!EFI_ERROR (Status)) {
+ PtrTrack->StartPtr = GetStartPointer (mNvVariableCache);
+ PtrTrack->EndPtr = GetEndPointer (mNvVariableCache);
+ PtrTrack->Volatile = FALSE;
+ Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);
+ }
+ return Status;
+}
+
+
+/**
+ This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize is external input.
+ This function will do basic validation, before parse the data.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarDataSize;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data size
+ //
+ VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
+ ASSERT (VarDataSize != 0);
+
+ if (*DataSize >= VarDataSize) {
+ if (Data == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
+ if (Attributes != NULL) {
+ *Attributes = Variable.CurrPtr->Attributes;
+ }
+
+ *DataSize = VarDataSize;
+ UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ *DataSize = VarDataSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ return Status;
+}
+
+
+/**
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Variable Vendor Guid.
+ @param[out] VariablePtr Pointer to variable header address.
+
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextInMemoryVariableInternal (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_HEADER **VariablePtr,
+ OUT BOOLEAN *CurrentVariableInMemory
+ )
+{
+ VARIABLE_STORE_TYPE Type;
+ VARIABLE_STORE_TYPE MaxSearch;
+ VARIABLE_POINTER_TRACK Variable;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+
+ *CurrentVariableInMemory = FALSE;
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 0: Volatile, 1: HOB
+ // The index and attributes mapping must be kept in this order to implement
+ // the variable enumeration search algorithm.
+ //
+ VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
+ VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ VariableStoreHeader[VariableStoreTypeNvCache] = mNvVariableCache;
+ if (mForceVolatileVariable) {
+ MaxSearch = VariableStoreTypeNvCache;
+ } else {
+ MaxSearch = VariableStoreTypeHob;
+ }
+
+ //
+ // Find the current variable by walk through HOB and volatile variable store.
+ //
+ Variable.CurrPtr = NULL;
+ Status = EFI_NOT_FOUND;
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type <= MaxSearch; Type++) {
+ if (VariableStoreHeader[Type] == NULL) {
+ continue;
+ }
+
+ Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ Variable.Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, &Variable);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
+ goto Done;
+ }
+ *CurrentVariableInMemory = TRUE;
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not NULL, get next variable.
+ //
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ }
+
+ while (TRUE) {
+ //
+ // Switch from Volatile to HOB
+ //
+ while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
+ //
+ // Find current storage index
+ //
+ for (Type = (VARIABLE_STORE_TYPE) 0; Type <= VariableStoreTypeHob; Type++) {
+ if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
+ break;
+ }
+ }
+ ASSERT (Type <= VariableStoreTypeHob);
+ //
+ // Switch to next storage
+ //
+ for (Type++; Type < VariableStoreTypeMax; Type++) {
+ if (VariableStoreHeader[Type] != NULL) {
+ break;
+ }
+ }
+ //
+ // Capture the case that
+ // 1. current storage is the last one, or
+ // 2. no further storage
+ //
+ if (Type > VariableStoreTypeHob) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
+ Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
+ Variable.CurrPtr = Variable.StartPtr;
+ }
+
+ //
+ // Variable is found
+ //
+ if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+ if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is also a same ADDED one at the same time,
+ // don't return it.
+ //
+ VariablePtrTrack.StartPtr = Variable.StartPtr;
+ VariablePtrTrack.EndPtr = Variable.EndPtr;
+ Status = FindVariableEx (
+ GetVariableNamePtr (Variable.CurrPtr),
+ GetVendorGuidPtr (Variable.CurrPtr),
+ FALSE,
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ continue;
+ }
+ }
+
+ *VariablePtr = Variable.CurrPtr;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ }
+
+Done:
+ return Status;
+}
+
+
+/**
+ Determines if a variable exists in the default HOB
+
+ @param[in] VariableName A pointer to a null-terminated string that is the variable's name.
+ @param[in] VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
+ VariableGuid and VariableName must be unique.
+
+ @retval TRUE The variable exists in the HOBs
+ @retval FALSE The variable does not exist in the HOBs
+
+**/
+BOOLEAN
+EFIAPI
+VariableExistsInHob (
+ IN CONST CHAR16 *VariableName,
+ IN CONST EFI_GUID *VariableGuid
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ EFI_STATUS Status;
+
+ Variable.CurrPtr = NULL;
+ Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ Variable.Volatile = FALSE;
+
+ Status = FindVariableEx ((CHAR16 *) VariableName, (EFI_GUID *) VariableGuid, FALSE, &Variable);
+ if ((Variable.CurrPtr != NULL) && (!EFI_ERROR (Status))) {
+ return TRUE;
+ } else {
+ if (Status == EFI_NOT_FOUND) {
+ return FALSE;
+ }
+ ASSERT_EFI_ERROR (Status);
+ return FALSE;
+ }
+}
+
+
+/**
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableInternal (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ )
+{
+ EFI_GUID VariableStorageId;
+ EFI_GUID InstanceGuid;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorage;
+ VARIABLE_HEADER *VariablePtr;
+ UINTN Index;
+ UINTN VarNameSize;
+ UINT32 VarAttributes;
+ UINTN CallerVariableNameBufferSize;
+ EFI_STATUS Status;
+ BOOLEAN SearchComplete;
+ BOOLEAN CurrentVariableInMemory;
+
+ CallerVariableNameBufferSize = *VariableNameSize;
+
+ //
+ // Check the volatile and HOB variables first
+ //
+ Status = VariableServiceGetNextInMemoryVariableInternal (
+ VariableName,
+ VariableGuid,
+ &VariablePtr,
+ &CurrentVariableInMemory
+ );
+ if (!EFI_ERROR (Status)) {
+ VarNameSize = NameSizeOfVariable (VariablePtr);
+ ASSERT (VarNameSize != 0);
+ if (VarNameSize <= *VariableNameSize) {
+ CopyMem (VariableName, GetVariableNamePtr (VariablePtr), VarNameSize);
+ CopyMem (VariableGuid, GetVendorGuidPtr (VariablePtr), sizeof (EFI_GUID));
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ return Status;
+ } else if (Status != EFI_NOT_FOUND) {
+ DEBUG ((DEBUG_INFO, "VariableServiceGetNextInMemoryVariableInternal status %r\n", Status));
+ return Status;
+ }
+
+ if (mForceVolatileVariable) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If VariableName is an empty string or we reached the end of the volatile
+ // and HOB variables, get the first variable from the first NV storage
+ //
+ if (VariableName[0] == 0 || (Status == EFI_NOT_FOUND && CurrentVariableInMemory)) {
+ if (mVariableModuleGlobal->VariableGlobal.VariableStoresCount <= 0) {
+ return EFI_NOT_FOUND;
+ }
+ ZeroMem ((VOID *) VariableName, *VariableNameSize);
+ ZeroMem ((VOID *) VariableGuid, sizeof (VariableGuid));
+ VariableStorage = mVariableModuleGlobal->VariableGlobal.VariableStores[0];
+ Status = VariableStorage->GetNextVariableName (
+ VariableStorage,
+ VariableNameSize,
+ VariableName,
+ VariableGuid,
+ &VarAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "VariableStorageProtocol->GetNextVariableName status %r\n", Status));
+ return Status;
+ } else {
+ //
+ // Don't return this variable if we are at runtime and the variable's attributes do not include
+ // the EFI_VARIABLE_RUNTIME_ACCESS flag. If this is true, advance to the next variable
+ //
+ if (((VarAttributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0) || !AtRuntime ()) {
+ return Status;
+ }
+ }
+ }
+
+ SearchComplete = FALSE;
+ while (!SearchComplete) {
+ Status = GetVariableStorageId (VariableName, VariableGuid, TRUE, &VariableStorageId);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ VarNameSize = CallerVariableNameBufferSize;
+
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorage = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ ZeroMem ((VOID *) &InstanceGuid, sizeof (EFI_GUID));
+ Status = VariableStorage->GetId (&InstanceGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CompareGuid (&VariableStorageId, &InstanceGuid)) {
+ Status = VariableStorage->GetNextVariableName (
+ VariableStorage,
+ &VarNameSize,
+ VariableName,
+ VariableGuid,
+ &VarAttributes
+ );
+ if (!EFI_ERROR (Status)) {
+ if (VariableExistsInHob (VariableName, VariableGuid)) {
+ //
+ // Don't return this variable if there is a HOB variable that overrides it
+ // advance to the next variable
+ //
+ break;
+ }
+ if (((VarAttributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
+ //
+ // Don't return this variable if we are at runtime and the variable's attributes do not include
+ // the EFI_VARIABLE_RUNTIME_ACCESS flag. If this is true, advance to the next variable
+ //
+ break;
+ }
+ goto Done;
+ } else if (Status == EFI_NOT_FOUND) {
+ //
+ // If we reached the end of the variables in the current NV storage
+ // get the first variable in the next NV storage
+ //
+ if ((Index + 1) < mVariableModuleGlobal->VariableGlobal.VariableStoresCount) {
+ VarNameSize = CallerVariableNameBufferSize;
+ VariableStorage = mVariableModuleGlobal->VariableGlobal.VariableStores[Index + 1];
+
+ ZeroMem ((VOID *) VariableGuid, sizeof (VariableGuid));
+ Status = VariableStorage->GetNextVariableName (
+ VariableStorage,
+ &VarNameSize,
+ VariableName,
+ VariableGuid,
+ &VarAttributes
+ );
+ if (!EFI_ERROR (Status)) {
+ if (VariableExistsInHob (VariableName, VariableGuid)) {
+ //
+ // Don't return this variable if there is a HOB variable that overrides it
+ // advance to the next variable
+ //
+ break;
+ }
+ if (((VarAttributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
+ //
+ // Don't return this variable if we are at runtime and the variable's attributes do not include
+ // the EFI_VARIABLE_RUNTIME_ACCESS flag. If this is true, advance to the next variable
+ //
+ break;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "VariableStorageProtocol->GetNextVariableName status %r\n", Status));
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "Variable.c: Status returned from the variable storage protocol is %r\n", Status));
+ goto Done;
+ } else {
+ // This is the last variable
+ SearchComplete = TRUE;
+ break;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "VariableStorageProtocol->GetNextVariableName status %r\n", Status));
+ return Status;
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+
+Done:
+ *VariableNameSize = VarNameSize;
+
+ if (CallerVariableNameBufferSize < VarNameSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ UINTN VariableNameBufferSize;
+ EFI_STATUS Status;
+
+ if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ VariableNameBufferSize = sizeof (mVariableNameBuffer);
+ ZeroMem ((VOID *) &mVariableNameBuffer[0], VariableNameBufferSize);
+ StrCpyS (&mVariableNameBuffer[0], VariableNameBufferSize, VariableName);
+
+ Status = VariableServiceGetNextVariableInternal (&VariableNameBufferSize, &mVariableNameBuffer[0], VendorGuid);
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+
+ if (!EFI_ERROR (Status)) {
+ if (VariableNameBufferSize > *VariableNameSize) {
+ *VariableNameSize = VariableNameBufferSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ StrCpyS (VariableName, *VariableNameSize, &mVariableNameBuffer[0]);
+ *VariableNameSize = VariableNameBufferSize;
+ }
+ }
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ return Status;
+}
+
+
+/**
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable found
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+
+ //
+ // Check input parameters.
+ //
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize != 0 && Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for the reserverd bit in the variable attributes.
+ //
+ if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that if the runtime bit is set, the boot service bit is also set.
+ //
+ if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+ //
+ // Authenticated variable writes are not supported.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ if (PcdGet32 (PcdHwErrStorageSize) == 0) {
+ //
+ // Harware error record variables are not supported on this platform.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+ // cannot both be set.
+ //
+ if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+ && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
+ if (DataSize < AUTHINFO_SIZE) {
+ //
+ // User attempted to write to a Authenticated Variable without AuthInfo.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ PayloadSize = DataSize - AUTHINFO_SIZE;
+ } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+ //
+ // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
+ //
+ if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||
+ ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||
+ ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+ } else {
+ PayloadSize = DataSize;
+ }
+
+ if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){
+ //
+ // Prevent whole variable size overflow
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The size of the VariableName, including the Unicode Null in bytes plus
+ // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
+ // bytes for HwErrRec#### variable.
+ //
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // The size of the VariableName, including the Unicode Null in bytes plus
+ // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.
+ //
+ if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ //
+ // Special Handling for MOR Lock variable.
+ //
+ Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));
+ if (Status == EFI_ALREADY_STARTED) {
+ //
+ // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
+ // Variable driver can just return SUCCESS.
+ //
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ //
+ // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
+ //
+ InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
+
+ //
+ // Check whether the input variable is already existed.
+ //
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
+ if (!EFI_ERROR (Status)) {
+ if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+ if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) {
+ //
+ // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
+ // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
+ // 1. No access attributes specified
+ // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
+ //
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_INFO, " Variable Driver: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
+ goto Done;
+ }
+ }
+
+ Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
+ //
+ // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
+ //
+ Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
+ //
+ goto Done;
+ }
+ }
+
+ if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+ Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
+ } else {
+ Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
+ }
+
+Done:
+ InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ if (!AtRuntime ()) {
+ if (!EFI_ERROR (Status)) {
+ SecureBootHook (
+ VariableName,
+ VendorGuid
+ );
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_SUCCESS Query successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfoInternal (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *NextVariable;
+ UINT64 VariableSize;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT64 CommonVariableTotalSize;
+ UINT64 HwErrVariableTotalSize;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+ UINTN Index;
+ UINT32 VariableStoreSize;
+ UINT32 VspCommonVariablesTotalSize;
+ UINT32 VspHwErrVariablesTotalSize;
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+
+ CommonVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ //
+ // Query is Volatile related.
+ //
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+ } else {
+ //
+ // Query is Non-Volatile related.
+ //
+ VariableStoreHeader = mNvVariableCache;
+ }
+
+ //
+ // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
+ // with the storage size (excluding the storage header size).
+ //
+ *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
+
+ //
+ // Harware error record variable needs larger size.
+ //
+ if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
+ *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ();
+ } else {
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ if (AtRuntime ()) {
+ *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
+ } else {
+ *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
+ }
+ }
+
+ //
+ // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.
+ //
+ if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();
+ } else {
+ *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ();
+ }
+ }
+
+ //
+ // Point to the starting address of the variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeader);
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ //
+ // For Volatile related, walk through the variable store.
+ //
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
+ NextVariable = GetNextVariablePtr (Variable);
+ VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
+
+ if (AtRuntime ()) {
+ //
+ // We don't take the state of the variables in mind
+ // when calculating RemainingVariableStorageSize,
+ // since the space occupied by variables not marked with
+ // VAR_ADDED is not allowed to be reclaimed in Runtime.
+ //
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ } else {
+ //
+ // Only care about Variables with State VAR_ADDED, because
+ // the space not marked as VAR_ADDED is reclaimable now.
+ //
+ if (Variable->State == VAR_ADDED) {
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If it is a IN_DELETED_TRANSITION variable,
+ // and there is not also a same ADDED one at the same time,
+ // this IN_DELETED_TRANSITION variable is valid.
+ //
+ VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
+ VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
+ Status = FindVariableEx (
+ GetVariableNamePtr (Variable),
+ GetVendorGuidPtr (Variable),
+ FALSE,
+ &VariablePtrTrack
+ );
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ }
+
+ //
+ // Go to the next one.
+ //
+ Variable = NextVariable;
+ }
+ } else {
+ //
+ // For Non Volatile related, call GetStorageUsage() on the VARIABLE_STORAGE_PROTOCOLs
+ //
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ Status = VariableStorageProtocol->GetStorageUsage (
+ VariableStorageProtocol,
+ AtRuntime (),
+ &VariableStoreSize,
+ &VspCommonVariablesTotalSize,
+ &VspHwErrVariablesTotalSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CommonVariableTotalSize += VspCommonVariablesTotalSize;
+ HwErrVariableTotalSize += VspHwErrVariablesTotalSize;
+ }
+ }
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
+ } else {
+ if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
+ *RemainingVariableStorageSize = 0;
+ } else {
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
+ }
+ }
+
+ if (*RemainingVariableStorageSize < GetVariableHeaderSize ()) {
+ *MaximumVariableSize = 0;
+ } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize ()) < *MaximumVariableSize) {
+ *MaximumVariableSize = *RemainingVariableStorageSize - GetVariableHeaderSize ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @return EFI_SUCCESS Query successfully.
+ @return EFI_UNSUPPORTED The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ EFI_STATUS Status;
+
+ if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
+ //
+ // Make sure the Attributes combination is supported by the platform.
+ //
+ return EFI_UNSUPPORTED;
+ } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+ //
+ // Make sure if runtime bit is set, boot service bit is set also.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
+ //
+ // Make sure RT Attribute is set if we are in Runtime phase.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ //
+ // Make sure Hw Attribute is set with NV.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
+ if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
+ //
+ // Not support authenticated variable write.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ if (PcdGet32 (PcdHwErrStorageSize) == 0) {
+ //
+ // Not support harware error record variable variable.
+ //
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ Status = VariableServiceQueryVariableInfoInternal (
+ Attributes,
+ MaximumVariableStorageSize,
+ RemainingVariableStorageSize,
+ MaximumVariableSize
+ );
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ return Status;
+}
+
+
+/**
+ This function reclaims variable storage if free size is below the threshold.
+
+ Caution: This function may be invoked at SMM mode.
+ Care must be taken to make sure not security issue.
+
+**/
+VOID
+ReclaimForOS(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN RemainingCommonRuntimeVariableSpace;
+ UINTN RemainingHwErrVariableSpace;
+ UINTN CacheOffset;
+ STATIC BOOLEAN Reclaimed;
+
+ //
+ // This function will be called only once at EndOfDxe or ReadyToBoot event.
+ //
+ if (Reclaimed) {
+ return;
+ }
+ Reclaimed = TRUE;
+
+ Status = EFI_SUCCESS;
+
+ if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {
+ RemainingCommonRuntimeVariableSpace = 0;
+ } else {
+ RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
+ }
+
+ RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
+
+ //
+ // Check if the free area is below a threshold.
+ //
+ if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
+ (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
+ ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
+ (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))) {
+ Status = Reclaim (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) mNvVariableCache,
+ &CacheOffset,
+ FALSE,
+ NULL,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+
+/**
+ Get non-volatile maximum variable size.
+
+ @return Non-volatile maximum variable size.
+
+**/
+UINTN
+GetNonVolatileMaxVariableSize (
+ VOID
+ )
+{
+ if (PcdGet32 (PcdHwErrStorageSize) != 0) {
+ return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),
+ PcdGet32 (PcdMaxHardwareErrorVariableSize));
+ } else {
+ return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));
+ }
+}
+
+
+/**
+ A callback invoked by each VARIABLE_STORAGE_PROTOCOL to indicate to the core variable driver that
+ SetVariable() is ready for use on that VARIABLE_STORAGE_PROTOCOL
+
+ @retval EFI_SUCCESS Change to WriteServiceIsReady() status was processed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableStorageWriteServiceReadyCallback (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+ BOOLEAN WriteServiceReady;
+
+ Status = EFI_SUCCESS;
+ WriteServiceReady = TRUE;
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ if (!VariableStorageProtocol->WriteServiceIsReady (VariableStorageProtocol)) {
+ WriteServiceReady = FALSE;
+ break;
+ }
+ }
+ if (WriteServiceReady && !mVariableModuleGlobal->WriteServiceReady) {
+ mVariableModuleGlobal->WriteServiceReady = TRUE;
+ Status = VariableWriteServiceInitialize ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, " Variable Driver: Variable write service initialization failed. Status = %r\n", Status));
+ } else {
+ //
+ // Install the Variable Write Architectural protocol
+ //
+ InstallVariableWriteReady ();
+ }
+ }
+ return Status;
+}
+
+
+/**
+ Init non-volatile variable store.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+ UINT32 NvStoreTotalSize;
+ UINT32 VariableStoreSize;
+ UINT32 CommonVariablesTotalSize;
+ UINT32 HwErrVariablesTotalSize;
+ UINT32 HwErrStorageSize;
+ UINT32 MaxUserNvVariableSpaceSize;
+ UINT32 BoottimeReservedNvVariableSpaceSize;
+ BOOLEAN AuthSupported;
+
+ //
+ // Get the total NV storage size from all VARIABLE_STORAGE_PROTOCOLs, and the amount of space
+ // used
+ //
+ NvStoreTotalSize = 0;
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;
+ mVariableModuleGlobal->WriteServiceReady = FALSE;
+
+ if (!mForceVolatileVariable) {
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ Status = VariableStorageProtocol->GetStorageUsage (
+ VariableStorageProtocol,
+ AtRuntime (),
+ &VariableStoreSize,
+ &CommonVariablesTotalSize,
+ &HwErrVariablesTotalSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "+-+-> Variable Driver: Data from StorageUsage VariableStorageProtocol[%d]:\n VariableStoreSize = %d bytes.\n CommonVariablesTotalSize = %d bytes. HwErrVariablesTotalSize = %d bytes.\n",
+ Index, VariableStoreSize, CommonVariablesTotalSize, HwErrVariablesTotalSize));
+
+ NvStoreTotalSize += VariableStoreSize;
+ mVariableModuleGlobal->CommonVariableTotalSize += CommonVariablesTotalSize;
+ mVariableModuleGlobal->HwErrVariableTotalSize += HwErrVariablesTotalSize;
+
+ //
+ // Determine authenticated variables support. If all of the
+ // VARIABLE_STORAGE_PROTOCOLs support authenticated variables, enable it. If
+ // any of the VARIABLE_STORAGE_PROTOCOLs do not support it disable it globally.
+ //
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthSupported = FALSE;
+ Status = VariableStorageProtocol->GetAuthenticatedSupport (
+ VariableStorageProtocol,
+ &AuthSupported
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (!AuthSupported) {
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;
+ }
+ }
+ }
+ } else {
+ NvStoreTotalSize = DEFAULT_NV_STORE_SIZE;
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;
+ }
+
+ DEBUG ((EFI_D_INFO, "+-+-> Variable Driver: Total data from StorageUsage:\n NvStoreTotalSize = %d bytes.\n CommonVariablesTotalSize = %d bytes. HwErrVariablesTotalSize = %d bytes.\n",
+ NvStoreTotalSize, mVariableModuleGlobal->CommonVariableTotalSize, mVariableModuleGlobal->HwErrVariableTotalSize));
+
+ //
+ // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
+ //
+ // The NV Storage Cache allows the variable services to cache any NV variable
+ // returned from the VARIABLE_STORAGE_PROTOCOLs so that subsequent reads will
+ // be returned from memory and not require additional NV access
+ //
+ NvStoreTotalSize = ALIGN_VALUE (NvStoreTotalSize, sizeof (UINT32));
+ mNvVariableCache = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (NvStoreTotalSize);
+ if (mNvVariableCache == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SetMem32 ((VOID *) mNvVariableCache, NvStoreTotalSize, (UINT32) 0xFFFFFFFF);
+ //
+ // Initialize the VARIABLE_STORE_HEADER for the NV Storage Cache
+ //
+ ZeroMem ((VOID *) mNvVariableCache, sizeof (VARIABLE_STORE_HEADER));
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ CopyMem (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid, sizeof (EFI_GUID));
+ } else {
+ CopyMem (&mNvVariableCache->Signature, &gEfiVariableGuid, sizeof (EFI_GUID));
+ }
+ mNvVariableCache->Size = NvStoreTotalSize;
+ mNvVariableCache->Format = VARIABLE_STORE_FORMATTED;
+ mNvVariableCache->State = VARIABLE_STORE_HEALTHY;
+ //
+ // Initialize mVariableModuleGlobal
+ //
+ HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
+ MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);
+ BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);
+ //
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+ // is stored with common variable in the same NV region. So the platform integrator should
+ // ensure that the value of PcdHwErrStorageSize is less than the value of
+ // (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER)).
+ //
+ ASSERT (HwErrStorageSize < (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER)));
+ //
+ // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
+ // (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
+ //
+ ASSERT (MaxUserNvVariableSpaceSize < (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
+ //
+ // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
+ // (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
+ //
+ ASSERT (BoottimeReservedNvVariableSpaceSize < (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
+
+ mVariableModuleGlobal->CommonVariableSpace = ((UINTN) NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
+ mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);
+ mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;
+
+ DEBUG ((EFI_D_INFO, " Variable Driver: Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace));
+
+ //
+ // The max NV variable size should be < (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER)).
+ //
+ ASSERT (GetNonVolatileMaxVariableSize () < (NvStoreTotalSize - sizeof (VARIABLE_STORE_HEADER)));
+
+ mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);
+ mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Flush the HOB variable to flash.
+
+ @param[in] VariableName Name of variable has been updated or deleted.
+ @param[in] VendorGuid Guid of variable has been updated or deleted.
+
+**/
+VOID
+FlushHobVariableToFlash (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_HEADER *Variable;
+ VOID *VariableData;
+ VARIABLE_POINTER_TRACK VariablePtrTrack;
+ BOOLEAN ErrorFlag;
+
+ ErrorFlag = FALSE;
+
+ //
+ // Flush the HOB variable to flash.
+ //
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
+ //
+ // Set HobVariableBase to 0, it can avoid SetVariable to call back.
+ //
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
+ for ( Variable = GetStartPointer (VariableStoreHeader)
+ ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
+ ; Variable = GetNextVariablePtr (Variable)
+ ) {
+ if (Variable->State != VAR_ADDED) {
+ //
+ // The HOB variable has been set to DELETED state in local.
+ //
+ continue;
+ }
+ ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
+ if (VendorGuid == NULL || VariableName == NULL ||
+ !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) ||
+ StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {
+ VariableData = GetVariableDataPtr (Variable);
+ FindVariable (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &VariablePtrTrack, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ Status = UpdateVariable (
+ GetVariableNamePtr (Variable),
+ GetVendorGuidPtr (Variable),
+ VariableData,
+ DataSizeOfVariable (Variable),
+ Variable->Attributes,
+ 0,
+ 0,
+ &VariablePtrTrack,
+ NULL
+ );
+ DEBUG ((EFI_D_INFO, " Variable Driver: Flushed the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status));
+ } else {
+ //
+ // The updated or deleted variable is matched with this HOB variable.
+ // Don't break here because we will try to set other HOB variables
+ // since this variable could be set successfully.
+ //
+ Status = EFI_SUCCESS;
+ }
+ if (!EFI_ERROR (Status)) {
+ //
+ // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
+ // set the HOB variable to DELETED state in local.
+ //
+ DEBUG ((EFI_D_INFO, " Variable Driver: Set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable)));
+ Variable->State &= VAR_DELETED;
+ } else {
+ ErrorFlag = TRUE;
+ }
+ }
+ if (ErrorFlag) {
+ //
+ // We still have HOB variable(s) not flushed in flash.
+ //
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;
+ } else {
+ //
+ // All HOB variables have been flushed in flash.
+ //
+ DEBUG ((EFI_D_INFO, " Variable Driver: All HOB variables have been flushed in flash.\n"));
+ if (!AtRuntime ()) {
+ FreePool ((VOID *) VariableStoreHeader);
+ }
+ }
+ }
+
+}
+
+
+/**
+ Initializes variable write service after FTW was ready.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Others Fail to initialize the variable service.
+
+**/
+EFI_STATUS
+VariableWriteServiceInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VARIABLE_ENTRY_PROPERTY *VariableEntry;
+
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+
+ FlushHobVariableToFlash (NULL, NULL);
+
+ Status = EFI_SUCCESS;
+ ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ //
+ // Authenticated variable initialize.
+ //
+ mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
+ mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();
+ Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " Variable Driver: Variable driver will work with auth variable support!\n"));
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;
+ if (mAuthContextOut.AuthVarEntry != NULL) {
+ for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
+ VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
+ Status = VarCheckLibVariablePropertySet (
+ VariableEntry->Name,
+ VariableEntry->Guid,
+ &VariableEntry->VariableProperty
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ } else if (Status == EFI_UNSUPPORTED) {
+ DEBUG ((EFI_D_INFO, " Variable Driver: NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
+ DEBUG ((EFI_D_INFO, " Variable Driver: Will continue to work without auth variable support!\n"));
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < sizeof (mVariableEntryProperty) / sizeof (mVariableEntryProperty[0]); Index++) {
+ VariableEntry = &mVariableEntryProperty[Index];
+ Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
+ //
+ // Initialize MOR Lock variable.
+ //
+ MorLockInit();
+
+ return Status;
+}
+
+
+/**
+ Initializes variable store area for non-volatile and volatile variable.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VolatileVariableStore;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINT64 VariableStoreLength;
+ UINTN ScratchSize;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_GUID *VariableGuid;
+ UINTN Index;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+
+ InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
+
+ //
+ // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
+ //
+ ScratchSize = GetNonVolatileMaxVariableSize ();
+ mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
+ VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
+ if (VolatileVariableStore == NULL) {
+ FreePool (mVariableModuleGlobal);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mVariableDataBuffer = AllocateRuntimePool (ScratchSize);
+ if (mVariableDataBuffer == NULL) {
+ FreePool (mVariableModuleGlobal);
+ FreePool (VolatileVariableStore);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init non-volatile variable store.
+ //
+ Status = InitNonVolatileVariableStore ();
+ if (EFI_ERROR (Status)) {
+ FreePool (mVariableModuleGlobal);
+ FreePool (mVariableDataBuffer);
+ FreePool (VolatileVariableStore);
+ return Status;
+ }
+
+ //
+ // mVariableModuleGlobal->VariableGlobal.AuthFormat
+ // has been initialized in InitNonVolatileVariableStore().
+ //
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ DEBUG ((EFI_D_INFO, " Variable Driver: Will work with auth variable format!\n"));
+ //
+ // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
+ //
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+ VariableGuid = &gEfiAuthenticatedVariableGuid;
+ } else {
+ DEBUG ((EFI_D_INFO, " Variable Driver: Will work without auth variable support!\n"));
+ mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
+ VariableGuid = &gEfiVariableGuid;
+ }
+
+ //
+ // Get HOB variable store.
+ //
+ GuidHob = GetFirstGuidHob (VariableGuid);
+ if (GuidHob != NULL) {
+ VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
+ VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));
+ if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
+ FreePool (mNvVariableCache);
+ FreePool (mVariableModuleGlobal);
+ FreePool (mVariableDataBuffer);
+ FreePool (VolatileVariableStore);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));
+ }
+ }
+
+ SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
+
+ //
+ // Initialize Variable Specific Data.
+ //
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
+ mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
+
+ CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
+ VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
+ VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
+ VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
+ VolatileVariableStore->Reserved = 0;
+ VolatileVariableStore->Reserved1 = 0;
+
+ //
+ // Setup the callback to determine when to enable variable writes
+ //
+ if (!mForceVolatileVariable) {
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ VariableStorageProtocol->RegisterWriteServiceReadyCallback (
+ VariableStorageProtocol,
+ VariableStorageWriteServiceReadyCallback
+ );
+ }
+ } else {
+ mVariableModuleGlobal->WriteServiceReady = TRUE;
+ Status = VariableWriteServiceInitialize ();
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, " Variable Driver: Variable write service initialization failed. Status = %r\n", Status));
+ } else {
+ //
+ // Install the Variable Write Architectural protocol
+ //
+ InstallVariableWriteReady ();
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
new file mode 100644
index 0000000000..eebf4e878d
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -0,0 +1,841 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by Variable modules.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VARIABLE_H_
+#define _VARIABLE_H_
+
+#include <PiDxe.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Variable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/VarCheck.h>
+#include <Protocol/VariableStorageProtocol.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/AuthVariableLib.h>
+#include <Library/VarCheckLib.h>
+#include <Library/VariableStorageSelectorLib.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
+#include <Guid/VariableFormat.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VarErrorFlag.h>
+
+#define EFI_VARIABLE_ATTRIBUTES_MASK (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS | \
+ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+ EFI_VARIABLE_APPEND_WRITE)
+
+///
+/// The size of a 3 character ISO639 language code.
+///
+#define ISO_639_2_ENTRY_SIZE 3
+
+#define MAX_VARIABLE_NAME_SIZE 1024
+#define DEFAULT_NV_STORE_SIZE 0x20000
+
+typedef enum {
+ VariableStoreTypeVolatile,
+ VariableStoreTypeHob,
+ VariableStoreTypeNvCache,
+ VariableStoreTypeMax
+} VARIABLE_STORE_TYPE;
+
+typedef struct {
+ VARIABLE_HEADER *CurrPtr;
+ //
+ // If both ADDED and IN_DELETED_TRANSITION variable are present,
+ // InDeletedTransitionPtr will point to the IN_DELETED_TRANSITION one.
+ // Otherwise, CurrPtr will point to the ADDED or IN_DELETED_TRANSITION one,
+ // and InDeletedTransitionPtr will be NULL at the same time.
+ //
+ VARIABLE_HEADER *InDeletedTransitionPtr;
+ VARIABLE_HEADER *EndPtr;
+ VARIABLE_HEADER *StartPtr;
+ BOOLEAN Volatile;
+} VARIABLE_POINTER_TRACK;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS HobVariableBase;
+ EFI_PHYSICAL_ADDRESS VolatileVariableBase;
+ VARIABLE_STORAGE_PROTOCOL **VariableStores;
+ UINTN VariableStoresCount;
+ EFI_LOCK VariableServicesLock;
+ UINT32 ReentrantState;
+ BOOLEAN AuthFormat;
+ BOOLEAN AuthSupport;
+} VARIABLE_GLOBAL;
+
+typedef struct {
+ VARIABLE_GLOBAL VariableGlobal;
+ UINTN VolatileLastVariableOffset;
+ UINTN CommonVariableSpace;
+ UINTN CommonMaxUserVariableSpace;
+ UINTN CommonRuntimeVariableSpace;
+ UINTN CommonVariableTotalSize;
+ UINTN CommonUserVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ UINTN MaxVariableSize;
+ UINTN MaxAuthVariableSize;
+ UINTN ScratchBufferSize;
+ CHAR8 *PlatformLangCodes;
+ CHAR8 *LangCodes;
+ CHAR8 *PlatformLang;
+ CHAR8 Lang[ISO_639_2_ENTRY_SIZE + 1];
+ BOOLEAN WriteServiceReady;
+} VARIABLE_MODULE_GLOBAL;
+
+/**
+ Flush the HOB variable to flash.
+
+ @param[in] VariableName Name of variable has been updated or deleted.
+ @param[in] VendorGuid Guid of variable has been updated or deleted.
+
+**/
+VOID
+FlushHobVariableToFlash (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+/**
+ Writes a buffer to variable storage space, in the working block.
+
+ This function writes a buffer to variable storage space into a firmware
+ volume block device. The destination is specified by the parameter
+ VariableBase. Fault Tolerant Write protocol is used for writing.
+
+ @param[in] VariableBase Base address of the variable to write.
+ @param[in] VariableBuffer Point to the variable data buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
+ @retval EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ IN VARIABLE_STORE_HEADER *VariableBuffer
+ );
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+ If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
+ at runtime when searching existing variable, only VariableName and VendorGuid are compared.
+ Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
+ check at runtime when searching variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found.
+
+**/
+EFI_STATUS
+FindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN IgnoreRtCheck
+ );
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param[in] VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ );
+
+/**
+ This code gets the size of variable header.
+
+ @return Size of variable header in bytes in type UINTN.
+
+**/
+UINTN
+GetVariableHeaderSize (
+ VOID
+ );
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+ This code gets the pointer to the variable guid.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return A EFI_GUID* pointer to Vendor Guid.
+
+**/
+EFI_GUID *
+GetVendorGuidPtr (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+
+ This code gets the size of variable data.
+
+ @param[in] Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ );
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param[in] Marker VA_LIST style variable argument list.
+ The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+CheckRemainingSpaceForConsistencyInternal (
+ IN UINT32 Attributes,
+ IN VA_LIST Marker
+ );
+
+/**
+ Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
+ index of associated public key is needed.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in, out] Variable The variable information that is used to keep track of variable usage.
+
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, cannot write other data into this region.
+
+**/
+EFI_STATUS
+UpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN OUT VARIABLE_POINTER_TRACK *Variable,
+ IN EFI_TIME *TimeStamp OPTIONAL
+ );
+
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+ @retval TRUE If ExitBootServices () has been called.
+
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ );
+
+/**
+ Initializes a basic mutual exclusion lock.
+
+ This function initializes a basic mutual exclusion lock to the released state
+ and returns the lock. Each lock provides mutual exclusion access at its task
+ priority level. Since there is no preemption or multiprocessor support in EFI,
+ acquiring the lock only consists of raising to the locks TPL.
+ If Lock is NULL, then ASSERT().
+ If Priority is not a valid TPL value, then ASSERT().
+
+ @param[in] Lock A pointer to the lock data structure to initialize.
+ @param[in] Priority EFI TPL is associated with the lock.
+
+ @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+ IN OUT EFI_LOCK *Lock,
+ IN EFI_TPL Priority
+ );
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Initializes variable store area for non-volatile and volatile variable.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+ VOID
+ );
+
+/**
+ This function reclaims variable storage if free size is below the threshold.
+
+**/
+VOID
+ReclaimForOS(
+ VOID
+ );
+
+/**
+ Get non-volatile maximum variable size.
+
+ @return Non-volatile maximum variable size.
+
+**/
+UINTN
+GetNonVolatileMaxVariableSize (
+ VOID
+ );
+
+/**
+ Initializes variable write service after FVB was ready.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Others Fail to initialize the variable service.
+
+**/
+EFI_STATUS
+VariableWriteServiceInitialize (
+ VOID
+ );
+
+/**
+ This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] VariableNameSize Size of the variable name.
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Variable Vendor Guid.
+
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableInternal (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VariableGuid
+ );
+
+/**
+
+ This code Finds the Next available variable.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Find the specified variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ );
+
+/**
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable found
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_SUCCESS Query successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfoInternal (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ );
+
+/**
+ This code returns information about the EFI variables.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @return EFI_SUCCESS Query successfully.
+ @return EFI_UNSUPPORTED The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ );
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The 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
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @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 for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ );
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @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 for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ );
+
+/**
+ Initialize variable quota.
+
+**/
+VOID
+InitializeVariableQuota (
+ VOID
+ );
+
+extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
+extern BOOLEAN mForceVolatileVariable;
+extern AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the variable found.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the next variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindNextVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
+ input of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateVariable (
+ IN AUTH_VARIABLE_INFO *AuthVariableInfo
+ );
+
+/**
+ Get scratch buffer.
+
+ @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+ the maximum supported buffer size, this value contains
+ the maximum supported buffer size as output.
+ @param[out] ScratchBuffer Pointer to scratch buffer address.
+
+ @retval EFI_SUCCESS Get scratch buffer successfully.
+ @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibGetScratchBuffer (
+ IN OUT UINTN *ScratchBufferSize,
+ OUT VOID **ScratchBuffer
+ );
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibCheckRemainingSpaceForConsistency (
+ IN UINT32 Attributes,
+ ...
+ );
+
+/**
+ Return TRUE if at OS runtime.
+
+ @retval TRUE If at OS runtime.
+ @retval FALSE If at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibAtRuntime (
+ VOID
+ );
+
+/**
+ Non-Volatile variable write service is ready event handler.
+
+**/
+VOID
+EFIAPI
+InstallVariableWriteReady (
+ VOID
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
new file mode 100644
index 0000000000..6400bae9ca
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
@@ -0,0 +1,436 @@
+/** @file
+ Implement all four UEFI Runtime Variable services for the nonvolatile
+ and volatile storage space and install variable architecture protocol.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+
+extern VARIABLE_STORE_HEADER *mNvVariableCache;
+extern VARIABLE_INFO_ENTRY *gVariableInfo;
+EFI_HANDLE mHandle = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+extern BOOLEAN mEndOfDxe;
+VOID ***mVarCheckAddressPointer = NULL;
+UINTN mVarCheckAddressPointerCount = 0;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock = { VariableLockRequestToLock };
+EDKII_VAR_CHECK_PROTOCOL mVarCheck = { VarCheckRegisterSetVariableCheckHandler,
+ VarCheckVariablePropertySet,
+ VarCheckVariablePropertyGet };
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ )
+{
+ return EfiAtRuntime ();
+}
+
+
+/**
+ Initializes a basic mutual exclusion lock.
+
+ This function initializes a basic mutual exclusion lock to the released state
+ and returns the lock. Each lock provides mutual exclusion access at its task
+ priority level. Since there is no preemption or multiprocessor support in EFI,
+ acquiring the lock only consists of raising to the locks TPL.
+ If Lock is NULL, then ASSERT().
+ If Priority is not a valid TPL value, then ASSERT().
+
+ @param[in] Lock A pointer to the lock data structure to initialize.
+ @param[in] Priority EFI TPL is associated with the lock.
+
+ @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+ IN OUT EFI_LOCK *Lock,
+ IN EFI_TPL Priority
+ )
+{
+ return EfiInitializeLock (Lock, Priority);
+}
+
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!AtRuntime ()) {
+ EfiAcquireLock (Lock);
+ }
+}
+
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!AtRuntime ()) {
+ EfiReleaseLock (Lock);
+ }
+}
+
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableClassAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+ VARIABLE_STORAGE_PROTOCOL *VariableStorageProtocol;
+
+ //
+ // Setup the callback to determine when to enable variable writes
+ //
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ VariableStorageProtocol = mVariableModuleGlobal->VariableGlobal.VariableStores[Index];
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->GetId);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->GetVariable);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->GetAuthenticatedVariable);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->GetNextVariableName);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->GetStorageUsage);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->GetAuthenticatedSupport);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->SetVariable);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->WriteServiceIsReady);
+ EfiConvertPointer (0x0, (VOID **) &VariableStorageProtocol->RegisterWriteServiceReadyCallback);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VariableStores[Index]);
+ }
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VariableStores);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
+ EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);
+
+ if (mAuthContextOut.AddressPointer != NULL) {
+ for (Index = 0; Index < mAuthContextOut.AddressPointerCount; Index++) {
+ EfiConvertPointer (0x0, (VOID **) mAuthContextOut.AddressPointer[Index]);
+ }
+ }
+
+ if (mVarCheckAddressPointer != NULL) {
+ for (Index = 0; Index < mVarCheckAddressPointerCount; Index++) {
+ EfiConvertPointer (0x0, (VOID **) mVarCheckAddressPointer[Index]);
+ }
+ }
+}
+
+
+/**
+ Notification function of EVT_GROUP_READY_TO_BOOT event group.
+
+ This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
+ When the Boot Manager is about to load and execute a boot option, it reclaims variable
+ storage if free size is below the threshold.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ if (!mEndOfDxe) {
+ //
+ // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUID event is not signaled.
+ //
+ mEndOfDxe = TRUE;
+ mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ }
+ ReclaimForOS ();
+ if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
+ } else {
+ gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
+ }
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n"));
+ mEndOfDxe = TRUE;
+ mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
+ ReclaimForOS ();
+ }
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Non-Volatile variable write service is ready event handler.
+
+**/
+VOID
+EFIAPI
+InstallVariableWriteReady (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "Installing EfiVariableWriteArchProtocolGuid\n"));
+ //
+ // Install the Variable Write Architectural protocol.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableWriteArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
+ EFI_HANDLE *Handles;
+ UINTN Index;
+
+ //
+ // Allocate runtime memory for variable driver global structure.
+ //
+ mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
+ if (mVariableModuleGlobal == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get the VARIABLE_STORAGE_PROTOCOL instances
+ //
+ mVariableModuleGlobal->VariableGlobal.VariableStoresCount = 0;
+ Handles = NULL;
+
+ //
+ // Determine if Force Volatile Mode is enabled
+ //
+ mForceVolatileVariable = PcdGetBool (PcdForceVolatileVariable);
+
+ if (!mForceVolatileVariable) {
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gVariableStorageProtocolGuid,
+ NULL,
+ &mVariableModuleGlobal->VariableGlobal.VariableStoresCount,
+ &Handles
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ mVariableModuleGlobal->VariableGlobal.VariableStores =
+ AllocateRuntimeZeroPool (
+ sizeof (VARIABLE_STORAGE_PROTOCOL *) *
+ mVariableModuleGlobal->VariableGlobal.VariableStoresCount
+ );
+ ASSERT (mVariableModuleGlobal->VariableGlobal.VariableStores != NULL);
+ if (mVariableModuleGlobal->VariableGlobal.VariableStores == NULL) {
+ FreePool (Handles);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ Status = gBS->OpenProtocol (
+ Handles[Index],
+ &gVariableStorageProtocolGuid,
+ (VOID **) &mVariableModuleGlobal->VariableGlobal.VariableStores[Index],
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ FreePool (Handles);
+ return Status;
+ }
+ }
+ FreePool (Handles);
+ }
+
+ //
+ // Initialize variable services
+ //
+ Status = VariableCommonInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVarCheckProtocolGuid,
+ &mVarCheck,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable;
+ SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
+ SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable;
+ SystemTable->RuntimeServices->QueryVariableInfo = VariableServiceQueryVariableInfo;
+
+ //
+ // Now install the Variable Runtime Architectural protocol on a new handle.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VariableClassAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event handling function to reclaim variable for OS usage.
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_NOTIFY,
+ OnReadyToBoot,
+ NULL,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the event handling function to set the End Of DXE flag.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
new file mode 100644
index 0000000000..00f9eb92d2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableExLib.c
@@ -0,0 +1,291 @@
+/** @file
+ Provides variable driver extended services.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the variable found.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
+
+ Status = FindVariable (
+ VariableName,
+ VendorGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ AuthVariableInfo->Data = NULL;
+ AuthVariableInfo->DataSize = 0;
+ AuthVariableInfo->Attributes = 0;
+ AuthVariableInfo->PubKeyIndex = 0;
+ AuthVariableInfo->MonotonicCount = 0;
+ AuthVariableInfo->TimeStamp = NULL;
+ return Status;
+ }
+
+ AuthVariableInfo->DataSize = DataSizeOfVariable (Variable.CurrPtr);
+ AuthVariableInfo->Data = GetVariableDataPtr (Variable.CurrPtr);
+ AuthVariableInfo->Attributes = Variable.CurrPtr->Attributes;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable.CurrPtr;
+ AuthVariableInfo->PubKeyIndex = AuthVariable->PubKeyIndex;
+ AuthVariableInfo->MonotonicCount = ReadUnaligned64 (&(AuthVariable->MonotonicCount));
+ AuthVariableInfo->TimeStamp = &AuthVariable->TimeStamp;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Finds next variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds next variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO structure for
+ output of the next variable.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibFindNextVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT AUTH_VARIABLE_INFO *AuthVariableInfo
+ )
+{
+ CHAR16 TempName[2048];
+ EFI_GUID TempGuid;
+ VARIABLE_POINTER_TRACK Variable;
+ EFI_STATUS Status;
+ UINTN TempNameSize;
+ VARIABLE_HEADER *VariablePtr;
+ AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr;
+
+ ASSERT (StrLen (VariableName) < 2048);
+ if (StrLen (VariableName) >= 2048) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ TempNameSize = 2048 * sizeof (CHAR16);
+ StrCpyS ((CHAR16 *) TempName, TempNameSize, VariableName);
+ CopyMem (&TempGuid, VendorGuid, sizeof (EFI_GUID));
+ Status = VariableServiceGetNextVariableInternal (
+ &TempNameSize,
+ &TempName[0],
+ &TempGuid
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+ AuthVariableInfo->VariableName = NULL;
+ AuthVariableInfo->VendorGuid = NULL;
+ AuthVariableInfo->Data = NULL;
+ AuthVariableInfo->DataSize = 0;
+ AuthVariableInfo->Attributes = 0;
+ AuthVariableInfo->PubKeyIndex = 0;
+ AuthVariableInfo->MonotonicCount = 0;
+ AuthVariableInfo->TimeStamp = NULL;
+ return Status;
+ } else {
+ Status = FindVariable (&TempName[0], &TempGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ AuthVariableInfo->VariableName = NULL;
+ AuthVariableInfo->VendorGuid = NULL;
+ AuthVariableInfo->Data = NULL;
+ AuthVariableInfo->DataSize = 0;
+ AuthVariableInfo->Attributes = 0;
+ AuthVariableInfo->PubKeyIndex = 0;
+ AuthVariableInfo->MonotonicCount = 0;
+ AuthVariableInfo->TimeStamp = NULL;
+ return Status;
+ }
+ VariablePtr = Variable.CurrPtr;
+ }
+
+ AuthVariableInfo->VariableName = GetVariableNamePtr (VariablePtr);
+ AuthVariableInfo->VendorGuid = GetVendorGuidPtr (VariablePtr);
+ AuthVariableInfo->DataSize = DataSizeOfVariable (VariablePtr);
+ AuthVariableInfo->Data = GetVariableDataPtr (VariablePtr);
+ AuthVariableInfo->Attributes = VariablePtr->Attributes;
+ if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
+ AuthVariablePtr = (AUTHENTICATED_VARIABLE_HEADER *) VariablePtr;
+ AuthVariableInfo->PubKeyIndex = AuthVariablePtr->PubKeyIndex;
+ AuthVariableInfo->MonotonicCount = ReadUnaligned64 (&(AuthVariablePtr->MonotonicCount));
+ AuthVariableInfo->TimeStamp = &AuthVariablePtr->TimeStamp;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for
+ input of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibUpdateVariable (
+ IN AUTH_VARIABLE_INFO *AuthVariableInfo
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+
+ FindVariable (AuthVariableInfo->VariableName, AuthVariableInfo->VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ return UpdateVariable (
+ AuthVariableInfo->VariableName,
+ AuthVariableInfo->VendorGuid,
+ AuthVariableInfo->Data,
+ AuthVariableInfo->DataSize,
+ AuthVariableInfo->Attributes,
+ AuthVariableInfo->PubKeyIndex,
+ AuthVariableInfo->MonotonicCount,
+ &Variable,
+ AuthVariableInfo->TimeStamp
+ );
+}
+
+
+/**
+ Get scratch buffer.
+
+ @param[in, out] ScratchBufferSize Scratch buffer size. If input size is greater than
+ the maximum supported buffer size, this value contains
+ the maximum supported buffer size as output.
+ @param[out] ScratchBuffer Pointer to scratch buffer address.
+
+ @retval EFI_SUCCESS Get scratch buffer successfully.
+ @retval EFI_UNSUPPORTED If input size is greater than the maximum supported buffer size.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableExLibGetScratchBuffer (
+ IN OUT UINTN *ScratchBufferSize,
+ OUT VOID **ScratchBuffer
+ )
+{
+ UINTN MaxBufferSize;
+
+ MaxBufferSize = mVariableModuleGlobal->ScratchBufferSize;
+ if (*ScratchBufferSize > MaxBufferSize) {
+ *ScratchBufferSize = MaxBufferSize;
+ return EFI_UNSUPPORTED;
+ }
+
+ *ScratchBuffer = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function is to check if the remaining variable space is enough to set
+ all Variables from argument list successfully. The purpose of the check
+ is to keep the consistency of the Variables to be in variable storage.
+
+ Note: Variables are assumed to be in same storage.
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
+ so follow the argument sequence to check the Variables.
+
+ @param[in] Attributes Variable attributes for Variable entries.
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
+ A NULL terminates the list. The VariableSize of
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
+ It will be changed to variable total size as output.
+
+ @retval TRUE Have enough variable space to set the Variables successfully.
+ @retval FALSE No enough variable space to set the Variables successfully.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibCheckRemainingSpaceForConsistency (
+ IN UINT32 Attributes,
+ ...
+ )
+{
+ VA_LIST Marker;
+ BOOLEAN Return;
+
+ VA_START (Marker, Attributes);
+
+ Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
+
+ VA_END (Marker);
+
+ return Return;
+}
+
+/**
+ Return TRUE if at OS runtime.
+
+ @retval TRUE If at OS runtime.
+ @retval FALSE If at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+VariableExLibAtRuntime (
+ VOID
+ )
+{
+ return AtRuntime ();
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
new file mode 100644
index 0000000000..35dff53114
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -0,0 +1,129 @@
+## @file
+# Provides variable service.
+#
+# This module installs variable arch protocol and variable write arch protocol to provide
+# variable services: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableRuntimeDxe
+ MODULE_UNI_FILE = VariableRuntimeDxe.uni
+ FILE_GUID = CBD2E4D5-7068-4FF5-B462-9822B4AD8D60
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableClassAddressChangeEvent
+#
+
+[Sources]
+ Variable.c
+ VariableDxe.c
+ Variable.h
+ Measurement.c
+ TcgMorLockDxe.c
+ VarCheck.c
+ VariableExLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ SynchronizationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ UefiRuntimeLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ PcdLib
+ HobLib
+ TpmMeasurementLib
+ AuthVariableLib
+ VarCheckLib
+ VariableStorageSelectorLib
+
+[Protocols]
+ gVariableStorageProtocolGuid ## CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiVariableWriteArchProtocolGuid ## PRODUCES
+ gEfiVariableArchProtocolGuid ## PRODUCES
+ gEdkiiVariableLockProtocolGuid ## PRODUCES
+ gEdkiiVarCheckProtocolGuid ## PRODUCES
+
+[Guids]
+ ## PRODUCES ## GUID # Signature of Variable store header
+ ## CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiAuthenticatedVariableGuid
+
+ ## PRODUCES ## GUID # Signature of Variable store header
+ ## CONSUMES ## GUID # Signature of Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang"
+ ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang"
+ ## SOMETIMES_CONSUMES ## Variable:L"Lang"
+ ## SOMETIMES_PRODUCES ## Variable:L"Lang"
+ gEfiGlobalVariableGuid
+ gEfiMemoryOverwriteControlDataGuid ## CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteRequestControlLockGuid ## PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEdkiiVarErrorFlagGuid ## CONSUMES ## GUID
+
+ ## SOMETIMES_CONSUMES ## Variable:L"DB"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBX"
+ gEfiImageSecurityDatabaseGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES
+ gSiPkgTokenSpaceGuid.PcdForceVolatileVariable ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # Variable statistic information
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang
+
+[Depex]
+ gVariableStorageProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableRuntimeDxeExtra.uni
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni
new file mode 100644
index 0000000000..1c3e7f07e4
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni
new file mode 100644
index 0000000000..a3a76dacb5
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxeExtra.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
new file mode 100644
index 0000000000..78439fc5a7
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
@@ -0,0 +1,911 @@
+/** @file
+ The sample implementation for SMM variable protocol. And this driver
+ implements an SMI handler to communicate with the DXE runtime driver
+ to provide variable services.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data and communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmVariableHandler() will receive untrusted input and do basic validation.
+
+ Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
+ VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
+ SmmVariableGetStatistics() should also do validation based on its own knowledge.
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Protocol/SmmVariable.h>
+#include <Protocol/SmmFirmwareVolumeBlock.h>
+#include <Protocol/SmmFaultTolerantWrite.h>
+#include <Protocol/SmmEndOfDxe.h>
+#include <Protocol/SmmVarCheck.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/SmmMemLib.h>
+#include <Guid/SmmVariableCommon.h>
+#include <Guid/ZeroGuid.h>
+#include "Variable.h"
+
+extern VARIABLE_INFO_ENTRY *gVariableInfo;
+EFI_HANDLE mSmmVariableHandle = NULL;
+EFI_HANDLE mVariableHandle = NULL;
+BOOLEAN mAtRuntime = FALSE;
+UINT8 *mVariableBufferPayload = NULL;
+UINTN mVariableBufferPayloadSize;
+extern BOOLEAN mEndOfDxe;
+extern VAR_CHECK_REQUEST_SOURCE mRequestSource;
+
+
+/**
+ SecureBoot Hook for SetVariable.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ return ;
+}
+
+
+/**
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable found
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Set successfully.
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @return EFI_NOT_FOUND Not found.
+ @return EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
+ //
+ mRequestSource = VarCheckFromTrusted;
+ Status = VariableServiceSetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ mRequestSource = VarCheckFromUntrusted;
+ return Status;
+}
+
+EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
+ VariableServiceGetVariable,
+ VariableServiceGetNextVariableName,
+ SmmVariableSetVariable,
+ VariableServiceQueryVariableInfo
+};
+
+EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck = { VarCheckRegisterSetVariableCheckHandler,
+ VarCheckVariablePropertySet,
+ VarCheckVariablePropertyGet };
+
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ )
+{
+ return mAtRuntime;
+}
+
+
+/**
+ Initializes a basic mutual exclusion lock.
+
+ This function initializes a basic mutual exclusion lock to the released state
+ and returns the lock. Each lock provides mutual exclusion access at its task
+ priority level. Since there is no preemption or multiprocessor support in EFI,
+ acquiring the lock only consists of raising to the locks TPL.
+ If Lock is NULL, then ASSERT().
+ If Priority is not a valid TPL value, then ASSERT().
+
+ @param[in] Lock A pointer to the lock data structure to initialize.
+ @param[in] Priority EFI TPL is associated with the lock.
+
+ @return The lock.
+
+**/
+EFI_LOCK *
+InitializeLock (
+ IN OUT EFI_LOCK *Lock,
+ IN EFI_TPL Priority
+ )
+{
+ return Lock;
+}
+
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+
+}
+
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+
+}
+
+
+/**
+ Get the variable statistics information from the information buffer pointed by gVariableInfo.
+
+ Caution: This function may be invoked at SMM runtime.
+ InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
+
+ @param[in, out] InfoEntry A pointer to the buffer of variable information entry.
+ On input, point to the variable information returned last time. if
+ InfoEntry->VendorGuid is zero, return the first information.
+ On output, point to the next variable information.
+ @param[in, out] InfoSize On input, the size of the variable information buffer.
+ On output, the returned variable information size.
+
+ @retval EFI_SUCCESS The variable information is found and returned successfully.
+ @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
+ PcdVariableCollectStatistics should be set TRUE to support it.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
+ @retval EFI_INVALID_PARAMETER Input parameter is invalid.
+
+**/
+EFI_STATUS
+SmmVariableGetStatistics (
+ IN OUT VARIABLE_INFO_ENTRY *InfoEntry,
+ IN OUT UINTN *InfoSize
+ )
+{
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ UINTN NameLength;
+ UINTN StatisticsInfoSize;
+ CHAR16 *InfoName;
+ EFI_GUID VendorGuid;
+
+ if (InfoEntry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableInfo = gVariableInfo;
+ if (VariableInfo == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);
+ if (*InfoSize < StatisticsInfoSize) {
+ *InfoSize = StatisticsInfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ InfoName = (CHAR16 *)(InfoEntry + 1);
+
+ CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);
+
+ if (CompareGuid (&VendorGuid, &gZeroGuid)) {
+ //
+ // Return the first variable info
+ //
+ CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
+ CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));
+ *InfoSize = StatisticsInfoSize;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the next variable info
+ //
+ while (VariableInfo != NULL) {
+ if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {
+ NameLength = StrSize (VariableInfo->Name);
+ if (NameLength == StrSize (InfoName)) {
+ if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {
+ //
+ // Find the match one
+ //
+ VariableInfo = VariableInfo->Next;
+ break;
+ }
+ }
+ }
+ VariableInfo = VariableInfo->Next;
+ };
+
+ if (VariableInfo == NULL) {
+ *InfoSize = 0;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Output the new variable info
+ //
+ StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);
+ if (*InfoSize < StatisticsInfoSize) {
+ *InfoSize = StatisticsInfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
+ CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));
+ *InfoSize = StatisticsInfoSize;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the variable wrapper driver.
+
+ Caution: This function may receive untrusted input.
+ This variable data and communicate buffer are external input, so this function will do basic validation.
+ Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
+ VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
+ SmmVariableGetStatistics() should also do validation based on its own knowledge.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmVariableHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize;
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
+ UINTN InfoSize;
+ UINTN NameBufferSize;
+ UINTN CommBufferPayloadSize;
+ UINTN TempCommBufferSize;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+ DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ CommBufferPayloadSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ if (CommBufferPayloadSize > mVariableBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer;
+ switch (SmmVariableFunctionHeader->Function) {
+ case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
+ if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+ DEBUG ((EFI_D_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
+ if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+ ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
+ + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize / sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VariableServiceGetVariable (
+ SmmVariableHeader->Name,
+ &SmmVariableHeader->Guid,
+ &SmmVariableHeader->Attributes,
+ &SmmVariableHeader->DataSize,
+ (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
+ );
+ CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
+ if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ DEBUG ((EFI_D_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) mVariableBufferPayload;
+ if ((UINTN) (~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + GetNextVariableName->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ NameBufferSize = CommBufferPayloadSize - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
+ if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize / sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure input VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VariableServiceGetNextVariableName (
+ &GetNextVariableName->NameSize,
+ GetNextVariableName->Name,
+ &GetNextVariableName->Guid
+ );
+ CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
+ if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+ DEBUG ((EFI_D_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
+ if (((UINTN) (~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+ ((UINTN) (~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
+ + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ // Data buffer should not contain SMM range
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize / sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VariableServiceSetVariable (
+ SmmVariableHeader->Name,
+ &SmmVariableHeader->Guid,
+ SmmVariableHeader->Attributes,
+ SmmVariableHeader->DataSize,
+ (UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize
+ );
+ break;
+
+ case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
+ DEBUG ((EFI_D_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;
+
+ Status = VariableServiceQueryVariableInfo (
+ QueryVariableInfo->Attributes,
+ &QueryVariableInfo->MaximumVariableStorageSize,
+ &QueryVariableInfo->RemainingVariableStorageSize,
+ &QueryVariableInfo->MaximumVariableSize
+ );
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
+ DEBUG ((EFI_D_ERROR, "GetPayloadSize: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ GetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
+ GetPayloadSize->VariablePayloadSize = mVariableBufferPayloadSize;
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
+ if (AtRuntime()) {
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ if (!mEndOfDxe) {
+ mEndOfDxe = TRUE;
+ VarCheckLibInitializeAtEndOfDxe (NULL);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ }
+ ReclaimForOS ();
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
+ mAtRuntime = TRUE;
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_STATISTICS:
+ VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;
+ InfoSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+
+ //
+ // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
+ // It is covered by previous CommBuffer check
+ //
+ if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS) (UINTN) CommBufferSize, sizeof (UINTN))) {
+ DEBUG ((EFI_D_ERROR, "GetStatistics: SMM communication buffer in SMRAM!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);
+ *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
+ if (mEndOfDxe) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) SmmVariableFunctionHeader->Data;
+ Status = VariableLockRequestToLock (
+ NULL,
+ VariableToLock->Name,
+ &VariableToLock->Guid
+ );
+ }
+ break;
+ case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET:
+ if (mEndOfDxe) {
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) SmmVariableFunctionHeader->Data;
+ Status = VarCheckVariablePropertySet (
+ CommVariableProperty->Name,
+ &CommVariableProperty->Guid,
+ &CommVariableProperty->VariableProperty
+ );
+ }
+ break;
+ case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET:
+ if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ DEBUG ((EFI_D_ERROR, "VarCheckVariablePropertyGet: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
+ //
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
+ CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) mVariableBufferPayload;
+ if ((UINTN) (~0) - CommVariableProperty->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ //
+ // Prevent InfoSize overflow happen
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+ InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + CommVariableProperty->NameSize;
+
+ //
+ // SMRAM range check already covered before
+ //
+ if (InfoSize > CommBufferPayloadSize) {
+ DEBUG ((EFI_D_ERROR, "VarCheckVariablePropertyGet: Data size exceed communication buffer size limit!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ if (CommVariableProperty->NameSize < sizeof (CHAR16) || CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof (CHAR16) - 1] != L'\0') {
+ //
+ // Make sure VariableName is A Null-terminated string.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto EXIT;
+ }
+
+ Status = VarCheckVariablePropertyGet (
+ CommVariableProperty->Name,
+ &CommVariableProperty->Guid,
+ &CommVariableProperty->VariableProperty
+ );
+ CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+EXIT:
+
+ SmmVariableFunctionHeader->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ SMM END_OF_DXE protocol notification event handler.
+
+ @param[in] Protocol Points to the protocol's unique identifier
+ @param[in] Interface Points to the interface instance
+ @param[in] Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ DEBUG ((EFI_D_INFO, "[Variable]SMM_END_OF_DXE is signaled\n"));
+ mEndOfDxe = TRUE;
+ VarCheckLibInitializeAtEndOfDxe (NULL);
+ //
+ // The initialization for variable quota.
+ //
+ InitializeVariableQuota ();
+ if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
+ ReclaimForOS ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Non-Volatile variable write service is ready event handler.
+
+**/
+VOID
+EFIAPI
+InstallVariableWriteReady (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "Installing SmmVariableWriteGuid to notify wrapper\n"));
+ //
+ // Notify the variable wrapper driver the variable write service is ready
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mSmmVariableHandle,
+ &gSmmVariableWriteGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE VariableHandle;
+ VOID *SmmEndOfDxeRegistration;
+ EFI_HANDLE *Handles;
+ UINTN Index;
+
+ //
+ // Allocate runtime memory for variable driver global structure.
+ //
+ mVariableModuleGlobal = NULL;
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (VARIABLE_MODULE_GLOBAL),
+ (VOID **) &mVariableModuleGlobal
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status) || mVariableModuleGlobal == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem (mVariableModuleGlobal, sizeof (VARIABLE_MODULE_GLOBAL));
+
+ //
+ // Get the VARIABLE_STORAGE_PROTOCOL instances
+ //
+ mVariableModuleGlobal->VariableGlobal.VariableStoresCount = 0;
+ Handles = NULL;
+
+ //
+ // Determine if Force Volatile Mode is enabled
+ //
+ mForceVolatileVariable = PcdGetBool (PcdForceVolatileVariable);
+
+ if (!mForceVolatileVariable) {
+ //
+ // Determine the number of handles
+ //
+ Status = gSmst->SmmLocateHandle (
+ ByProtocol,
+ &gVariableStorageProtocolGuid,
+ NULL,
+ &mVariableModuleGlobal->VariableGlobal.VariableStoresCount,
+ Handles
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ DEBUG ((DEBUG_INFO, "No SMM VariableStorageProtocol instances exist\n"));
+ return EFI_NOT_READY;
+ }
+ Handles = AllocateZeroPool (mVariableModuleGlobal->VariableGlobal.VariableStoresCount);
+ if (Handles == NULL) {
+ ASSERT (Handles != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mVariableModuleGlobal->VariableGlobal.VariableStores = NULL;
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (VARIABLE_STORAGE_PROTOCOL *) * (mVariableModuleGlobal->VariableGlobal.VariableStoresCount / sizeof (EFI_HANDLE)),
+ (VOID **) &mVariableModuleGlobal->VariableGlobal.VariableStores
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (mVariableModuleGlobal->VariableGlobal.VariableStores != NULL);
+ if (EFI_ERROR (Status) || mVariableModuleGlobal->VariableGlobal.VariableStores == NULL) {
+ FreePool (Handles);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the handles
+ //
+ Status = gSmst->SmmLocateHandle (
+ ByProtocol,
+ &gVariableStorageProtocolGuid,
+ NULL,
+ &mVariableModuleGlobal->VariableGlobal.VariableStoresCount,
+ Handles
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ gSmst->SmmFreePool (mVariableModuleGlobal->VariableGlobal.VariableStores);
+ FreePool (Handles);
+ return Status;
+ }
+ mVariableModuleGlobal->VariableGlobal.VariableStoresCount /= sizeof (EFI_HANDLE);
+
+ for ( Index = 0;
+ Index < mVariableModuleGlobal->VariableGlobal.VariableStoresCount;
+ Index++) {
+ Status = gSmst->SmmHandleProtocol (
+ Handles[Index],
+ &gVariableStorageProtocolGuid,
+ (VOID **) &mVariableModuleGlobal->VariableGlobal.VariableStores[Index]
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ FreePool (Handles);
+ return Status;
+ }
+ }
+ FreePool (Handles);
+ }
+
+ //
+ // Variable initialize.
+ //
+ Status = VariableCommonInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the Smm Variable Protocol on a new handle.
+ //
+ VariableHandle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &VariableHandle,
+ &gEfiSmmVariableProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gSmmVariable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gSmst->SmmInstallProtocolInterface (
+ &VariableHandle,
+ &gEdkiiSmmVarCheckProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmVarCheck
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mVariableBufferPayloadSize = GetNonVolatileMaxVariableSize () +
+ OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - GetVariableHeaderSize ();
+
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ mVariableBufferPayloadSize,
+ (VOID **)&mVariableBufferPayload
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SMM variable SMI handler
+ //
+ VariableHandle = NULL;
+ Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Notify the variable wrapper driver the variable service is ready
+ //
+ Status = SystemTable->BootServices->InstallProtocolInterface (
+ &mVariableHandle,
+ &gEfiSmmVariableProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gSmmVariable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmEndOfDxeCallback,
+ &SmmEndOfDxeRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
new file mode 100644
index 0000000000..d0cec98ae4
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
@@ -0,0 +1,114 @@
+## @file
+# Provides SMM variable service.
+#
+# This module installs SMM variable protocol into SMM protocol database,
+# which can be used by SMM driver, and installs SMM variable protocol
+# into BS protocol database, which can be used to notify the SMM Runtime
+# Dxe driver that the SMM variable service is ready.
+# This module should be used with SMM Runtime DXE module together. The
+# SMM Runtime DXE module would install variable arch protocol and variable
+# write arch protocol based on SMM variable module.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data and communicate buffer in SMM mode.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+# The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+# may not be modified without authorization. If platform fails to protect these resources,
+# the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableSmm
+ MODULE_UNI_FILE = VariableSmm.uni
+ FILE_GUID = 23A089B3-EED5-4ac5-B2AB-43E3298C2343
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ Variable.c
+ VariableSmm.c
+ VarCheck.c
+ Variable.h
+ VariableExLib.c
+ TcgMorLockSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseLib
+ SynchronizationLib
+ UefiLib
+ SmmServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ DxeServicesTableLib
+ HobLib
+ PcdLib
+ SmmMemLib
+ AuthVariableLib
+ VarCheckLib
+ VariableStorageSelectorLib
+
+[Protocols]
+ gVariableStorageProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid
+ gEfiSmmEndOfDxeProtocolGuid ## NOTIFY
+ gEdkiiSmmVarCheckProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiAuthenticatedVariableGuid
+ gEfiVariableGuid
+ gEfiGlobalVariableGuid
+ gEfiMemoryOverwriteControlDataGuid ## CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteRequestControlLockGuid ## PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+
+ gSmmVariableWriteGuid ## PRODUCES ## GUID # Install protocol
+ gEdkiiVarErrorFlagGuid ## CONSUMES ## GUID
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES
+ gSiPkgTokenSpaceGuid.PcdForceVolatileVariable ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # Variable statistic information
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES # Auto update PlatformLang/Lang
+
+[Depex]
+ gVariableStorageProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableSmmExtra.uni
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni
new file mode 100644
index 0000000000..79513cd49c
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni
new file mode 100644
index 0000000000..f4b74a363b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmExtra.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
new file mode 100644
index 0000000000..21ed15ed40
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -0,0 +1,1228 @@
+/** @file
+ Implement all four UEFI Runtime Variable services for the nonvolatile
+ and volatile storage space and install variable architecture protocol
+ based on SMM variable module.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
+ to receive data buffer. The size should be checked carefully.
+
+ InitCommunicateBuffer() is really function to check the variable data size.
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Variable.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/VarCheck.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Guid/EventGroup.h>
+#include <Guid/SmmVariableCommon.h>
+
+EFI_HANDLE mHandle = NULL;
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
+UINT8 *mVariableBuffer = NULL;
+UINT8 *mVariableBufferPhysical = NULL;
+UINTN mVariableBufferSize;
+UINTN mVariableBufferPayloadSize;
+EFI_LOCK mVariableServicesLock;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
+EDKII_VAR_CHECK_PROTOCOL mVarCheck;
+
+
+/**
+ SecureBoot Hook for SetVariable.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ );
+
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function that will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (Lock);
+ }
+}
+
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (Lock);
+ }
+}
+
+
+/**
+ Initialize the communicate buffer using DataSize and Function.
+
+ The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
+ DataSize.
+
+ Caution: This function may receive untrusted input.
+ The data size external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[out] DataPtr Points to the data in the communicate buffer.
+ @param[in] DataSize The data size to send to SMM.
+ @param[in] Function The function number to initialize the communicate header.
+
+ @retval EFI_INVALID_PARAMETER The data size is too big.
+ @retval EFI_SUCCESS Find the specified variable.
+
+**/
+EFI_STATUS
+InitCommunicateBuffer (
+ OUT VOID **DataPtr OPTIONAL,
+ IN UINTN DataSize,
+ IN UINTN Function
+ )
+{
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+
+
+ if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = Function;
+ if (DataPtr != NULL) {
+ *DataPtr = SmmVariableFunctionHeader->Data;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send the data in communicate buffer to SMM.
+
+ @param[in] DataSize This size of the function header and the data.
+
+ @retval EFI_SUCCESS Success is returned from the functin in SMM.
+ @retval Others Failure is returned from the function in SMM.
+
+**/
+EFI_STATUS
+SendCommunicateBuffer (
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+
+ CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+
+ return SmmVariableFunctionHeader->ReturnStatus;
+}
+
+
+/**
+ Mark a variable that will become read-only after leaving the DXE phase of execution.
+
+ @param[in] This The 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
+VariableLockRequestToLock (
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
+
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (VariableName);
+ VariableToLock = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (VariableToLock == NULL) {
+ ASSERT (VariableToLock != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid (&VariableToLock->Guid, VendorGuid);
+ VariableToLock->NameSize = VariableNameSize;
+ CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @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 for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @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 for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (Name);
+ CommVariableProperty = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (CommVariableProperty == NULL) {
+ ASSERT (CommVariableProperty != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid (&CommVariableProperty->Guid, Guid);
+ CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
+ CommVariableProperty->NameSize = VariableNameSize;
+ CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableNameSize;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (Name);
+ CommVariableProperty = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
+ Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (CommVariableProperty == NULL) {
+ ASSERT (CommVariableProperty != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid (&CommVariableProperty->Guid, Guid);
+ CommVariableProperty->NameSize = VariableNameSize;
+ CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ if (Status == EFI_SUCCESS) {
+ CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ This code finds variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[out] Attributes Attribute value of the variable found.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data Data pointer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Find the specified variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ UINTN TempDataSize;
+ UINTN VariableNameSize;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TempDataSize = *DataSize;
+ VariableNameSize = StrSize (VariableName);
+ SmmVariableHeader = NULL;
+
+ //
+ // If VariableName exceeds SMM payload limit. Return failure
+ //
+ if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
+ //
+ // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
+ //
+ TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
+ }
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
+
+ Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (SmmVariableHeader == NULL) {
+ ASSERT (SmmVariableHeader != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
+ SmmVariableHeader->DataSize = TempDataSize;
+ SmmVariableHeader->NameSize = VariableNameSize;
+ if (Attributes == NULL) {
+ SmmVariableHeader->Attributes = 0;
+ } else {
+ SmmVariableHeader->Attributes = *Attributes;
+ }
+ CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+ //
+ // Get data from SMM.
+ //
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // SMM CommBuffer DataSize can be a trimed value
+ // Only update DataSize when needed
+ //
+ *DataSize = SmmVariableHeader->DataSize;
+ }
+ if (Attributes != NULL) {
+ *Attributes = SmmVariableHeader->Attributes;
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Data != NULL) {
+ CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ This code Finds the Next available variable.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Find the specified variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
+ UINTN OutVariableNameSize;
+ UINTN InVariableNameSize;
+
+ if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OutVariableNameSize = *VariableNameSize;
+ InVariableNameSize = StrSize (VariableName);
+ SmmGetNextVariableName = NULL;
+
+ //
+ // If input string exceeds SMM payload limit. Return failure
+ //
+ if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
+ //
+ // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
+ //
+ OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
+ }
+ //
+ // Payload should be Guid + NameSize + MAX of Input & Output buffer
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
+
+ Status = InitCommunicateBuffer ((VOID **) &SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (SmmGetNextVariableName == NULL) {
+ ASSERT (SmmGetNextVariableName != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // SMM comm buffer->NameSize is buffer size for return string
+ //
+ SmmGetNextVariableName->NameSize = OutVariableNameSize;
+
+ CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
+ //
+ // Copy whole string
+ //
+ CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
+ if (OutVariableNameSize > InVariableNameSize) {
+ ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
+ }
+
+ //
+ // Send data to SMM
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+ //
+ // Get data from SMM.
+ //
+ if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // SMM CommBuffer NameSize can be a trimed value
+ // Only update VariableNameSize when needed
+ //
+ *VariableNameSize = SmmGetNextVariableName->NameSize;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
+ CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ This code sets variable in storage blocks (Volatile or Non-Volatile).
+
+ Caution: This function may receive untrusted input.
+ The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable found
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SUCCESS Set successfully.
+ @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_WRITE_PROTECTED Variable is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ UINTN VariableNameSize;
+
+ //
+ // Check input parameters.
+ //
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize != 0 && Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNameSize = StrSize (VariableName);
+ SmmVariableHeader = NULL;
+
+ //
+ // If VariableName or DataSize exceeds SMM payload limit. Return failure
+ //
+ if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
+ (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime(&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
+ //
+ PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
+ Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (SmmVariableHeader == NULL) {
+ ASSERT (SmmVariableHeader != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
+ SmmVariableHeader->DataSize = DataSize;
+ SmmVariableHeader->NameSize = VariableNameSize;
+ SmmVariableHeader->Attributes = Attributes;
+ CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
+ CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+ if (!EfiAtRuntime ()) {
+ if (!EFI_ERROR (Status)) {
+ SecureBootHook (
+ VariableName,
+ VendorGuid
+ );
+ }
+ }
+ return Status;
+}
+
+
+/**
+ This code 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 Pointer to the maximum size of the storage space available
+ for the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
+ for EFI variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
+ associated with the attributes specified.
+
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @retval EFI_SUCCESS Query successfully.
+ @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+RuntimeServiceQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
+
+ SmmQueryVariableInfo = NULL;
+
+ if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
+ //
+ PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
+ Status = InitCommunicateBuffer ((VOID **) &SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (SmmQueryVariableInfo == NULL) {
+ ASSERT (SmmQueryVariableInfo != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SmmQueryVariableInfo->Attributes = Attributes;
+
+ //
+ // Send data to SMM.
+ //
+ Status = SendCommunicateBuffer (PayloadSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
+ *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
+ *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ Exit Boot Services Event notification handler.
+
+ Notify SMM variable driver about the event.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+OnExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
+
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+}
+
+
+/**
+ On Ready To Boot Services Event notification handler.
+
+ Notify SMM variable driver about the event.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
+
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
+ EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
+}
+
+
+/**
+ This code gets variable payload size.
+
+ @param[out] VariablePayloadSize Output pointer to variable payload size.
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval Others Get unsuccessfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariablePayloadSize (
+ OUT UINTN *VariablePayloadSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+
+ SmmGetPayloadSize = NULL;
+ CommBuffer = NULL;
+
+ if(VariablePayloadSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+ //
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+ CommBuffer = AllocateZeroPool (CommSize);
+ if (CommBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
+ SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
+
+Done:
+ if (CommBuffer != NULL) {
+ FreePool (CommBuffer);
+ }
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
+}
+
+
+/**
+ Initialize variable service and install Variable Architectural protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmVariableReady (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate memory for variable communicate buffer.
+ //
+ Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
+ ASSERT_EFI_ERROR (Status);
+ mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
+ mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
+ ASSERT (mVariableBuffer != NULL);
+
+ //
+ // Save the buffer physical address used for SMM conmunication.
+ //
+ mVariableBufferPhysical = mVariableBuffer;
+
+ gRT->GetVariable = RuntimeServiceGetVariable;
+ gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
+ gRT->SetVariable = RuntimeServiceSetVariable;
+ gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
+
+ //
+ // Install the Variable Architectural Protocol on a new handle.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mVariableLock.RequestToLock = VariableLockRequestToLock;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVariableLockProtocolGuid,
+ &mVariableLock,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
+ mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;
+ mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEdkiiVarCheckProtocolGuid,
+ &mVarCheck,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ SMM Non-Volatile variable write service is ready notify event handler.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SmmVariableWriteReady (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *ProtocolOps;
+
+ //
+ // Check whether the protocol is installed or not.
+ //
+ Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiVariableWriteArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Variable Driver main entry point. The Variable driver places the 4 EFI
+ runtime services in the EFI System Table and installs arch protocols
+ for variable read and write services being available. It also registers
+ a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableSmmRuntimeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *SmmVariableRegistration;
+ VOID *SmmVariableWriteRegistration;
+ EFI_EVENT OnReadyToBootEvent;
+ EFI_EVENT ExitBootServiceEvent;
+ EFI_EVENT LegacyBootEvent;
+
+ EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
+
+ //
+ // Smm variable service is ready
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiSmmVariableProtocolGuid,
+ TPL_CALLBACK,
+ SmmVariableReady,
+ NULL,
+ &SmmVariableRegistration
+ );
+
+ //
+ // Smm Non-Volatile variable write service is ready
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gSmmVariableWriteGuid,
+ TPL_CALLBACK,
+ SmmVariableWriteReady,
+ NULL,
+ &SmmVariableWriteRegistration
+ );
+
+ //
+ // Register the event to reclaim variable for OS usage.
+ //
+ EfiCreateEventReadyToBootEx (
+ TPL_NOTIFY,
+ OnReadyToBoot,
+ NULL,
+ &OnReadyToBootEvent
+ );
+
+ //
+ // Register the event to inform SMM variable that it is at runtime.
+ //
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnExitBootServices,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &ExitBootServiceEvent
+ );
+
+ //
+ // Register the event to inform SMM variable that it is at runtime for legacy boot.
+ // Reuse OnExitBootServices() here.
+ //
+ EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ OnExitBootServices,
+ NULL,
+ &LegacyBootEvent
+ );
+
+ //
+ // Register the event to convert the pointer for runtime.
+ //
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VariableAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
new file mode 100644
index 0000000000..8741960dd1
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
@@ -0,0 +1,81 @@
+## @file
+# Runtime DXE part corresponding to SMM authenticated variable module.
+#
+# This module installs variable arch protocol and variable write arch protocol to provide
+# variable service. This module need work together with SMM authenticated variable module.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable data.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+# The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+# which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+# may not be modified without authorization. If platform fails to protect these resources,
+# the authentication service provided in this driver will be broken, and the behavior is undefined.
+#
+# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableSmmRuntimeDxe
+ MODULE_UNI_FILE = VariableSmmRuntimeDxe.uni
+ FILE_GUID = 9F7DCADE-11EA-448a-A46F-76E003657DD1
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VariableSmmRuntimeInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableAddressChangeEvent
+#
+
+[Sources]
+ VariableSmmRuntimeDxe.c
+ Measurement.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ DebugLib
+ UefiRuntimeLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ TpmMeasurementLib
+
+[Protocols]
+ gEfiVariableWriteArchProtocolGuid ## PRODUCES
+ gEfiVariableArchProtocolGuid ## PRODUCES
+ gEfiSmmCommunicationProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid
+ gEdkiiVariableLockProtocolGuid ## PRODUCES
+ gEdkiiVarCheckProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gSmmVariableWriteGuid
+ gEfiGlobalVariableGuid
+ gEfiImageSecurityDatabaseGuid
+
+[Depex]
+ gEfiSmmCommunicationProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VariableSmmRuntimeDxeExtra.uni
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni
new file mode 100644
index 0000000000..696a04fed3
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.uni
Binary files differ
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni
new file mode 100644
index 0000000000..721b8235ca
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SampleCode/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxeExtra.uni
Binary files differ