]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
MdeModulePkg/Variable: Add RT GetVariable() cache support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableRuntimeCache.c
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeCache.c
new file mode 100644 (file)
index 0000000..bc93cc0
--- /dev/null
@@ -0,0 +1,153 @@
+/** @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