X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FVariable%2FRuntimeDxe%2FVariableSmmRuntimeDxe.c;h=2cf0ed32ae55bea2094e7bb578a60810c242dbc1;hp=982eea0f145ae40ef33166936edff14335e33d89;hb=bd85bf54c268204c7a698a96f3ccd96cd77952cd;hpb=d00ed85e0ab212b988458b2fe98f20cb295637ad
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
index 982eea0f14..2cf0ed32ae 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
@@ -1,17 +1,20 @@
/** @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.
-Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
-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
+ 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.
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ InitCommunicateBuffer() is really function to check the variable data size.
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
@@ -19,6 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include
#include
#include
+#include
+#include
#include
#include
@@ -27,22 +32,158 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include
#include
#include
-#include
#include
#include
#include
-#include
#include
-EFI_HANDLE mHandle = NULL;
+#include "PrivilegePolymorphic.h"
+#include "VariableParsing.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;
+VARIABLE_INFO_ENTRY *mVariableInfo = NULL;
+VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
+VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
+VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;
UINTN mVariableBufferSize;
+UINTN mVariableRuntimeHobCacheBufferSize;
+UINTN mVariableRuntimeNvCacheBufferSize;
+UINTN mVariableRuntimeVolatileCacheBufferSize;
+UINTN mVariableBufferPayloadSize;
+BOOLEAN mVariableRuntimeCachePendingUpdate;
+BOOLEAN mVariableRuntimeCacheReadLock;
+BOOLEAN mVariableAuthFormat;
+BOOLEAN mHobFlushComplete;
+EFI_LOCK mVariableServicesLock;
+EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
+EDKII_VAR_CHECK_PROTOCOL mVarCheck;
+
+/**
+ Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
+ Record their initial State when variable write service is ready.
+
+**/
+VOID
+EFIAPI
+RecordSecureBootPolicyVarData(
+ VOID
+ );
+
+/**
+ 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 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 Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (Lock);
+ }
+}
+
+/**
+ Return TRUE if ExitBootServices () has been called.
+
+ @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
+**/
+BOOLEAN
+AtRuntime (
+ VOID
+ )
+{
+ return EfiAtRuntime ();
+}
+
+/**
+ Initialize the variable cache buffer as an empty variable store.
+
+ @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
+ @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
+ buffer that is allocated. On output, the actual size of the buffer allocated.
+ If TotalVariableCacheSize is zero, a buffer will not be allocated and the
+ function will return with EFI_SUCCESS.
+
+ @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
+ @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
+
+**/
+EFI_STATUS
+InitVariableCache (
+ OUT VARIABLE_STORE_HEADER **VariableCacheBuffer,
+ IN OUT UINTN *TotalVariableCacheSize
+ )
+{
+ VARIABLE_STORE_HEADER *VariableCacheStorePtr;
+
+ if (TotalVariableCacheSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*TotalVariableCacheSize == 0) {
+ return EFI_SUCCESS;
+ }
+ if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));
+
+ //
+ // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
+ //
+ *VariableCacheBuffer = (VARIABLE_STORE_HEADER *) AllocateRuntimePages (
+ EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)
+ );
+ if (*VariableCacheBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ VariableCacheStorePtr = *VariableCacheBuffer;
+ SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF);
+ ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));
+ VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize;
+ VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;
+ VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY;
+
+ return EFI_SUCCESS;
+}
/**
Initialize the communicate buffer using DataSize and Function.
@@ -50,10 +191,13 @@ UINTN mVariableBufferSize;
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.
@@ -65,10 +209,10 @@ InitCommunicateBuffer (
IN UINTN Function
)
{
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
- SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ 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;
}
@@ -76,7 +220,7 @@ InitCommunicateBuffer (
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) {
@@ -93,8 +237,8 @@ InitCommunicateBuffer (
@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.
-
+ @retval Others Failure is returned from the function in SMM.
+
**/
EFI_STATUS
SendCommunicateBuffer (
@@ -103,9 +247,9 @@ SendCommunicateBuffer (
{
EFI_STATUS Status;
UINTN CommSize;
- EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ 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);
@@ -115,17 +259,652 @@ SendCommunicateBuffer (
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;
+ }
+ ASSERT (VariableToLock != NULL);
+
+ 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;
+ }
+ ASSERT (CommVariableProperty != NULL);
+
+ 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;
+ }
+ ASSERT (CommVariableProperty != NULL);
+
+ 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;
+}
+
+/**
+ Signals SMM to synchronize any pending variable updates with the runtime cache(s).
+
+**/
+VOID
+SyncRuntimeCache (
+ VOID
+ )
+{
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
+ //
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);
+
+ //
+ // Send data to SMM.
+ //
+ SendCommunicateBuffer (0);
+}
+
+/**
+ Check whether a SMI must be triggered to retrieve pending cache updates.
+
+ If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
+ will prevent the HOB cache from being used for future runtime cache hits.
+
+**/
+VOID
+CheckForRuntimeCacheSync (
+ VOID
+ )
+{
+ if (mVariableRuntimeCachePendingUpdate) {
+ SyncRuntimeCache ();
+ }
+ ASSERT (!mVariableRuntimeCachePendingUpdate);
+
+ //
+ // The HOB variable data may have finished being flushed in the runtime cache sync update
+ //
+ if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) {
+ if (!EfiAtRuntime ()) {
+ FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));
+ }
+ mVariableRuntimeHobCacheBuffer = NULL;
+ }
+}
+
+/**
+ Finds the given variable in a runtime cache variable store.
+
+ 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_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInRuntimeCache (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN TempDataSize;
+ VARIABLE_POINTER_TRACK RtPtrTrack;
+ VARIABLE_STORE_TYPE StoreType;
+ VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
+
+ Status = EFI_NOT_FOUND;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack));
+
+ //
+ // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
+ // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
+ // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
+ // cache read lock should always be free when entering this function.
+ //
+ ASSERT (!mVariableRuntimeCacheReadLock);
+
+ mVariableRuntimeCacheReadLock = TRUE;
+ CheckForRuntimeCacheSync ();
+
+ if (!mVariableRuntimeCachePendingUpdate) {
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.
+ // The index and attributes mapping must be kept in this order as FindVariable
+ // makes use of this mapping to implement search algorithm.
+ //
+ VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
+ VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
+ VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
+
+ for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {
+ if (VariableStoreList[StoreType] == NULL) {
+ continue;
+ }
+
+ RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
+ RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]);
+ RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);
+
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get data size
+ //
+ TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);
+ ASSERT (TempDataSize != 0);
+
+ if (*DataSize >= TempDataSize) {
+ if (Data == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);
+ if (Attributes != NULL) {
+ *Attributes = RtPtrTrack.CurrPtr->Attributes;
+ }
+
+ *DataSize = TempDataSize;
+
+ UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ *DataSize = TempDataSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+ }
+ }
+
+Done:
+ mVariableRuntimeCacheReadLock = FALSE;
+
+ return Status;
+}
+
+/**
+ Finds the given variable in a variable store in SMM.
+
+ 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_SUCCESS Found the specified variable.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND The specified variable could not be found.
+
+**/
+EFI_STATUS
+FindVariableInSmm (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ )
+{
+ 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;
+ }
+
+ //
+ // 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;
+ }
+ ASSERT (SmmVariableHeader != NULL);
+
+ 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:
+ 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;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (VariableName[0] == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+ Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);
+ } else {
+ Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);
+ }
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+ return Status;
+}
+
+/**
+ Finds the next available variable in a runtime cache variable store.
+
+ @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
+GetNextVariableNameInRuntimeCache (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarNameSize;
+ VARIABLE_HEADER *VariablePtr;
+ VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
+ // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
+ // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
+ // cache read lock should always be free when entering this function.
+ //
+ ASSERT (!mVariableRuntimeCacheReadLock);
+
+ CheckForRuntimeCacheSync ();
+
+ mVariableRuntimeCacheReadLock = TRUE;
+ if (!mVariableRuntimeCachePendingUpdate) {
+ //
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.
+ // The index and attributes mapping must be kept in this order as FindVariable
+ // makes use of this mapping to implement search algorithm.
+ //
+ VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
+ VariableStoreHeader[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
+ VariableStoreHeader[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
+
+ Status = VariableServiceGetNextVariableInternal (
+ VariableName,
+ VendorGuid,
+ VariableStoreHeader,
+ &VariablePtr,
+ mVariableAuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);
+ ASSERT (VarNameSize != 0);
+ if (VarNameSize <= *VariableNameSize) {
+ CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);
+ CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ }
+ }
+ mVariableRuntimeCacheReadLock = FALSE;
+
+ return Status;
+}
/**
- This code finds variable in storage blocks (Volatile or Non-Volatile).
+ Finds the next available variable in a SMM variable store.
+
+ @param[in, out] VariableNameSize Size of the variable name.
+ @param[in, out] VariableName Pointer to variable name.
+ @param[in, out] VendorGuid Variable Vendor Guid.
- @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.
@@ -133,71 +912,90 @@ SendCommunicateBuffer (
**/
EFI_STATUS
-EFIAPI
-RuntimeServiceGetVariable (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- OUT UINT32 *Attributes OPTIONAL,
- IN OUT UINTN *DataSize,
- OUT VOID *Data
+GetNextVariableNameInSmm (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
)
{
- EFI_STATUS Status;
- UINTN PayloadSize;
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
+ EFI_STATUS Status;
+ UINTN PayloadSize;
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
+ UINTN OutVariableNameSize;
+ UINTN InVariableNameSize;
- if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
- return EFI_INVALID_PARAMETER;
- }
+ OutVariableNameSize = *VariableNameSize;
+ InVariableNameSize = StrSize (VariableName);
+ SmmGetNextVariableName = NULL;
- if ((*DataSize != 0) && (Data == 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;
}
-
+
//
// 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) + StrSize (VariableName);
- Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
+ 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)) {
- return Status;
+ goto Done;
}
- ASSERT (SmmVariableHeader != NULL);
+ ASSERT (SmmGetNextVariableName != NULL);
- CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
- SmmVariableHeader->DataSize = *DataSize;
- SmmVariableHeader->NameSize = StrSize (VariableName);
- if (Attributes == NULL) {
- SmmVariableHeader->Attributes = 0;
- } else {
- SmmVariableHeader->Attributes = *Attributes;
+ //
+ // 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);
}
- CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
//
- // Send data to SMM.
+ // Send data to SMM
//
Status = SendCommunicateBuffer (PayloadSize);
//
// Get data from SMM.
//
- *DataSize = SmmVariableHeader->DataSize;
- if (Attributes != NULL) {
- *Attributes = SmmVariableHeader->Attributes;
+ 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)) {
- return Status;
+ goto Done;
}
- CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
+ CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
+ CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
+Done:
return Status;
}
-
/**
This code Finds the Next available variable.
@@ -219,44 +1017,34 @@ RuntimeServiceGetNextVariableName (
IN OUT EFI_GUID *VendorGuid
)
{
- EFI_STATUS Status;
- UINTN PayloadSize;
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
+ EFI_STATUS Status;
+ UINTN MaxLen;
+
+ Status = EFI_NOT_FOUND;
if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
return EFI_INVALID_PARAMETER;
}
-
- //
- // 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_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize;
- Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- ASSERT (SmmGetNextVariableName != NULL);
-
- SmmGetNextVariableName->NameSize = *VariableNameSize;
- CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
- CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize);
//
- // Send data to SMM
+ // Calculate the possible maximum length of name string, including the Null terminator.
//
- Status = SendCommunicateBuffer (PayloadSize);
+ MaxLen = *VariableNameSize / sizeof (CHAR16);
+ if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
+ //
+ // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
+ // follow spec to return EFI_INVALID_PARAMETER.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
- //
- // Get data from SMM.
- //
- *VariableNameSize = SmmGetNextVariableName->NameSize;
- if (EFI_ERROR (Status)) {
- return Status;
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+ Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);
+ } else {
+ Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);
}
-
- CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
- CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
return Status;
}
@@ -264,6 +1052,9 @@ RuntimeServiceGetNextVariableName (
/**
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
@@ -289,34 +1080,48 @@ RuntimeServiceSetVariable (
)
{
EFI_STATUS Status;
- UINTN PayloadSize;
+ 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) + StrSize (VariableName) + DataSize;
+ 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)) {
- return Status;
+ goto Done;
}
ASSERT (SmmVariableHeader != NULL);
CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
SmmVariableHeader->DataSize = DataSize;
- SmmVariableHeader->NameSize = StrSize (VariableName);
+ SmmVariableHeader->NameSize = VariableNameSize;
SmmVariableHeader->Attributes = Attributes;
CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
@@ -325,7 +1130,18 @@ RuntimeServiceSetVariable (
// Send data to SMM.
//
Status = SendCommunicateBuffer (PayloadSize);
-
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+
+ if (!EfiAtRuntime ()) {
+ if (!EFI_ERROR (Status)) {
+ SecureBootHook (
+ VariableName,
+ VendorGuid
+ );
+ }
+ }
return Status;
}
@@ -360,10 +1176,14 @@ RuntimeServiceQueryVariableInfo (
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;
@@ -371,7 +1191,7 @@ RuntimeServiceQueryVariableInfo (
PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Done;
}
ASSERT (SmmQueryVariableInfo != NULL);
@@ -382,7 +1202,7 @@ RuntimeServiceQueryVariableInfo (
//
Status = SendCommunicateBuffer (PayloadSize);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Done;
}
//
@@ -390,9 +1210,11 @@ RuntimeServiceQueryVariableInfo (
//
*MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
*MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
- *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
-
- return EFI_SUCCESS;
+ *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
}
@@ -416,7 +1238,7 @@ OnExitBootServices (
// 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);
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
//
// Send data to SMM.
@@ -446,11 +1268,24 @@ OnReadyToBoot (
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
//
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
-
+
//
// Send data to SMM.
//
SendCommunicateBuffer (0);
+
+ //
+ // Install the system configuration table for variable info data captured
+ //
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {
+ if (mVariableAuthFormat) {
+ gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);
+ } else {
+ gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);
+ }
+ }
+
+ gBS->CloseEvent (Event);
}
@@ -473,15 +1308,244 @@ VariableAddressChangeEvent (
{
EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);
+}
+
+/**
+ 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;
+}
+
+/**
+ This code gets information needed from SMM for runtime cache initialization.
+
+ @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
+ @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
+ @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
+ @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
+
+ @retval EFI_SUCCESS Retrieved the size successfully.
+ @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
+ @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
+ @retval Others Could not retrieve the size successfully.
+
+**/
+EFI_STATUS
+GetRuntimeCacheInfo (
+ OUT UINTN *TotalHobStorageSize,
+ OUT UINTN *TotalNvStorageSize,
+ OUT UINTN *TotalVolatileStorageSize,
+ OUT BOOLEAN *AuthenticatedVariableUsage
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+
+ SmmGetRuntimeCacheInfo = NULL;
+ CommBuffer = mVariableBuffer;
+
+ if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CommBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
+ ZeroMem (CommBuffer, CommSize);
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;
+ SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;
+ *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;
+ *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;
+ *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;
+
+Done:
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
+ return Status;
}
+/**
+ Sends the runtime variable cache context information to SMM.
+
+ @retval EFI_SUCCESS Retrieved the size successfully.
+ @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
+ @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
+ @retval Others Could not retrieve the size successfully.;
+
+**/
+EFI_STATUS
+SendRuntimeVariableCacheContextToSmm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+
+ SmmRuntimeVarCacheContext = NULL;
+ CommBuffer = mVariableBuffer;
+
+ if (CommBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);
+
+ //
+ // Init the communicate buffer. The buffer data size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+ //
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+ ZeroMem (CommBuffer, CommSize);
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;
+ SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;
+
+ SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;
+ SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;
+ SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;
+ SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;
+ SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;
+ SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ 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
@@ -492,19 +1556,20 @@ SmmVariableReady (
{
EFI_STATUS Status;
- Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
+ 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 store.
+ // Allocate memory for variable communicate buffer.
//
- mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
- mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
+ Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
+ ASSERT_EFI_ERROR (Status);
+ mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
ASSERT (mVariableBuffer != NULL);
@@ -513,21 +1578,79 @@ SmmVariableReady (
//
mVariableBufferPhysical = mVariableBuffer;
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
+ DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));
+ //
+ // Allocate runtime variable cache memory buffers.
+ //
+ Status = GetRuntimeCacheInfo (
+ &mVariableRuntimeHobCacheBufferSize,
+ &mVariableRuntimeNvCacheBufferSize,
+ &mVariableRuntimeVolatileCacheBufferSize,
+ &mVariableAuthFormat
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);
+ if (!EFI_ERROR (Status)) {
+ Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);
+ if (!EFI_ERROR (Status)) {
+ Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);
+ if (!EFI_ERROR (Status)) {
+ Status = SendRuntimeVariableCacheContextToSmm ();
+ if (!EFI_ERROR (Status)) {
+ SyncRuntimeCache ();
+ }
+ }
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ mVariableRuntimeHobCacheBuffer = NULL;
+ mVariableRuntimeNvCacheBuffer = NULL;
+ mVariableRuntimeVolatileCacheBuffer = NULL;
+ }
+ }
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));
+ }
+
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,
+ &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);
}
@@ -536,7 +1659,7 @@ SmmVariableReady (
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
-
+
**/
VOID
EFIAPI
@@ -555,26 +1678,34 @@ SmmVariableWriteReady (
if (EFI_ERROR (Status)) {
return;
}
-
+
+ //
+ // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
+ // Secure Boot Policy Variable change. Record their initial value.
+ //
+ RecordSecureBootPolicyVarData();
+
Status = gBS->InstallProtocolInterface (
&mHandle,
- &gEfiVariableWriteArchProtocolGuid,
+ &gEfiVariableWriteArchProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
- ASSERT_EFI_ERROR (Status);
+ 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
+ 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] 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.
**/
@@ -589,15 +1720,18 @@ VariableSmmRuntimeInitialize (
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,
+ &gEfiSmmVariableProtocolGuid,
+ TPL_CALLBACK,
+ SmmVariableReady,
+ NULL,
&SmmVariableRegistration
);
@@ -605,10 +1739,10 @@ VariableSmmRuntimeInitialize (
// Smm Non-Volatile variable write service is ready
//
EfiCreateProtocolNotifyEvent (
- &gSmmVariableWriteGuid,
- TPL_CALLBACK,
- SmmVariableWriteReady,
- NULL,
+ &gSmmVariableWriteGuid,
+ TPL_CALLBACK,
+ SmmVariableWriteReady,
+ NULL,
&SmmVariableWriteRegistration
);
@@ -616,11 +1750,11 @@ VariableSmmRuntimeInitialize (
// Register the event to reclaim variable for OS usage.
//
EfiCreateEventReadyToBootEx (
- TPL_NOTIFY,
- OnReadyToBoot,
- NULL,
+ TPL_NOTIFY,
+ OnReadyToBoot,
+ NULL,
&OnReadyToBootEvent
- );
+ );
//
// Register the event to inform SMM variable that it is at runtime.
@@ -632,7 +1766,18 @@ VariableSmmRuntimeInitialize (
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.
@@ -645,7 +1790,7 @@ VariableSmmRuntimeInitialize (
&gEfiEventVirtualAddressChangeGuid,
&mVirtualAddressChangeEvent
);
-
+
return EFI_SUCCESS;
}