]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / FirmwarePerformanceDataTableSmm / FirmwarePerformanceSmm.c
index 19a2fe68a95c221c7996f1754aa1d7a3c8686467..d6c6e7693e4d0df91c62ea03c56d57fd40c578ee 100644 (file)
@@ -1,24 +1,23 @@
 /** @file\r
-  This module update S3 Suspend Performance Record in ACPI Firmware Performance Data Table.\r
+  This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.\r
 \r
-  This module register report status code listener to collect performance data\r
-  for S3 Suspend Performance Record.\r
+  This module registers report status code listener to collect performance data\r
+  for SMM driver boot records and S3 Suspend Performance Record.\r
 \r
-  Copyright (c) 2011, Intel Corporation. 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
-  http://opensource.org/licenses/bsd-license.php\r
+  Caution: This module requires additional review when modified.\r
+  This driver will have external input - communicate buffer in SMM mode.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  FpdtSmiHandler() will receive untrusted input and do basic validation.\r
+\r
+  Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include <PiSmm.h>\r
 \r
-#include <IndustryStandard/Acpi50.h>\r
-\r
 #include <Protocol/SmmReportStatusCodeHandler.h>\r
 \r
 #include <Guid/FirmwarePerformance.h>\r
 #include <Library/TimerLib.h>\r
 #include <Library/LockBoxLib.h>\r
 #include <Library/PcdLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/SynchronizationLib.h>\r
+#include <Library/SmmMemLib.h>\r
+\r
+SMM_BOOT_PERFORMANCE_TABLE    *mSmmBootPerformanceTable = NULL;\r
 \r
 EFI_SMM_RSC_HANDLER_PROTOCOL  *mRscHandlerProtocol    = NULL;\r
 UINT64                        mSuspendStartTime       = 0;\r
 BOOLEAN                       mS3SuspendLockBoxSaved  = FALSE;\r
+UINT32                        mBootRecordSize = 0;\r
+UINT8                         *mBootRecordBuffer = NULL;\r
+\r
+SPIN_LOCK                     mSmmFpdtLock;\r
+BOOLEAN                       mSmramIsOutOfResource = FALSE;\r
 \r
 /**\r
   Report status code listener for SMM. This is used to record the performance\r
@@ -73,6 +84,27 @@ FpdtStatusCodeListenerSmm (
   if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {\r
     return EFI_UNSUPPORTED;\r
   }\r
+\r
+  //\r
+  // Collect one or more Boot records in boot time\r
+  //\r
+  if (Data != NULL && CompareGuid (&Data->Type, &gEdkiiFpdtExtendedFirmwarePerformanceGuid)) {\r
+    AcquireSpinLock (&mSmmFpdtLock);\r
+    //\r
+    // Get the boot performance data.\r
+    //\r
+    CopyMem (&mSmmBootPerformanceTable, Data + 1, Data->Size);\r
+    mBootRecordBuffer = ((UINT8 *) (mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
+\r
+    ReleaseSpinLock (&mSmmFpdtLock);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {\r
+    DEBUG ((DEBUG_ERROR, "FpdtStatusCodeListenerSmm: Performance data reported through gEfiFirmwarePerformanceGuid will not be collected by FirmwarePerformanceDataTableSmm\n"));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
   if ((Value != PcdGet32 (PcdProgressCodeS3SuspendStart)) &&\r
       (Value != PcdGet32 (PcdProgressCodeS3SuspendEnd))) {\r
     return EFI_UNSUPPORTED;\r
@@ -122,6 +154,118 @@ FpdtStatusCodeListenerSmm (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Communication service SMI Handler entry.\r
+\r
+  This SMI handler provides services for report SMM boot records.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  Communicate buffer and buffer size are external input, so this function will do basic validation.\r
+\r
+  @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param[in]     RegisterContext Points to an optional handler context which was specified when the\r
+                                 handler was registered.\r
+  @param[in, out] CommBuffer     A pointer to a collection of data in memory that will\r
+                                 be conveyed from a non-SMM environment into an SMM environment.\r
+  @param[in, out] CommBufferSize The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers\r
+                                              should still be called.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should\r
+                                              still be called.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still\r
+                                              be called.\r
+  @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FpdtSmiHandler (\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_BOOT_RECORD_COMMUNICATE  *SmmCommData;\r
+  UINTN                        BootRecordOffset;\r
+  UINTN                        BootRecordSize;\r
+  VOID                         *BootRecordData;\r
+  UINTN                        TempCommBufferSize;\r
+\r
+  //\r
+  // If input is invalid, stop processing this SMI\r
+  //\r
+  if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  TempCommBufferSize = *CommBufferSize;\r
+\r
+  if(TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
+    DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM communication data buffer in SMRAM or overflow!\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)CommBuffer;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (SmmCommData->Function) {\r
+    case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE :\r
+      if (mSmmBootPerformanceTable != NULL) {\r
+        mBootRecordSize = mSmmBootPerformanceTable->Header.Length - sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
+      }\r
+      SmmCommData->BootRecordSize = mBootRecordSize;\r
+      break;\r
+\r
+    case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA :\r
+      Status = EFI_UNSUPPORTED;\r
+      break;\r
+\r
+    case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET :\r
+      BootRecordOffset = SmmCommData->BootRecordOffset;\r
+      BootRecordData   = SmmCommData->BootRecordData;\r
+      BootRecordSize   = SmmCommData->BootRecordSize;\r
+      if (BootRecordData == NULL || BootRecordOffset >= mBootRecordSize) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Sanity check\r
+      //\r
+      if (BootRecordSize > mBootRecordSize - BootRecordOffset) {\r
+        BootRecordSize = mBootRecordSize - BootRecordOffset;\r
+      }\r
+      SmmCommData->BootRecordSize = BootRecordSize;\r
+      if (!SmmIsBufferOutsideSmmValid ((UINTN)BootRecordData, BootRecordSize)) {\r
+        DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM Data buffer in SMRAM or overflow!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      }\r
+\r
+      CopyMem (\r
+       (UINT8*)BootRecordData,\r
+       mBootRecordBuffer + BootRecordOffset,\r
+       BootRecordSize\r
+       );\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SmmCommData->ReturnStatus = Status;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   The module Entry Point of the Firmware Performance Data Table SMM driver.\r
 \r
@@ -139,27 +283,36 @@ FirmwarePerformanceSmmEntryPoint (
   IN EFI_SYSTEM_TABLE    *SystemTable\r
   )\r
 {\r
-  if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {\r
-    EFI_STATUS  Status;\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                Handle;\r
 \r
-    //\r
-    // Get SMM Report Status Code Handler Protocol.\r
-    //\r
-    Status = gSmst->SmmLocateProtocol (\r
-                      &gEfiSmmRscHandlerProtocolGuid,\r
-                      NULL,\r
-                      (VOID **) &mRscHandlerProtocol\r
-                      );\r
-    ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Initialize spin lock\r
+  //\r
+  InitializeSpinLock (&mSmmFpdtLock);\r
 \r
-    //\r
-    // Register report status code listener for S3 Suspend Start and End.\r
-    //\r
-    Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerSmm);\r
-    ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Get SMM Report Status Code Handler Protocol.\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (\r
+                    &gEfiSmmRscHandlerProtocolGuid,\r
+                    NULL,\r
+                    (VOID **) &mRscHandlerProtocol\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-    return Status;\r
-  } else {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
+  //\r
+  // Register report status code listener for BootRecords and S3 Suspend Start and End.\r
+  //\r
+  Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerSmm);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register SMI handler.\r
+  //\r
+  Handle = NULL;\r
+  Status = gSmst->SmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
 }\r