]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
MdeModulePkg/Variable: Add RT GetVariable() cache support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmm.c
index 5e24bc4a6242f2773fd1e2f634298da53e97b0e5..caca5c32411be8528c48a757d43a14805630bfe4 100644 (file)
@@ -31,6 +31,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #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
@@ -451,25 +454,29 @@ SmmVariableGetStatistics (
 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
@@ -789,6 +796,154 @@ SmmVariableHandler (
                  );\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