]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
MdeModulePkg Variable: Add emulated variable NV mode support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmm.c
index fb16af31b1a999863077ebe81dd527e124336124..3e35219d053ab05cd01e307ac5428d1be87f8c7c 100644 (file)
@@ -14,7 +14,8 @@
   VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),\r
   SmmVariableGetStatistics() should also do validation based on its own knowledge.\r
 \r
-Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -28,24 +29,17 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/SmmVariable.h>\r
 #include <Protocol/SmmFirmwareVolumeBlock.h>\r
 #include <Protocol/SmmFaultTolerantWrite.h>\r
-#include <Protocol/SmmEndOfDxe.h>\r
+#include <Protocol/MmEndOfDxe.h>\r
 #include <Protocol/SmmVarCheck.h>\r
 \r
-#include <Library/SmmServicesTableLib.h>\r
-#include <Library/SmmMemLib.h>\r
+#include <Library/MmServicesTableLib.h>\r
 \r
 #include <Guid/SmmVariableCommon.h>\r
-#include <Guid/ZeroGuid.h>\r
 #include "Variable.h"\r
 \r
-extern VARIABLE_INFO_ENTRY                           *gVariableInfo;\r
-EFI_HANDLE                                           mSmmVariableHandle      = NULL;\r
-EFI_HANDLE                                           mVariableHandle         = NULL;\r
 BOOLEAN                                              mAtRuntime              = FALSE;\r
 UINT8                                                *mVariableBufferPayload = NULL;\r
 UINTN                                                mVariableBufferPayloadSize;\r
