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