| /** @file | |
| This module collects performance data for MM driver boot records and S3 Suspend Performance Record. | |
| This module registers report status code listener to collect performance data | |
| for MM driver boot records and S3 Suspend Performance Record. | |
| Caution: This module requires additional review when modified. | |
| This driver will have external input - communicate buffer in MM mode. | |
| This external input must be validated carefully to avoid security issue like | |
| buffer overflow, integer overflow. | |
| FpdtSmiHandler() will receive untrusted input and do basic validation. | |
| Copyright (c) 2011 - 2021, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <PiMm.h> | |
| #include <Protocol/MmReportStatusCodeHandler.h> | |
| #include <Guid/FirmwarePerformance.h> | |
| #include <Library/MmServicesTableLib.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/TimerLib.h> | |
| #include <Library/LockBoxLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include "FirmwarePerformanceCommon.h" | |
| EFI_MM_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL; | |
| UINT64 mSuspendStartTime = 0; | |
| BOOLEAN mS3SuspendLockBoxSaved = FALSE; | |
| /** | |
| Report status code listener for MM. This is used to record the performance | |
| data for S3 Suspend Start and S3 Suspend End in FPDT. | |
| @param[in] CodeType Indicates the type of status code being reported. | |
| @param[in] Value Describes the current status of a hardware or software entity. | |
| This included information about the class and subclass that is used to | |
| classify the entity as well as an operation. | |
| @param[in] Instance The enumeration of a hardware or software entity within | |
| the system. Valid instance numbers start with 1. | |
| @param[in] CallerId This optional parameter may be used to identify the caller. | |
| This parameter allows the status code driver to apply different rules to | |
| different callers. | |
| @param[in] Data This optional parameter may be used to pass additional data. | |
| @retval EFI_SUCCESS Status code is what we expected. | |
| @retval EFI_UNSUPPORTED Status code not supported. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FpdtStatusCodeListenerMm ( | |
| IN EFI_STATUS_CODE_TYPE CodeType, | |
| IN EFI_STATUS_CODE_VALUE Value, | |
| IN UINT32 Instance, | |
| IN EFI_GUID *CallerId, | |
| IN EFI_STATUS_CODE_DATA *Data | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT64 CurrentTime; | |
| EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord; | |
| // | |
| // Check whether status code is what we are interested in. | |
| // | |
| if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if ((Data != NULL) && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) { | |
| DEBUG ((DEBUG_ERROR, "FpdtStatusCodeListenerMm: Performance data reported through gEfiFirmwarePerformanceGuid will not be collected by FirmwarePerformanceDataTableMm\n")); | |
| return EFI_UNSUPPORTED; | |
| } | |
| if ((Value != PcdGet32 (PcdProgressCodeS3SuspendStart)) && | |
| (Value != PcdGet32 (PcdProgressCodeS3SuspendEnd))) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Retrieve current time. | |
| // | |
| CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ()); | |
| if (Value == PcdGet32 (PcdProgressCodeS3SuspendStart)) { | |
| // | |
| // S3 Suspend started, record the performance data and return. | |
| // | |
| mSuspendStartTime = CurrentTime; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // We are going to S3 sleep, record S3 Suspend End performance data. | |
| // | |
| S3SuspendRecord.SuspendStart = mSuspendStartTime; | |
| S3SuspendRecord.SuspendEnd = CurrentTime; | |
| // | |
| // Save S3 suspend performance data to lock box, it will be used by Firmware Performance PEIM. | |
| // | |
| if (!mS3SuspendLockBoxSaved) { | |
| Status = SaveLockBox ( | |
| &gEfiFirmwarePerformanceGuid, | |
| &S3SuspendRecord, | |
| sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD) | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| mS3SuspendLockBoxSaved = TRUE; | |
| } else { | |
| Status = UpdateLockBox ( | |
| &gEfiFirmwarePerformanceGuid, | |
| 0, | |
| &S3SuspendRecord, | |
| sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD) | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| The module Entry Point of the Firmware Performance Data Table MM driver. | |
| @retval EFI_SUCCESS The entry point is executed successfully. | |
| @retval Other Some error occurs when executing this entry point. | |
| **/ | |
| EFI_STATUS | |
| FirmwarePerformanceCommonEntryPoint ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Get MM Report Status Code Handler Protocol. | |
| // | |
| Status = gMmst->MmLocateProtocol ( | |
| &gEfiMmRscHandlerProtocolGuid, | |
| NULL, | |
| (VOID **)&mRscHandlerProtocol | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Register report status code listener for BootRecords and S3 Suspend Start and End. | |
| // | |
| Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerMm); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |