/** @file\r
The file defined some common structures used for communicating between SMM variable module and SMM variable wrapper module.\r
\r
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
#ifndef _SMM_VARIABLE_COMMON_H_\r
#define _SMM_VARIABLE_COMMON_H_\r
\r
+#include <Guid/VariableFormat.h>\r
#include <Protocol/VarCheck.h>\r
\r
#define EFI_SMM_VARIABLE_WRITE_GUID \\r
#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10\r
\r
#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11\r
+//\r
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT\r
+//\r
+#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12\r
+\r
+#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13\r
+//\r
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO\r
+//\r
+#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14\r
\r
///\r
/// Size of SMM communicate header, without including the payload.\r
UINTN VariablePayloadSize;\r
} SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE;\r
\r
+typedef struct {\r
+ BOOLEAN *ReadLock;\r
+ BOOLEAN *PendingUpdate;\r
+ BOOLEAN *HobFlushComplete;\r
+ VARIABLE_STORE_HEADER *RuntimeHobCache;\r
+ VARIABLE_STORE_HEADER *RuntimeNvCache;\r
+ VARIABLE_STORE_HEADER *RuntimeVolatileCache;\r
+} SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT;\r
+\r
+typedef struct {\r
+ UINTN TotalHobStorageSize;\r
+ UINTN TotalNvStorageSize;\r
+ UINTN TotalVolatileStorageSize;\r
+ BOOLEAN AuthenticatedVariableUsage;\r
+} SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO;\r
+\r
#endif // _SMM_VARIABLE_COMMON_H_\r
# @Prompt Enable Device Path From Text support.\r
gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText|TRUE|BOOLEAN|0x00010038\r
\r
+ ## Indicates if the UEFI variable runtime cache should be enabled.\r
+ # This setting only applies if SMM variables are enabled. When enabled, all variable\r
+ # data for Runtime Service GetVariable () and GetNextVariableName () calls is retrieved\r
+ # from a runtime data buffer referred to as the "runtime cache". An SMI is not triggered\r
+ # at all for these requests. Variables writes still trigger an SMI. This can greatly\r
+ # reduce overall system SMM usage as most boots tend to issue far more variable reads\r
+ # than writes.<BR><BR>\r
+ # TRUE - The UEFI variable runtime cache is enabled.<BR>\r
+ # FALSE - The UEFI variable runtime cache is disabled.<BR>\r
+ # @Prompt Enable the UEFI variable runtime cache.\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache|FALSE|BOOLEAN|0x00010039\r
+\r
## Indicates if the statistics about variable usage will be collected. This information is\r
# stored as a vendor configuration table into the EFI system table.\r
# Set this PCD to TRUE to use VariableInfo application in MdeModulePkg\Application directory to get\r
#include "Variable.h"\r
#include "VariableNonVolatile.h"\r
#include "VariableParsing.h"\r
+#include "VariableRuntimeCache.h"\r
\r
VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
\r
// Update the data in NV cache.\r
//\r
*VarErrFlag = TempFlag;\r
+ Status = SynchronizeRuntimeVariableCache (\r
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,\r
+ (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+ sizeof (TempFlag)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
}\r
}\r
\r
Done:\r
if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
+ Status = SynchronizeRuntimeVariableCache (\r
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,\r
+ 0,\r
+ VariableStoreHeader->Size\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
FreePool (ValidBuffer);\r
} else {\r
//\r
// For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.\r
//\r
- CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
+ CopyMem (mNvVariableCache, (UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size);\r
+ Status = SynchronizeRuntimeVariableCache (\r
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,\r
+ 0,\r
+ VariableStoreHeader->Size\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
\r
return Status;\r
VARIABLE_POINTER_TRACK *Variable;\r
VARIABLE_POINTER_TRACK NvVariable;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;\r
UINT8 *BufferForMerge;\r
UINTN MergedBufSize;\r
BOOLEAN DataReady;\r
}\r
\r
Done:\r
+ if (!EFI_ERROR (Status)) {\r
+ if (Variable->Volatile) {\r
+ VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);\r
+ } else {\r
+ VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);\r
+ }\r
+\r
+ if (VolatileCacheInstance->Store != NULL) {\r
+ Status = SynchronizeRuntimeVariableCache (\r
+ VolatileCacheInstance,\r
+ 0,\r
+ VolatileCacheInstance->Store->Size\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
return Status;\r
}\r
\r
ErrorFlag = TRUE;\r
}\r
}\r
+ if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store != NULL) {\r
+ Status = SynchronizeRuntimeVariableCache (\r
+ &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,\r
+ 0,\r
+ mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store->Size\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
if (ErrorFlag) {\r
//\r
// We still have HOB variable(s) not flushed in flash.\r
// All HOB variables have been flushed in flash.\r
//\r
DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
+ if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete != NULL) {\r
+ *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = TRUE;\r
+ }\r
if (!AtRuntime ()) {\r
FreePool ((VOID *) VariableStoreHeader);\r
}\r
VariableStoreTypeMax\r
} VARIABLE_STORE_TYPE;\r
\r
+typedef struct {\r
+ UINT32 PendingUpdateOffset;\r
+ UINT32 PendingUpdateLength;\r
+ VARIABLE_STORE_HEADER *Store;\r
+} VARIABLE_RUNTIME_CACHE;\r
+\r
+typedef struct {\r
+ BOOLEAN *ReadLock;\r
+ BOOLEAN *PendingUpdate;\r
+ BOOLEAN *HobFlushComplete;\r
+ VARIABLE_RUNTIME_CACHE VariableRuntimeHobCache;\r
+ VARIABLE_RUNTIME_CACHE VariableRuntimeNvCache;\r
+ VARIABLE_RUNTIME_CACHE VariableRuntimeVolatileCache;\r
+} VARIABLE_RUNTIME_CACHE_CONTEXT;\r
+\r
typedef struct {\r
VARIABLE_HEADER *CurrPtr;\r
//\r
} VARIABLE_POINTER_TRACK;\r
\r
typedef struct {\r
- EFI_PHYSICAL_ADDRESS HobVariableBase;\r
- EFI_PHYSICAL_ADDRESS VolatileVariableBase;\r
- EFI_PHYSICAL_ADDRESS NonVolatileVariableBase;\r
- EFI_LOCK VariableServicesLock;\r
- UINT32 ReentrantState;\r
- BOOLEAN AuthFormat;\r
- BOOLEAN AuthSupport;\r
- BOOLEAN EmuNvMode;\r
+ EFI_PHYSICAL_ADDRESS HobVariableBase;\r
+ EFI_PHYSICAL_ADDRESS VolatileVariableBase;\r
+ EFI_PHYSICAL_ADDRESS NonVolatileVariableBase;\r
+ VARIABLE_RUNTIME_CACHE_CONTEXT VariableRuntimeCacheContext;\r
+ EFI_LOCK VariableServicesLock;\r
+ UINT32 ReentrantState;\r
+ BOOLEAN AuthFormat;\r
+ BOOLEAN AuthSupport;\r
+ BOOLEAN EmuNvMode;\r
} VARIABLE_GLOBAL;\r
\r
typedef struct {\r
--- /dev/null
+/** @file\r
+ Functions related to managing the UEFI variable runtime cache. This file should only include functions\r
+ used by the SMM UEFI variable driver.\r
+\r
+ Caution: This module requires additional review when modified.\r
+ This driver will have external input - variable data. They may be input in SMM mode.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "VariableParsing.h"\r
+#include "VariableRuntimeCache.h"\r
+\r
+extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
+extern VARIABLE_STORE_HEADER *mNvVariableCache;\r
+\r
+/**\r
+ Copies any pending updates to runtime variable caches.\r
+\r
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.\r
+ @retval EFI_SUCCESS The volatile store was updated successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+FlushPendingRuntimeVariableCacheUpdates (\r
+ VOID\r
+ )\r
+{\r
+ VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext;\r
+\r
+ VariableRuntimeCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;\r
+\r
+ if (VariableRuntimeCacheContext->VariableRuntimeNvCache.Store == NULL ||\r
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store == NULL ||\r
+ VariableRuntimeCacheContext->PendingUpdate == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (*(VariableRuntimeCacheContext->PendingUpdate)) {\r
+ if (VariableRuntimeCacheContext->VariableRuntimeHobCache.Store != NULL &&\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {\r
+ CopyMem (\r
+ (VOID *) (\r
+ ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeHobCache.Store) +\r
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset\r
+ ),\r
+ (VOID *) (\r
+ ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase) +\r
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset\r
+ ),\r
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength\r
+ );\r
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;\r
+ VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;\r
+ }\r
+\r
+ CopyMem (\r
+ (VOID *) (\r
+ ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeNvCache.Store) +\r
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset\r
+ ),\r
+ (VOID *) (\r
+ ((UINT8 *) (UINTN) mNvVariableCache) +\r
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset\r
+ ),\r
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength\r
+ );\r
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength = 0;\r
+ VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;\r
+\r
+ CopyMem (\r
+ (VOID *) (\r
+ ((UINT8 *) (UINTN) VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store) +\r
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset\r
+ ),\r
+ (VOID *) (\r
+ ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase) +\r
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset\r
+ ),\r
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength\r
+ );\r
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = 0;\r
+ VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;\r
+ *(VariableRuntimeCacheContext->PendingUpdate) = FALSE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Synchronizes the runtime variable caches with all pending updates outside runtime.\r
+\r
+ Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt\r
+ to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the\r
+ update is added as a pending update for the given variable store and it will be flushed to the runtime cache\r
+ at the next opportunity the ReadLock is available.\r
+\r
+ @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized.\r
+ @param[in] Offset Offset in bytes to apply the update.\r
+ @param[in] Length Length of data in bytes of the update.\r
+\r
+ @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime\r
+ cache ReadLock was available, the runtime cache was updated successfully.\r
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.\r
+\r
+**/\r
+EFI_STATUS\r
+SynchronizeRuntimeVariableCache (\r
+ IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache,\r
+ IN UINTN Offset,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ if (VariableRuntimeCache == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (VariableRuntimeCache->Store == NULL) {\r
+ // The runtime cache may not be active or allocated yet.\r
+ // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_YET.\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate == NULL ||\r
+ mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) &&\r
+ VariableRuntimeCache->PendingUpdateLength > 0) {\r
+ VariableRuntimeCache->PendingUpdateLength =\r
+ (UINT32) (\r
+ MAX (\r
+ (UINTN) (VariableRuntimeCache->PendingUpdateOffset + VariableRuntimeCache->PendingUpdateLength),\r
+ Offset + Length\r
+ ) - MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset)\r
+ );\r
+ VariableRuntimeCache->PendingUpdateOffset =\r
+ (UINT32) MIN ((UINTN) VariableRuntimeCache->PendingUpdateOffset, Offset);\r
+ } else {\r
+ VariableRuntimeCache->PendingUpdateLength = (UINT32) Length;\r
+ VariableRuntimeCache->PendingUpdateOffset = (UINT32) Offset;\r
+ }\r
+ *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) = TRUE;\r
+\r
+ if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock) == FALSE) {\r
+ return FlushPendingRuntimeVariableCacheUpdates ();\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ The common variable volatile store routines shared by the DXE_RUNTIME variable\r
+ module and the DXE_SMM variable module.\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef _VARIABLE_RUNTIME_CACHE_H_\r
+#define _VARIABLE_RUNTIME_CACHE_H_\r
+\r
+#include "Variable.h"\r
+\r
+/**\r
+ Copies any pending updates to runtime variable caches.\r
+\r
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.\r
+ @retval EFI_SUCCESS The volatile store was updated successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+FlushPendingRuntimeVariableCacheUpdates (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Synchronizes the runtime variable caches with all pending updates outside runtime.\r
+\r
+ Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt\r
+ to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the\r
+ update is added as a pending update for the given variable store and it will be flushed to the runtime cache\r
+ at the next opportunity the ReadLock is available.\r
+\r
+ @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized.\r
+ @param[in] Offset Offset in bytes to apply the update.\r
+ @param[in] Length Length of data in bytes of the update.\r
+\r
+ @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime\r
+ cache ReadLock was available, the runtime cache was updated successfully.\r
+ @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly.\r
+\r
+**/\r
+EFI_STATUS\r
+SynchronizeRuntimeVariableCache (\r
+ IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache,\r
+ IN UINTN Offset,\r
+ IN UINTN Length\r
+ );\r
+\r
+#endif\r
VariableNonVolatile.h\r
VariableParsing.c\r
VariableParsing.h\r
+ VariableRuntimeCache.c\r
+ VariableRuntimeCache.h\r
PrivilegePolymorphic.h\r
Measurement.c\r
TcgMorLockDxe.c\r
#include <Guid/SmmVariableCommon.h>\r
#include "Variable.h"\r
#include "VariableParsing.h"\r
+#include "VariableRuntimeCache.h"\r
+\r
+extern VARIABLE_STORE_HEADER *mNvVariableCache;\r
\r
BOOLEAN mAtRuntime = FALSE;\r
UINT8 *mVariableBufferPayload = NULL;\r
EFI_STATUS\r
EFIAPI\r
SmmVariableHandler (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN CONST VOID *RegisterContext,\r
- IN OUT VOID *CommBuffer,\r
- IN OUT UINTN *CommBufferSize\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *RegisterContext,\r
+ IN OUT VOID *CommBuffer,\r
+ IN OUT UINTN *CommBufferSize\r
)\r
{\r
- EFI_STATUS Status;\r
- SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
- SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;\r
- SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;\r
- SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize;\r
- VARIABLE_INFO_ENTRY *VariableInfo;\r
- SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;\r
- SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
- UINTN InfoSize;\r
- UINTN NameBufferSize;\r
- UINTN CommBufferPayloadSize;\r
- UINTN TempCommBufferSize;\r
+ EFI_STATUS Status;\r
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
+ SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;\r
+ SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;\r
+ SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize;\r
+ SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *RuntimeVariableCacheContext;\r
+ SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *GetRuntimeCacheInfo;\r
+ SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;\r
+ SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
+ VARIABLE_INFO_ENTRY *VariableInfo;\r
+ VARIABLE_RUNTIME_CACHE_CONTEXT *VariableCacheContext;\r
+ VARIABLE_STORE_HEADER *VariableCache;\r
+ UINTN InfoSize;\r
+ UINTN NameBufferSize;\r
+ UINTN CommBufferPayloadSize;\r
+ UINTN TempCommBufferSize;\r
\r
//\r
// If input is invalid, stop processing this SMI\r
);\r
CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);\r
break;\r
+ case SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT:\r
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM communication buffer size invalid!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+ if (mEndOfDxe) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init context after end of DXE!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Copy the input communicate buffer payload to the pre-allocated SMM variable payload buffer.\r
+ //\r
+ CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
+ RuntimeVariableCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) mVariableBufferPayload;\r
+\r
+ //\r
+ // Verify required runtime cache buffers are provided.\r
+ //\r
+ if (RuntimeVariableCacheContext->RuntimeVolatileCache == NULL ||\r
+ RuntimeVariableCacheContext->RuntimeNvCache == NULL ||\r
+ RuntimeVariableCacheContext->PendingUpdate == NULL ||\r
+ RuntimeVariableCacheContext->ReadLock == NULL ||\r
+ RuntimeVariableCacheContext->HobFlushComplete == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required runtime cache buffer is NULL!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Verify minimum size requirements for the runtime variable store buffers.\r
+ //\r
+ if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL &&\r
+ RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof (VARIABLE_STORE_HEADER)) ||\r
+ RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof (VARIABLE_STORE_HEADER) ||\r
+ RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof (VARIABLE_STORE_HEADER)) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime cache buffer size is invalid!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Verify runtime buffers do not overlap with SMRAM ranges.\r
+ //\r
+ if (RuntimeVariableCacheContext->RuntimeHobCache != NULL &&\r
+ !VariableSmmIsBufferOutsideSmmValid (\r
+ (UINTN) RuntimeVariableCacheContext->RuntimeHobCache,\r
+ (UINTN) RuntimeVariableCacheContext->RuntimeHobCache->Size)) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime HOB cache buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+ if (!VariableSmmIsBufferOutsideSmmValid (\r
+ (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache,\r
+ (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache->Size)) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime volatile cache buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+ if (!VariableSmmIsBufferOutsideSmmValid (\r
+ (UINTN) RuntimeVariableCacheContext->RuntimeNvCache,\r
+ (UINTN) RuntimeVariableCacheContext->RuntimeNvCache->Size)) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime non-volatile cache buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+ if (!VariableSmmIsBufferOutsideSmmValid (\r
+ (UINTN) RuntimeVariableCacheContext->PendingUpdate,\r
+ sizeof (*(RuntimeVariableCacheContext->PendingUpdate)))) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache pending update buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+ if (!VariableSmmIsBufferOutsideSmmValid (\r
+ (UINTN) RuntimeVariableCacheContext->ReadLock,\r
+ sizeof (*(RuntimeVariableCacheContext->ReadLock)))) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache read lock buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+ if (!VariableSmmIsBufferOutsideSmmValid (\r
+ (UINTN) RuntimeVariableCacheContext->HobFlushComplete,\r
+ sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)))) {\r
+ DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache HOB flush complete buffer in SMRAM or overflow!\n"));\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto EXIT;\r
+ }\r
+\r
+ VariableCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;\r
+ VariableCacheContext->VariableRuntimeHobCache.Store = RuntimeVariableCacheContext->RuntimeHobCache;\r
+ VariableCacheContext->VariableRuntimeVolatileCache.Store = RuntimeVariableCacheContext->RuntimeVolatileCache;\r
+ VariableCacheContext->VariableRuntimeNvCache.Store = RuntimeVariableCacheContext->RuntimeNvCache;\r
+ VariableCacheContext->PendingUpdate = RuntimeVariableCacheContext->PendingUpdate;\r
+ VariableCacheContext->ReadLock = RuntimeVariableCacheContext->ReadLock;\r
+ VariableCacheContext->HobFlushComplete = RuntimeVariableCacheContext->HobFlushComplete;\r
+\r
+ // Set up the intial pending request since the RT cache needs to be in sync with SMM cache\r
+ VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;\r
+ VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0 &&\r
+ VariableCacheContext->VariableRuntimeHobCache.Store != NULL) {\r
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
+ VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);\r
+ CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store->Signature), &(VariableCache->Signature));\r
+ }\r
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
+ VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;\r
+ VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);\r
+ CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Store->Signature), &(VariableCache->Signature));\r
+\r
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;\r
+ VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;\r
+ VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);\r
+ CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store->Signature), &(VariableCache->Signature));\r
+\r
+ *(VariableCacheContext->PendingUpdate) = TRUE;\r
+ *(VariableCacheContext->ReadLock) = FALSE;\r
+ *(VariableCacheContext->HobFlushComplete) = FALSE;\r
+\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE:\r
+ Status = FlushPendingRuntimeVariableCacheUpdates ();\r
+ break;\r
+ case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO:\r
+ if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) {\r
+ DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication buffer size invalid!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ GetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;\r
+\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {\r
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
+ GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size;\r
+ } else {\r
+ GetRuntimeCacheInfo->TotalHobStorageSize = 0;\r
+ }\r
+\r
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
+ GetRuntimeCacheInfo->TotalVolatileStorageSize = VariableCache->Size;\r
+ VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;\r
+ GetRuntimeCacheInfo->TotalNvStorageSize = (UINTN) VariableCache->Size;\r
+ GetRuntimeCacheInfo->AuthenticatedVariableUsage = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
+\r
+ Status = EFI_SUCCESS;\r
+ break;\r
\r
default:\r
Status = EFI_UNSUPPORTED;\r
VariableNonVolatile.h\r
VariableParsing.c\r
VariableParsing.h\r
+ VariableRuntimeCache.c\r
+ VariableRuntimeCache.h\r
VarCheck.c\r
Variable.h\r
PrivilegePolymorphic.h\r
\r
InitCommunicateBuffer() is really function to check the variable data size.\r
\r
-Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
#include <Guid/SmmVariableCommon.h>\r
\r
#include "PrivilegePolymorphic.h"\r
+#include "VariableParsing.h"\r
\r
EFI_HANDLE mHandle = NULL;\r
EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r
EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
UINT8 *mVariableBuffer = NULL;\r
UINT8 *mVariableBufferPhysical = NULL;\r
+VARIABLE_INFO_ENTRY *mVariableInfo = NULL;\r
+VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;\r
+VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;\r
+VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;\r
UINTN mVariableBufferSize;\r
+UINTN mVariableRuntimeHobCacheBufferSize;\r
+UINTN mVariableRuntimeNvCacheBufferSize;\r
+UINTN mVariableRuntimeVolatileCacheBufferSize;\r
UINTN mVariableBufferPayloadSize;\r
+BOOLEAN mVariableRuntimeCachePendingUpdate;\r
+BOOLEAN mVariableRuntimeCacheReadLock;\r
+BOOLEAN mVariableAuthFormat;\r
+BOOLEAN mHobFlushComplete;\r
EFI_LOCK mVariableServicesLock;\r
EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;\r
EDKII_VAR_CHECK_PROTOCOL mVarCheck;\r
}\r
}\r
\r
+/**\r
+ Return TRUE if ExitBootServices () has been called.\r
+\r
+ @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+ VOID\r
+ )\r
+{\r
+ return EfiAtRuntime ();\r
+}\r
+\r
+/**\r
+ Initialize the variable cache buffer as an empty variable store.\r
+\r
+ @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.\r
+ @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache\r
+ buffer that is allocated. On output, the actual size of the buffer allocated.\r
+ If TotalVariableCacheSize is zero, a buffer will not be allocated and the\r
+ function will return with EFI_SUCCESS.\r
+\r
+ @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.\r
+ @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.\r
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+InitVariableCache (\r
+ OUT VARIABLE_STORE_HEADER **VariableCacheBuffer,\r
+ IN OUT UINTN *TotalVariableCacheSize\r
+ )\r
+{\r
+ VARIABLE_STORE_HEADER *VariableCacheStorePtr;\r
+\r
+ if (TotalVariableCacheSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (*TotalVariableCacheSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));\r
+\r
+ //\r
+ // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)\r
+ //\r
+ *VariableCacheBuffer = (VARIABLE_STORE_HEADER *) AllocateRuntimePages (\r
+ EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)\r
+ );\r
+ if (*VariableCacheBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ VariableCacheStorePtr = *VariableCacheBuffer;\r
+ SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF);\r
+\r
+ ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));\r
+ VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize;\r
+ VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;\r
+ VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Initialize the communicate buffer using DataSize and Function.\r
\r
}\r
\r
/**\r
- This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+ Signals SMM to synchronize any pending variable updates with the runtime cache(s).\r
+\r
+**/\r
+VOID\r
+SyncRuntimeCache (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Init the communicate buffer. The buffer data size is:\r
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
+ //\r
+ InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ SendCommunicateBuffer (0);\r
+}\r
+\r
+/**\r
+ Check whether a SMI must be triggered to retrieve pending cache updates.\r
+\r
+ If the variable HOB was finished being flushed since the last check for a runtime cache update, this function\r
+ will prevent the HOB cache from being used for future runtime cache hits.\r
+\r
+**/\r
+VOID\r
+CheckForRuntimeCacheSync (\r
+ VOID\r
+ )\r
+{\r
+ if (mVariableRuntimeCachePendingUpdate) {\r
+ SyncRuntimeCache ();\r
+ }\r
+ ASSERT (!mVariableRuntimeCachePendingUpdate);\r
+\r
+ //\r
+ // The HOB variable data may have finished being flushed in the runtime cache sync update\r
+ //\r
+ if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) {\r
+ if (!EfiAtRuntime ()) {\r
+ FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));\r
+ }\r
+ mVariableRuntimeHobCacheBuffer = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Finds the given variable in a runtime cache variable store.\r
\r
Caution: This function may receive untrusted input.\r
The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
data, this value contains the required size.\r
@param[out] Data Data pointer.\r
\r
+ @retval EFI_SUCCESS Found the specified variable.\r
@retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_SUCCESS Find the specified variable.\r
- @retval EFI_NOT_FOUND Not found.\r
- @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
+ @retval EFI_NOT_FOUND The specified variable could not be found.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-RuntimeServiceGetVariable (\r
+FindVariableInRuntimeCache (\r
IN CHAR16 *VariableName,\r
IN EFI_GUID *VendorGuid,\r
OUT UINT32 *Attributes OPTIONAL,\r
IN OUT UINTN *DataSize,\r
- OUT VOID *Data\r
+ OUT VOID *Data OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN TempDataSize;\r
+ VARIABLE_POINTER_TRACK RtPtrTrack;\r
+ VARIABLE_STORE_TYPE StoreType;\r
+ VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
+ // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
+ // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
+ // cache read lock should always be free when entering this function.\r
+ //\r
+ ASSERT (!mVariableRuntimeCacheReadLock);\r
+\r
+ mVariableRuntimeCacheReadLock = TRUE;\r
+ CheckForRuntimeCacheSync ();\r
+\r
+ if (!mVariableRuntimeCachePendingUpdate) {\r
+ //\r
+ // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
+ // The index and attributes mapping must be kept in this order as FindVariable\r
+ // makes use of this mapping to implement search algorithm.\r
+ //\r
+ VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
+ VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;\r
+ VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;\r
+\r
+ for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {\r
+ if (VariableStoreList[StoreType] == NULL) {\r
+ continue;\r
+ }\r
+\r
+ RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);\r
+ RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]);\r
+ RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);\r
+\r
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get data size\r
+ //\r
+ TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);\r
+ ASSERT (TempDataSize != 0);\r
+\r
+ if (*DataSize >= TempDataSize) {\r
+ if (Data == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);\r
+ if (Attributes != NULL) {\r
+ *Attributes = RtPtrTrack.CurrPtr->Attributes;\r
+ }\r
+\r
+ *DataSize = TempDataSize;\r
+\r
+ UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);\r
+\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ } else {\r
+ *DataSize = TempDataSize;\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+\r
+Done:\r
+ mVariableRuntimeCacheReadLock = FALSE;\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Finds the given variable in a variable store in SMM.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
+ @param[in] VariableName Name of Variable to be found.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[out] Attributes Attribute value of the variable found.\r
+ @param[in, out] DataSize Size of Data found. If size is less than the\r
+ data, this value contains the required size.\r
+ @param[out] Data Data pointer.\r
+\r
+ @retval EFI_SUCCESS Found the specified variable.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_NOT_FOUND The specified variable could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariableInSmm (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT32 *Attributes OPTIONAL,\r
+ IN OUT UINTN *DataSize,\r
+ OUT VOID *Data OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
-\r
//\r
// Init the communicate buffer. The buffer data size is:\r
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
}\r
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
\r
- Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
+ Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
}\r
\r
Done:\r
- ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
return Status;\r
}\r
\r
+/**\r
+ This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+ Caution: This function may receive untrusted input.\r
+ The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
+\r
+ @param[in] VariableName Name of Variable to be found.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[out] Attributes Attribute value of the variable found.\r
+ @param[in, out] DataSize Size of Data found. If size is less than the\r
+ data, this value contains the required size.\r
+ @param[out] Data Data pointer.\r
+\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_SUCCESS Find the specified variable.\r
+ @retval EFI_NOT_FOUND Not found.\r
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT32 *Attributes OPTIONAL,\r
+ IN OUT UINTN *DataSize,\r
+ OUT VOID *Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (VariableName[0] == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
+ Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+ } else {\r
+ Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+ }\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+ return Status;\r
+}\r
\r
/**\r
This code Finds the Next available variable.\r
//\r
SendCommunicateBuffer (0);\r
\r
+ //\r
+ // Install the system configuration table for variable info data captured\r
+ //\r
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+ if (mVariableAuthFormat) {\r
+ gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);\r
+ } else {\r
+ gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);\r
+ }\r
+ }\r
+\r
gBS->CloseEvent (Event);\r
}\r
\r
{\r
EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);\r
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);\r
+ EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);\r
}\r
\r
/**\r
return Status;\r
}\r
\r
+/**\r
+ This code gets information needed from SMM for runtime cache initialization.\r
+\r
+ @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.\r
+ @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.\r
+ @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.\r
+ @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.\r
+\r
+ @retval EFI_SUCCESS Retrieved the size successfully.\r
+ @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.\r
+ @retval Others Could not retrieve the size successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetRuntimeCacheInfo (\r
+ OUT UINTN *TotalHobStorageSize,\r
+ OUT UINTN *TotalNvStorageSize,\r
+ OUT UINTN *TotalVolatileStorageSize,\r
+ OUT BOOLEAN *AuthenticatedVariableUsage\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo;\r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
+ UINTN CommSize;\r
+ UINT8 *CommBuffer;\r
+\r
+ SmmGetRuntimeCacheInfo = NULL;\r
+ CommBuffer = mVariableBuffer;\r
+\r
+ if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (CommBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
+ ZeroMem (CommBuffer, CommSize);\r
+\r
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
+\r
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;\r
+ SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ Status = SmmVariableFunctionHeader->ReturnStatus;\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Get data from SMM.\r
+ //\r
+ *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;\r
+ *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;\r
+ *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;\r
+ *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sends the runtime variable cache context information to SMM.\r
+\r
+ @retval EFI_SUCCESS Retrieved the size successfully.\r
+ @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.\r
+ @retval Others Could not retrieve the size successfully.;\r
+\r
+**/\r
+EFI_STATUS\r
+SendRuntimeVariableCacheContextToSmm (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext;\r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
+ UINTN CommSize;\r
+ UINT8 *CommBuffer;\r
+\r
+ SmmRuntimeVarCacheContext = NULL;\r
+ CommBuffer = mVariableBuffer;\r
+\r
+ if (CommBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
+\r
+ //\r
+ // Init the communicate buffer. The buffer data size is:\r
+ // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
+ //\r
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
+ ZeroMem (CommBuffer, CommSize);\r
+\r
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+ SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
+\r
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;\r
+ SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;\r
+\r
+ SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;\r
+ SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;\r
+ SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;\r
+ SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;\r
+ SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;\r
+ SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;\r
+\r
+ //\r
+ // Send data to SMM.\r
+ //\r
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ Status = SmmVariableFunctionHeader->ReturnStatus;\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
+ return Status;\r
+}\r
+\r
/**\r
Initialize variable service and install Variable Architectural protocol.\r
\r
{\r
EFI_STATUS Status;\r
\r
- Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
+ Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);\r
if (EFI_ERROR (Status)) {\r
return;\r
}\r
//\r
mVariableBufferPhysical = mVariableBuffer;\r
\r
+ if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
+ DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));\r
+ //\r
+ // Allocate runtime variable cache memory buffers.\r
+ //\r
+ Status = GetRuntimeCacheInfo (\r
+ &mVariableRuntimeHobCacheBufferSize,\r
+ &mVariableRuntimeNvCacheBufferSize,\r
+ &mVariableRuntimeVolatileCacheBufferSize,\r
+ &mVariableAuthFormat\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendRuntimeVariableCacheContextToSmm ();\r
+ if (!EFI_ERROR (Status)) {\r
+ SyncRuntimeCache ();\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ mVariableRuntimeHobCacheBuffer = NULL;\r
+ mVariableRuntimeNvCacheBuffer = NULL;\r
+ mVariableRuntimeVolatileCacheBuffer = NULL;\r
+ }\r
+ }\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));\r
+ }\r
+\r
gRT->GetVariable = RuntimeServiceGetVariable;\r
gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
gRT->SetVariable = RuntimeServiceSetVariable;\r
# may not be modified without authorization. If platform fails to protect these resources,\r
# the authentication service provided in this driver will be broken, and the behavior is undefined.\r
#\r
-# Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
##\r
VariableSmmRuntimeDxe.c\r
PrivilegePolymorphic.h\r
Measurement.c\r
+ VariableParsing.c\r
+ VariableParsing.h\r
\r
[Packages]\r
MdePkg/MdePkg.dec\r
gEdkiiVariableLockProtocolGuid ## PRODUCES\r
gEdkiiVarCheckProtocolGuid ## PRODUCES\r
\r
+[FeaturePcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES\r
+\r
[Guids]\r
+ ## PRODUCES ## GUID # Signature of Variable store header\r
+ ## CONSUMES ## GUID # Signature of Variable store header\r
+ ## SOMETIMES_PRODUCES ## SystemTable\r
+ gEfiAuthenticatedVariableGuid\r
+\r
+ ## PRODUCES ## GUID # Signature of Variable store header\r
+ ## CONSUMES ## GUID # Signature of Variable store header\r
+ ## SOMETIMES_PRODUCES ## SystemTable\r
+ gEfiVariableGuid\r
+\r
gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event\r
gEfiEventExitBootServicesGuid ## CONSUMES ## Event\r
## CONSUMES ## GUID # Locate protocol\r
VariableNonVolatile.h\r
VariableParsing.c\r
VariableParsing.h\r
+ VariableRuntimeCache.c\r
+ VariableRuntimeCache.h\r
VarCheck.c\r
Variable.h\r
PrivilegePolymorphic.h\r