]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
Add EDKII_VARIABLE_LOCK_PROTOCOL and the implementation in MdeModulePkg variable...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmm.c
index 111a6cd41174f4cb581c3ec5ec6ea8c5bbd2f838..4009fcb1712eaded50b18d740c91a814e19c46f6 100644 (file)
@@ -29,6 +29,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/SmmFirmwareVolumeBlock.h>\r
 #include <Protocol/SmmFaultTolerantWrite.h>\r
 #include <Protocol/SmmAccess2.h>\r
+#include <Protocol/SmmEndOfDxe.h>\r
 \r
 #include <Library/SmmServicesTableLib.h>\r
 \r
@@ -46,15 +47,61 @@ BOOLEAN                                              mAtRuntime              = F
 EFI_GUID                                             mZeroGuid               = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
 UINT8                                                *mVariableBufferPayload = NULL;\r
 UINTN                                                mVariableBufferPayloadSize;\r
+extern BOOLEAN                                       mEndOfDxe;\r
+extern BOOLEAN                                       mEnableLocking;\r
+\r
+/**\r
+\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName                     Name of Variable to be found.\r
+  @param VendorGuid                       Variable vendor GUID.\r
+  @param Attributes                       Attribute value of the variable found\r
+  @param DataSize                         Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param Data                             Data pointer.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Set successfully.\r
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @return EFI_NOT_FOUND                   Not found.\r
+  @return EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmVariableSetVariable (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+\r
+  //\r
+  // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.\r
+  //\r
+  mEnableLocking = FALSE;\r
+  Status         = VariableServiceSetVariable (\r
+                     VariableName,\r
+                     VendorGuid,\r
+                     Attributes,\r
+                     DataSize,\r
+                     Data\r
+                     );\r
+  mEnableLocking = TRUE;\r
+  return Status;\r
+}\r
 \r
 EFI_SMM_VARIABLE_PROTOCOL      gSmmVariable = {\r
   VariableServiceGetVariable,\r
   VariableServiceGetNextVariableName,\r
-  VariableServiceSetVariable,\r
+  SmmVariableSetVariable,\r
   VariableServiceQueryVariableInfo\r
 };\r
 \r
-\r
 /**\r
   Return TRUE if ExitBootServices () has been called.\r
   \r
@@ -450,6 +497,7 @@ SmmVariableHandler (
   SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME  *GetNextVariableName;\r
   SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO     *QueryVariableInfo;\r
   VARIABLE_INFO_ENTRY                              *VariableInfo;\r
+  SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE           *VariableToLock;\r
   UINTN                                            InfoSize;\r
   UINTN                                            NameBufferSize;\r
   UINTN                                            CommBufferPayloadSize;\r
@@ -635,6 +683,7 @@ SmmVariableHandler (
       break;\r
 \r
     case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:\r
+      mEndOfDxe = TRUE;\r
       if (AtRuntime()) {\r
         Status = EFI_UNSUPPORTED;\r
         break;\r
@@ -667,6 +716,51 @@ SmmVariableHandler (
       *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
       break;\r
 \r
+    case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:\r
+      if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
+        DEBUG ((EFI_D_ERROR, "RequestToLock: SMM communication buffer size invalid!\n"));\r
+        return EFI_SUCCESS;\r
+      }\r
+      //\r
+      // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.\r
+      //\r
+      CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
+      VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) mVariableBufferPayload;\r
+\r
+      if (VariableToLock->NameSize > MAX_ADDRESS - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
+        //\r
+        // Prevent InfoSize overflow happen\r
+        //\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }\r
+\r
+      if (VariableToLock->NameSize < sizeof (CHAR16) || VariableToLock->Name[VariableToLock->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
+        //\r
+        // Make sure VariableName is A Null-terminated string.\r
+        //\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }\r
+      \r
+      InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableToLock->NameSize;\r
+      \r
+      //\r
+      // SMRAM range check already covered before\r
+      //\r
+      if (InfoSize > CommBufferPayloadSize) {\r
+        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }\r
+\r
+      Status = VariableLockRequestToLock (\r
+                 NULL,\r
+                 VariableToLock->Name,\r
+                 &VariableToLock->Guid\r
+                 );\r
+      break;\r
+\r
     default:\r
       Status = EFI_UNSUPPORTED;\r
   }\r
@@ -678,6 +772,28 @@ EXIT:
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  SMM END_OF_DXE protocol notification event handler.\r
+\r
+  @param  Protocol   Points to the protocol's unique identifier\r
+  @param  Interface  Points to the interface instance\r
+  @param  Handle     The handle on which the interface was installed\r
+\r
+  @retval EFI_SUCCESS   SmmEndOfDxeCallback runs successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEndOfDxeCallback (\r
+  IN CONST EFI_GUID                       *Protocol,\r
+  IN VOID                                 *Interface,\r
+  IN EFI_HANDLE                           Handle\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n"));\r
+  mEndOfDxe = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   SMM Fault Tolerant Write protocol notification event handler.\r
@@ -774,6 +890,7 @@ VariableServiceInitialize (
   VOID                                    *SmmFtwRegistration;\r
   EFI_SMM_ACCESS2_PROTOCOL                *SmmAccess;\r
   UINTN                                   Size;\r
+  VOID                                    *SmmEndOfDxeRegistration;\r
 \r
   //\r
   // Variable initialize.\r
@@ -843,6 +960,16 @@ VariableServiceInitialize (
                                         );\r
   ASSERT_EFI_ERROR (Status);\r
  \r
+  //\r
+  // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.\r
+  //\r
+  Status = gSmst->SmmRegisterProtocolNotify (\r
+                    &gEfiSmmEndOfDxeProtocolGuid,\r
+                    SmmEndOfDxeCallback,\r
+                    &SmmEndOfDxeRegistration\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   //\r
   // Register FtwNotificationEvent () notify function.\r
   // \r