]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
MdeModulePkg/FPDT: Lock boot performance table address variable at EndOfDxe
[mirror_edk2.git] / MdeModulePkg / Library / SmmCorePerformanceLib / SmmCorePerformanceLib.c
index b4f22c14ae73aed4f7f9fecbde452ca5214a44d7..d80f37e52016f62cc9988b125407d8c91bc34f9c 100644 (file)
@@ -16,7 +16,7 @@
 \r
  SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.\r
 \r
-Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2021, Intel Corporation. All rights reserved.<BR>\r
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -48,6 +48,7 @@ CHAR8                *mPlatformLanguage    = NULL;
 SPIN_LOCK            mSmmFpdtLock;\r
 PERFORMANCE_PROPERTY  mPerformanceProperty;\r
 UINT32               mCachedLength         = 0;\r
+UINT32               mBootRecordSize       = 0;\r
 \r
 //\r
 // Interfaces for SMM PerformanceMeasurement Protocol.\r
@@ -776,41 +777,116 @@ InsertFpdtRecord (
 }\r
 \r
 /**\r
-  SmmReadyToBoot protocol notification event handler.\r
+  Communication service SMI Handler entry.\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
+  This SMI handler provides services for report MM boot records.\r
 \r
-  @retval EFI_SUCCESS   SmmReadyToBootCallback runs successfully\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-MM environment into an MM 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
-SmmReportFpdtRecordData (\r
-  IN CONST EFI_GUID                       *Protocol,\r
-  IN VOID                                 *Interface,\r
-  IN EFI_HANDLE                           Handle\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
-  UINT64          SmmBPDTddr;\r
-\r
-  if (!mFpdtDataIsReported && mSmmBootPerformanceTable != NULL) {\r
-    SmmBPDTddr = (UINT64)(UINTN)mSmmBootPerformanceTable;\r
-    REPORT_STATUS_CODE_EX (\r
-        EFI_PROGRESS_CODE,\r
-        EFI_SOFTWARE_SMM_DRIVER,\r
-        0,\r
-        NULL,\r
-        &gEdkiiFpdtExtendedFirmwarePerformanceGuid,\r
-        &SmmBPDTddr,\r
-        sizeof (UINT64)\r
+  EFI_STATUS                   Status;\r
+  SMM_BOOT_RECORD_COMMUNICATE  *SmmCommData;\r
+  UINTN                        BootRecordOffset;\r
+  UINTN                        BootRecordSize;\r
+  VOID                         *BootRecordData;\r
+  UINTN                        TempCommBufferSize;\r
+  UINT8                        *BootRecordBuffer;\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 ((DEBUG_ERROR, "FpdtSmiHandler: MM communication data buffer in MMRAM 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 ((DEBUG_ERROR, "FpdtSmiHandler: MM Data buffer in MMRAM or overflow!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      }\r
+      BootRecordBuffer = ((UINT8 *) (mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
+      CopyMem (\r
+        (UINT8*)BootRecordData,\r
+        BootRecordBuffer + BootRecordOffset,\r
+        BootRecordSize\r
         );\r
-    //\r
-    // Set FPDT report state to TRUE.\r
-    //\r
-    mFpdtDataIsReported = TRUE;\r
+      mFpdtDataIsReported = TRUE;\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_UNSUPPORTED;\r
   }\r
+\r
+  SmmCommData->ReturnStatus = Status;\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -830,8 +906,8 @@ InitializeSmmCorePerformanceLib (
   )\r
 {\r
   EFI_HANDLE                Handle;\r
+  EFI_HANDLE                SmiHandle;\r
   EFI_STATUS                Status;\r
-  VOID                      *SmmReadyToBootRegistration;\r
   PERFORMANCE_PROPERTY      *PerformanceProperty;\r
 \r
   //\r
@@ -851,11 +927,13 @@ InitializeSmmCorePerformanceLib (
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = gSmst->SmmRegisterProtocolNotify (\r
-                    &gEdkiiSmmReadyToBootProtocolGuid,\r
-                    SmmReportFpdtRecordData,\r
-                    &SmmReadyToBootRegistration\r
-                    );\r
+  //\r
+  // Register SMI handler.\r
+  //\r
+  SmiHandle = NULL;\r
+  Status = gSmst->SmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &SmiHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);\r
   if (EFI_ERROR (Status)) {\r
     //\r