-extern BOOLEAN                                       mEndOfDxe;\r
-extern VAR_CHECK_REQUEST_SOURCE                      mRequestSource;\r
 \r
 /**\r
   SecureBoot Hook for SetVariable.\r
@@ -200,7 +194,7 @@ ReleaseLockOnlyAtBootTime (
 }\r
 \r
 /**\r
-  Retrive the SMM Fault Tolerent Write protocol interface.\r
+  Retrieve the SMM Fault Tolerent Write protocol interface.\r
 \r
   @param[out] FtwProtocol       The interface of SMM Ftw protocol\r
 \r
@@ -219,7 +213,7 @@ GetFtwProtocol (
   //\r
   // Locate Smm Fault Tolerent Write protocol\r
   //\r
-  Status = gSmst->SmmLocateProtocol (\r
+  Status = gMmst->MmLocateProtocol (\r
                     &gEfiSmmFaultTolerantWriteProtocolGuid,\r
                     NULL,\r
                     FtwProtocol\r
@@ -229,7 +223,7 @@ GetFtwProtocol (
 \r
 \r
 /**\r
-  Retrive the SMM FVB protocol interface by HANDLE.\r
+  Retrieve the SMM FVB protocol interface by HANDLE.\r
 \r
   @param[in]  FvBlockHandle     The handle of SMM FVB protocol that provides services for\r
                                 reading, writing, and erasing the target block.\r
@@ -249,7 +243,7 @@ GetFvbByHandle (
   //\r
   // To get the SMM FVB protocol interface on the handle\r
   //\r
-  return gSmst->SmmHandleProtocol (\r
+  return gMmst->MmHandleProtocol (\r
                   FvBlockHandle,\r
                   &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
                   (VOID **) FvBlock\r
@@ -288,7 +282,7 @@ GetFvbCountAndBuffer (
   BufferSize     = 0;\r
   *NumberHandles = 0;\r
   *Buffer        = NULL;\r
-  Status = gSmst->SmmLocateHandle (\r
+  Status = gMmst->MmLocateHandle (\r
                     ByProtocol,\r
                     &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
                     NULL,\r
@@ -304,7 +298,7 @@ GetFvbCountAndBuffer (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Status = gSmst->SmmLocateHandle (\r
+  Status = gMmst->MmLocateHandle (\r
                     ByProtocol,\r
                     &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
                     NULL,\r
@@ -350,9 +344,10 @@ SmmVariableGetStatistics (
   )\r
 {\r
   VARIABLE_INFO_ENTRY                                  *VariableInfo;\r
-  UINTN                                                NameLength;\r
+  UINTN                                                NameSize;\r
   UINTN                                                StatisticsInfoSize;\r
   CHAR16                                               *InfoName;\r
+  UINTN                                                InfoNameMaxSize;\r
   EFI_GUID                                             VendorGuid;\r
 \r
   if (InfoEntry == NULL) {\r
@@ -364,21 +359,28 @@ SmmVariableGetStatistics (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);\r
+  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY);\r
   if (*InfoSize < StatisticsInfoSize) {\r
     *InfoSize = StatisticsInfoSize;\r
     return EFI_BUFFER_TOO_SMALL;\r
   }\r
   InfoName = (CHAR16 *)(InfoEntry + 1);\r
+  InfoNameMaxSize = (*InfoSize - sizeof (VARIABLE_INFO_ENTRY));\r
 \r
   CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);\r
 \r
-  if (CompareGuid (&VendorGuid, &gZeroGuid)) {\r
+  if (IsZeroGuid (&VendorGuid)) {\r
     //\r
     // Return the first variable info\r
     //\r
+    NameSize = StrSize (VariableInfo->Name);\r
+    StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;\r
+    if (*InfoSize < StatisticsInfoSize) {\r
+      *InfoSize = StatisticsInfoSize;\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
     CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));\r
-    CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));\r
+    CopyMem (InfoName, VariableInfo->Name, NameSize);\r
     *InfoSize = StatisticsInfoSize;\r
     return EFI_SUCCESS;\r
   }\r
@@ -388,9 +390,9 @@ SmmVariableGetStatistics (
   //\r
   while (VariableInfo != NULL) {\r
     if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {\r
-      NameLength = StrSize (VariableInfo->Name);\r
-      if (NameLength == StrSize (InfoName)) {\r
-        if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {\r
+      NameSize = StrSize (VariableInfo->Name);\r
+      if (NameSize <= InfoNameMaxSize) {\r
+        if (CompareMem (VariableInfo->Name, InfoName, NameSize) == 0) {\r
           //\r
           // Find the match one\r
           //\r
@@ -410,14 +412,15 @@ SmmVariableGetStatistics (
   //\r
   // Output the new variable info\r
   //\r
-  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);\r
+  NameSize = StrSize (VariableInfo->Name);\r
+  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;\r
   if (*InfoSize < StatisticsInfoSize) {\r
     *InfoSize = StatisticsInfoSize;\r
     return EFI_BUFFER_TOO_SMALL;\r
   }\r
 \r
   CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));\r
-  CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));\r
+  CopyMem (InfoName, VariableInfo->Name, NameSize);\r
   *InfoSize = StatisticsInfoSize;\r
 \r
   return EFI_SUCCESS;\r
@@ -492,7 +495,7 @@ SmmVariableHandler (
     return EFI_SUCCESS;\r
   }\r
 \r
-  if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
+  if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
     DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
     return EFI_SUCCESS;\r
   }\r
@@ -529,6 +532,12 @@ SmmVariableHandler (
         goto EXIT;\r
       }\r
 \r
+      //\r
+      // The VariableSpeculationBarrier() call here is to ensure the previous\r
+      // range/content checks for the CommBuffer have been completed before the\r
+      // subsequent consumption of the CommBuffer content.\r
+      //\r
+      VariableSpeculationBarrier ();\r
       if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
         //\r
         // Make sure VariableName is A Null-terminated string.\r
@@ -623,6 +632,12 @@ SmmVariableHandler (
         goto EXIT;\r
       }\r
 \r
+      //\r
+      // The VariableSpeculationBarrier() call here is to ensure the previous\r
+      // range/content checks for the CommBuffer have been completed before the\r
+      // subsequent consumption of the CommBuffer content.\r
+      //\r
+      VariableSpeculationBarrier ();\r
       if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
         //\r
         // Make sure VariableName is A Null-terminated string.\r
@@ -671,6 +686,7 @@ SmmVariableHandler (
         break;\r
       }\r
       if (!mEndOfDxe) {\r
+        MorLockInitAtEndOfDxe ();\r
         mEndOfDxe = TRUE;\r
         VarCheckLibInitializeAtEndOfDxe (NULL);\r
         //\r
@@ -696,11 +712,10 @@ SmmVariableHandler (
       // It is covered by previous CommBuffer check\r
       //\r
 \r
-      if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) {\r
-        DEBUG ((EFI_D_ERROR, "GetStatistics: SMM communication buffer in SMRAM!\n"));\r
-        Status = EFI_ACCESS_DENIED;\r
-        goto EXIT;\r
-      }\r
+      //\r
+      // Do not need to check CommBufferSize buffer as it should point to SMRAM\r
+      // that was used by SMM core to cache CommSize from SmmCommunication protocol.\r
+      //\r
 \r
       Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);\r
       *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
@@ -758,6 +773,12 @@ SmmVariableHandler (
         goto EXIT;\r
       }\r
 \r
+      //\r
+      // The VariableSpeculationBarrier() call here is to ensure the previous\r
+      // range/content checks for the CommBuffer have been completed before the\r
+      // subsequent consumption of the CommBuffer content.\r
+      //\r
+      VariableSpeculationBarrier ();\r
       if (CommVariableProperty->NameSize < sizeof (CHAR16) || CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
         //\r
         // Make sure VariableName is A Null-terminated string.\r
@@ -804,6 +825,7 @@ SmmEndOfDxeCallback (
   )\r
 {\r
   DEBUG ((EFI_D_INFO, "[Variable]SMM_END_OF_DXE is signaled\n"));\r
+  MorLockInitAtEndOfDxe ();\r
   mEndOfDxe = TRUE;\r
   VarCheckLibInitializeAtEndOfDxe (NULL);\r
   //\r
@@ -817,6 +839,28 @@ SmmEndOfDxeCallback (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Initializes variable write service for SMM.\r
+\r
+**/\r
+VOID\r
+VariableWriteServiceInitializeSmm (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  Status = VariableWriteServiceInitialize ();\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));\r
+  }\r
+\r
+  //\r
+  // Notify the variable wrapper driver the variable write service is ready\r
+  //\r
+  VariableNotifySmmWriteReady ();\r
+}\r
+\r
 /**\r
   SMM Fault Tolerant Write protocol notification event handler.\r
 \r
@@ -840,6 +884,7 @@ SmmFtwNotificationEvent (
   )\r
 {\r
   EFI_STATUS                              Status;\r
+  EFI_PHYSICAL_ADDRESS                    VariableStoreBase;\r
   EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;\r
   EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;\r
   EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;\r
@@ -862,13 +907,17 @@ SmmFtwNotificationEvent (
     ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);\r
   }\r
 \r
+  NvStorageVariableBase = NV_STORAGE_VARIABLE_BASE;\r
+  VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;\r
+\r
+  //\r
+  // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+\r
   //\r
   // Find the proper FVB protocol for variable.\r
   //\r
-  NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
-  if (NvStorageVariableBase == 0) {\r
-    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
-  }\r
   Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_NOT_FOUND;\r
@@ -876,21 +925,10 @@ SmmFtwNotificationEvent (
 \r
   mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
 \r
-  Status = VariableWriteServiceInitialize ();\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));\r
-  }\r
-\r
   //\r
-  // Notify the variable wrapper driver the variable write service is ready\r
+  // Initializes variable write service after FTW was ready.\r
   //\r
-  Status = gBS->InstallProtocolInterface (\r
-                  &mSmmVariableHandle,\r
-                  &gSmmVariableWriteGuid,\r
-                  EFI_NATIVE_INTERFACE,\r
-                  NULL\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
+  VariableWriteServiceInitializeSmm ();\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -902,17 +940,13 @@ SmmFtwNotificationEvent (
   for variable read and write services being available. It also registers\r
   a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
 \r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
-  @param[in] SystemTable    A pointer to the EFI System Table.\r
-\r
   @retval EFI_SUCCESS       Variable service successfully initialized.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-VariableServiceInitialize (\r
-  IN EFI_HANDLE                           ImageHandle,\r
-  IN EFI_SYSTEM_TABLE                     *SystemTable\r
+MmVariableServiceInitialize (\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS                              Status;\r
@@ -930,7 +964,7 @@ VariableServiceInitialize (
   // Install the Smm Variable Protocol on a new handle.\r
   //\r
   VariableHandle = NULL;\r
-  Status = gSmst->SmmInstallProtocolInterface (\r
+  Status = gMmst->MmInstallProtocolInterface (\r
                     &VariableHandle,\r
                     &gEfiSmmVariableProtocolGuid,\r
                     EFI_NATIVE_INTERFACE,\r
@@ -938,7 +972,7 @@ VariableServiceInitialize (
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = gSmst->SmmInstallProtocolInterface (\r
+  Status = gMmst->MmInstallProtocolInterface (\r
                     &VariableHandle,\r
                     &gEdkiiSmmVarCheckProtocolGuid,\r
                     EFI_NATIVE_INTERFACE,\r
@@ -946,10 +980,10 @@ VariableServiceInitialize (
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  mVariableBufferPayloadSize = GetNonVolatileMaxVariableSize () +\r
+  mVariableBufferPayloadSize = GetMaxVariableSize () +\r
                                OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - GetVariableHeaderSize ();\r
 \r
-  Status = gSmst->SmmAllocatePool (\r
+  Status = gMmst->MmAllocatePool (\r
                     EfiRuntimeServicesData,\r
                     mVariableBufferPayloadSize,\r
                     (VOID **)&mVariableBufferPayload\r
@@ -960,41 +994,42 @@ VariableServiceInitialize (
   /// Register SMM variable SMI handler\r
   ///\r
   VariableHandle = NULL;\r
-  Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);\r
+  Status = gMmst->MmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
   // Notify the variable wrapper driver the variable service is ready\r
   //\r
-  Status = SystemTable->BootServices->InstallProtocolInterface (\r
-                                        &mVariableHandle,\r
-                                        &gEfiSmmVariableProtocolGuid,\r
-                                        EFI_NATIVE_INTERFACE,\r
-                                        &gSmmVariable\r
-                                        );\r
-  ASSERT_EFI_ERROR (Status);\r
+  VariableNotifySmmReady ();\r
 \r
   //\r
   // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.\r
   //\r
-  Status = gSmst->SmmRegisterProtocolNotify (\r
-                    &gEfiSmmEndOfDxeProtocolGuid,\r
+  Status = gMmst->MmRegisterProtocolNotify (\r
+                    &gEfiMmEndOfDxeProtocolGuid,\r
                     SmmEndOfDxeCallback,\r
                     &SmmEndOfDxeRegistration\r
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  //\r
-  // Register FtwNotificationEvent () notify function.\r
-  //\r
-  Status = gSmst->SmmRegisterProtocolNotify (\r
-                    &gEfiSmmFaultTolerantWriteProtocolGuid,\r
-                    SmmFtwNotificationEvent,\r
-                    &SmmFtwRegistration\r
-                    );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  SmmFtwNotificationEvent (NULL, NULL, NULL);\r
+  if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
+    //\r
+    // Register FtwNotificationEvent () notify function.\r
+    //\r
+    Status = gMmst->MmRegisterProtocolNotify (\r
+                      &gEfiSmmFaultTolerantWriteProtocolGuid,\r
+                      SmmFtwNotificationEvent,\r
+                      &SmmFtwRegistration\r
+                      );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    SmmFtwNotificationEvent (NULL, NULL, NULL);\r
+  } else {\r
+    //\r
+    // Emulated non-volatile variable mode does not depend on FVB and FTW.\r
+    //\r
+    VariableWriteServiceInitializeSmm ();\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r