diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
index 0e418f4a32..a1fd2645e0 100644
--- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
+++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
@@ -22,10 +22,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// Data for FPDT performance records.
//
-#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))
-#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
-#define FIRMWARE_RECORD_BUFFER 0x10000
-#define CACHE_HANDLE_GUID_COUNT 0x800
+// MU_CHANGE [BEGIN] - Standalone MM Perf Support
+#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))
+// MU_CHANGE [END] - Standalone MM Perf Support
+#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
+#define FIRMWARE_RECORD_BUFFER 0x10000
+#define CACHE_HANDLE_GUID_COUNT 0x800
BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;
BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {
@@ -228,16 +230,18 @@ InternalGetSmmPerfData (
{
EFI_STATUS Status;
UINT8 *SmmBootRecordCommBuffer;
- EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
+ EFI_MM_COMMUNICATE_HEADER *MmCommBufferHeader; // MU_CHANGE - Standalone MM Perf Support
SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
UINTN CommSize;
EFI_SMM_COMMUNICATION_PROTOCOL *Communication;
EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;
UINTN Index;
+ VOID *CurrentBootRecordData; // MU_CHANGE - Standalone MM Perf Support
VOID *SmmBootRecordData;
UINTN SmmBootRecordDataSize;
UINTN ReservedMemSize;
+ UINTN BootRecordDataPayloadSize; // MU_CHANGE - Standalone MM Perf Support
UINTN SmmBootRecordDataRetrieved;
//
@@ -278,13 +282,13 @@ InternalGetSmmPerfData (
//
if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) {
SmmBootRecordCommBuffer = (VOID *)(UINTN)SmmCommMemRegion->PhysicalStart;
- SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)SmmBootRecordCommBuffer;
- SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE *)SmmCommBufferHeader->Data;
+ MmCommBufferHeader = (EFI_MM_COMMUNICATE_HEADER *)SmmBootRecordCommBuffer; // MU_CHANGE - Standalone MM Perf Support
+ SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE *)MmCommBufferHeader->Data; // MU_CHANGE - Standalone MM Perf Support
ZeroMem ((UINT8 *)SmmCommData, sizeof (SMM_BOOT_RECORD_COMMUNICATE));
- CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);
- SmmCommBufferHeader->MessageLength = sizeof (SMM_BOOT_RECORD_COMMUNICATE);
- CommSize = SMM_BOOT_RECORD_COMM_SIZE;
+ CopyGuid (&MmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid); // MU_CHANGE - Standalone MM Perf Support
+ MmCommBufferHeader->MessageLength = sizeof (SMM_BOOT_RECORD_COMMUNICATE); // MU_CHANGE - Standalone MM Perf Support
+ CommSize = SMM_BOOT_RECORD_COMM_SIZE;
//
// Get the size of boot records.
@@ -292,7 +296,14 @@ InternalGetSmmPerfData (
SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
SmmCommData->BootRecordData = NULL;
Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
+ // MU_CHANGE [BEGIN] - Standalone MM Perf Support
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Perf handler MMI not found or communicate failed. Status = %r.\n", Status));
+ } else if (EFI_ERROR (SmmCommData->ReturnStatus)) {
+ DEBUG ((DEBUG_ERROR, "Perf handler MMI returned an error. Status = %r.\n", SmmCommData->ReturnStatus));
+ }
+ // MU_CHANGE [END] - Standalone MM Perf Support
if (!EFI_ERROR (Status) && !EFI_ERROR (SmmCommData->ReturnStatus) && (SmmCommData->BootRecordSize != 0)) {
if (SkipGetPerfData) {
*SmmPerfDataSize = SmmCommData->BootRecordSize;
@@ -308,26 +319,42 @@ InternalGetSmmPerfData (
SmmBootRecordData = AllocateZeroPool (SmmBootRecordDataSize);
SmmBootRecordDataRetrieved = 0;
ASSERT (SmmBootRecordData != NULL);
- SmmCommData->BootRecordData = (VOID *)((UINTN)SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
- SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;
- while (SmmBootRecordDataRetrieved < SmmBootRecordDataSize) {
- Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
- ASSERT_EFI_ERROR (Status);
- ASSERT_EFI_ERROR (SmmCommData->ReturnStatus);
- if (SmmBootRecordDataRetrieved + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
- CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmBootRecordDataRetrieved);
- } else {
- CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
+ // MU_CHANGE [BEGIN] - Standalone MM Perf Support
+ if (SmmBootRecordData != NULL) {
+ CurrentBootRecordData = (VOID *)((UINTN)SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
+ while (SmmBootRecordDataRetrieved < SmmBootRecordDataSize) {
+ // Note: Maximum comm buffer data payload size is ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE
+ BootRecordDataPayloadSize = MIN (
+ ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE,
+ SmmBootRecordDataSize - SmmBootRecordDataRetrieved
+ );
+
+ MmCommBufferHeader->MessageLength = sizeof (SMM_BOOT_RECORD_COMMUNICATE) + BootRecordDataPayloadSize;
+ CommSize = sizeof (EFI_MM_COMMUNICATE_HEADER) + (UINTN)MmCommBufferHeader->MessageLength;
+
+ Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status) || EFI_ERROR (SmmCommData->ReturnStatus)) {
+ break;
+ }
+
+ if (SmmBootRecordDataRetrieved + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
+ CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, CurrentBootRecordData, SmmBootRecordDataSize - SmmBootRecordDataRetrieved);
+ } else {
+ CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, CurrentBootRecordData, SmmCommData->BootRecordSize);
+ }
+
+ SmmBootRecordDataRetrieved += SmmCommData->BootRecordSize;
+ SmmCommData->BootRecordOffset += SmmCommData->BootRecordSize;
}
- SmmBootRecordDataRetrieved += SmmCommData->BootRecordSize;
- SmmCommData->BootRecordOffset += SmmCommData->BootRecordSize;
- }
+ mSmmBootRecordOffset = SmmCommData->BootRecordOffset;
- mSmmBootRecordOffset = SmmCommData->BootRecordOffset;
+ *SmmPerfData = SmmBootRecordData;
+ *SmmPerfDataSize = SmmBootRecordDataSize;
+ }
- *SmmPerfData = SmmBootRecordData;
- *SmmPerfDataSize = SmmBootRecordDataSize;
+ // MU_CHANGE [END] - Standalone MM Perf Support
}
}
}
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/MmCorePerformanceLib.c b/MdeModulePkg/Library/SmmCorePerformanceLib/MmCorePerformanceLib.c
new file mode 100644
index 0000000000..91585e9ca4
--- /dev/null
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/MmCorePerformanceLib.c
@@ -0,0 +1,1383 @@
+/** @file
+ This library is mainly used by a MM Core to start performance logging to ensure that
+ MM Performance and PerformanceEx Protocol are installed as early as possible in the MM phase.
+
+ Caution: This module requires additional review when modified.
+ - This driver will have external input - performance data and communicate buffer in SMM mode.
+ - This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
+
+ Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ MU_CHANGE [WHOLE FILE] - Standalone MM Perf Support
+
+**/
+
+#include "SmmCorePerformanceLibInternal.h"
+
+#include
+#include
+
+SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+ EFI_GUID ModuleGuid;
+} HANDLE_GUID_MAP;
+
+HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
+UINTN mCachePairCount = 0;
+
+UINT32 mPerformanceLength = sizeof (SMM_BOOT_PERFORMANCE_TABLE);
+UINT32 mMaxPerformanceLength = 0;
+UINT32 mLoadImageCount = 0;
+BOOLEAN mFpdtDataIsReported = FALSE;
+BOOLEAN mLackSpaceIsReport = FALSE;
+SPIN_LOCK mSmmFpdtLock;
+UINT32 mCachedLength = 0;
+UINT32 mBootRecordSize = 0;
+BOOLEAN mPerformanceMeasurementEnabled;
+
+//
+// Interfaces for SMM PerformanceMeasurement Protocol.
+//
+EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
+ CreatePerformanceMeasurement,
+};
+
+/**
+ Return the module name and optionally module GUID for a given handle.
+
+ @param[in] Handle The image handle.
+ @param[out] NameString The buffer to store the name string.
+ @param[in] BufferSize The size of the NameString buffer in bytes.
+ @param[out] ModuleGuid An optional buffer to store the module GUID.
+
+ @retval EFI_SUCCESS The module information was successfully retrieved.
+ @retval EFI_INVALID_PARAMETER A required pointer argument is null or the given handle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+GetModuleInfoFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize,
+ OUT EFI_GUID *ModuleGuid OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_GUID *TempGuid;
+ INTN Count;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
+
+ if ((Handle == NULL) || (NameString == NULL) || (BufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Try to get the ModuleGuid and name string form the cached array.
+ //
+ if (mCachePairCount > 0) {
+ for (Count = mCachePairCount - 1; Count >= 0; Count--) {
+ if (Handle == mCacheHandleGuidTable[Count].Handle) {
+ CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
+ AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ NameString[0] = 0;
+ TempGuid = &gZeroGuid;
+
+ LoadedImage = GetLoadedImageProtocol (Handle);
+ if (LoadedImage != NULL) {
+ //
+ // Get Module Guid from DevicePath.
+ //
+ if ((LoadedImage->FilePath != NULL) &&
+ (LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH) &&
+ (LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP)
+ )
+ {
+ //
+ // Determine GUID associated with module logging performance
+ //
+ FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath;
+ TempGuid = &FvFilePath->FvFileName;
+ }
+
+ if (GetModuleNameFromPdbString (LoadedImage->ImageBase, NameString, BufferSize) == EFI_SUCCESS) {
+ goto Done;
+ }
+ }
+
+ if (!IsZeroGuid (TempGuid)) {
+ Status = GetNameFromUiSection (TempGuid, NameString, BufferSize);
+ }
+
+Done:
+ //
+ // Copy Module Guid
+ //
+ if (ModuleGuid != NULL) {
+ CopyGuid (ModuleGuid, TempGuid);
+ if (IsZeroGuid (TempGuid) && (Handle != NULL)) {
+ // Handle is GUID
+ CopyGuid (ModuleGuid, (EFI_GUID *)Handle);
+ }
+ }
+
+ //
+ // Cache the Handle and Guid pairs.
+ //
+ if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
+ mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
+ CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
+ AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
+ mCachePairCount++;
+ }
+
+ return Status;
+}
+
+/**
+ Get the module name from the PDB file name in the image header.
+
+ @param[in] ImageBase The base address of the image.
+ @param[out] NameString The buffer to store the name string.
+ @param[in] BufferSize The size of the buffer in bytes.
+
+ @retval EFI_SUCCESS The name string is successfully retrieved.
+ @retval EFI_INVALID_PARAMETER A pointer argument provided is null.
+ @retval EFI_NOT_FOUND The module name was not found.
+
+**/
+EFI_STATUS
+GetModuleNameFromPdbString (
+ IN VOID *ImageBase,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize
+ )
+{
+ CHAR8 *PdbFileName;
+ UINTN Index;
+ UINTN StartIndex;
+
+ if ((ImageBase == NULL) || (NameString == NULL) || (BufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PdbFileName = PeCoffLoaderGetPdbPointer (ImageBase);
+
+ for (StartIndex = 0, Index = 0; PdbFileName[Index] != 0; Index++) {
+ if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+
+ //
+ // Copy the PDB file name to our temporary string.
+ // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < BufferSize - 1; Index++) {
+ NameString[Index] = PdbFileName[Index + StartIndex];
+ if ((NameString[Index] == 0) || (NameString[Index] == '.')) {
+ NameString[Index] = 0;
+ break;
+ }
+ }
+
+ if (Index == BufferSize - 1) {
+ NameString[Index] = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the pointer to the FPDT record in the allocated memory.
+
+ @param RecordSize The size of FPDT record.
+ @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.
+
+ @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.
+ @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+ IN UINT8 RecordSize,
+ IN OUT FPDT_RECORD_PTR *FpdtRecordPtr
+ )
+{
+ if (mFpdtDataIsReported) {
+ //
+ // Append Boot records after Smm boot performance records have been reported.
+ //
+ if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+ if (!mLackSpaceIsReport) {
+ DEBUG ((DEBUG_ERROR, "[%a] - Not enough space to save boot records\n", __func__));
+ mLackSpaceIsReport = TRUE;
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Covert buffer to FPDT Ptr Union type.
+ //
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
+ }
+ } else {
+ //
+ // Check if pre-allocated buffer is full
+ //
+ if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+ mSmmBootPerformanceTable = ReallocatePool (
+ mPerformanceLength,
+ mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,
+ mSmmBootPerformanceTable
+ );
+
+ if (mSmmBootPerformanceTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mSmmBootPerformanceTable->Header.Length = mPerformanceLength;
+ mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;
+ }
+
+ //
+ // Covert buffer to FPDT Ptr Union type.
+ //
+ FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
+ }
+
+ FpdtRecordPtr->RecordHeader->Length = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+Check whether the Token is a known one which is uesed by core.
+
+@param Token Pointer to a Null-terminated ASCII string
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownTokens (
+ IN CONST CHAR8 *Token
+ )
+{
+ if (Token == NULL) {
+ return FALSE;
+ }
+
+ if ((AsciiStrCmp (Token, SEC_TOK) == 0) ||
+ (AsciiStrCmp (Token, PEI_TOK) == 0) ||
+ (AsciiStrCmp (Token, DXE_TOK) == 0) ||
+ (AsciiStrCmp (Token, BDS_TOK) == 0) ||
+ (AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0) ||
+ (AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0) ||
+ (AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0) ||
+ (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) ||
+ (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) ||
+ (AsciiStrCmp (Token, PEIM_TOK) == 0))
+ {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+Check whether the ID is a known one which map to the known Token.
+
+@param Identifier 32-bit identifier.
+
+@retval TRUE Is a known one used by core.
+@retval FALSE Not a known one.
+
+**/
+BOOLEAN
+IsKnownID (
+ IN UINT32 Identifier
+ )
+{
+ if ((Identifier == MODULE_START_ID) ||
+ (Identifier == MODULE_END_ID) ||
+ (Identifier == MODULE_LOADIMAGE_START_ID) ||
+ (Identifier == MODULE_LOADIMAGE_END_ID) ||
+ (Identifier == MODULE_DB_START_ID) ||
+ (Identifier == MODULE_DB_END_ID) ||
+ (Identifier == MODULE_DB_SUPPORT_START_ID) ||
+ (Identifier == MODULE_DB_SUPPORT_END_ID) ||
+ (Identifier == MODULE_DB_STOP_START_ID) ||
+ (Identifier == MODULE_DB_STOP_END_ID))
+ {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Get the FPDT record identifier.
+
+ @param Attribute The attribute of the Record.
+ PerfStartEntry: Start Record.
+ PerfEndEntry: End Record.
+ @param Handle Pointer to environment specific context used to identify the component being measured.
+ @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.
+ @param ProgressID On return, pointer to the ProgressID.
+
+ @retval EFI_SUCCESS Get record info successfully.
+ @retval EFI_INVALID_PARAMETER No matched FPDT record.
+
+**/
+EFI_STATUS
+GetFpdtRecordId (
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute,
+ IN CONST VOID *Handle,
+ IN CONST CHAR8 *String,
+ OUT UINT16 *ProgressID
+ )
+{
+ //
+ // Token to Id.
+ //
+ if (String != NULL) {
+ if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) {
+ // "StartImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_START_ID;
+ } else {
+ *ProgressID = MODULE_END_ID;
+ }
+ } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {
+ // "LoadImage:"
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = MODULE_LOADIMAGE_START_ID;
+ } else {
+ *ProgressID = MODULE_LOADIMAGE_END_ID;
+ }
+ } else {
+ // Pref used in Modules
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ }
+ } else if (Handle != NULL) {
+ // Pref used in Modules
+ if (Attribute == PerfStartEntry) {
+ *ProgressID = PERF_INMODULE_START_ID;
+ } else {
+ *ProgressID = PERF_INMODULE_END_ID;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Copies the string from Source into Destination and updates Length with the
+ size of the string.
+
+ @param Destination - destination of the string copy
+ @param Source - pointer to the source string which will get copied
+ @param Length - pointer to a length variable to be updated
+
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+ IN OUT CHAR8 *Destination,
+ IN CONST CHAR8 *Source,
+ IN OUT UINT8 *Length
+ )
+{
+ UINTN StringLen;
+ UINTN DestMax;
+
+ ASSERT (Source != NULL);
+
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ DestMax = STRING_SIZE;
+ } else {
+ DestMax = AsciiStrSize (Source);
+ if (DestMax > STRING_SIZE) {
+ DestMax = STRING_SIZE;
+ }
+ }
+
+ StringLen = AsciiStrLen (Source);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+
+ AsciiStrnCpyS (Destination, DestMax, Source, StringLen);
+ *Length += (UINT8)DestMax;
+
+ return;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param Ticker - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param PerfId - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+
+ @retval EFI_SUCCESS - Successfully created performance record
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+EFI_STATUS
+InsertFpdtRecord (
+ IN CONST VOID *CallerIdentifier OPTIONAL,
+ IN CONST VOID *Guid OPTIONAL,
+ IN CONST CHAR8 *String OPTIONAL,
+ IN UINT64 Ticker,
+ IN UINT64 Address OPTIONAL,
+ IN UINT16 PerfId,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_GUID ModuleGuid;
+ CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+ FPDT_RECORD_PTR FpdtRecordPtr;
+ FPDT_RECORD_PTR CachedFpdtRecordPtr;
+ UINT64 TimeStamp;
+ CONST CHAR8 *StringPtr;
+ UINTN DestMax;
+ UINTN StringLen;
+ UINT16 ProgressId;
+
+ StringPtr = NULL;
+ ZeroMem (ModuleName, sizeof (ModuleName));
+
+ //
+ // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
+ // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
+ //
+ if (Attribute != PerfEntry) {
+ //
+ // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
+ // !!! Note: If the Perf is not the known Token used in the core but have same
+ // ID with the core Token, this case will not be supported.
+ // And in currtnt usage mode, for the unkown ID, there is a general rule:
+ // If it is start pref: the lower 4 bits of the ID should be 0.
+ // If it is end pref: the lower 4 bits of the ID should not be 0.
+ // If input ID doesn't follow the rule, we will adjust it.
+ //
+ if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+ if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
+ PerfId &= 0xFFF0;
+ } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+ PerfId += 1;
+ }
+ }
+
+ if (PerfId == 0) {
+ //
+ // Get ProgressID form the String Token.
+ //
+ Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PerfId = ProgressId;
+ }
+ }
+
+ //
+ // 2. Get the buffer to store the FPDT record.
+ //
+ Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 3. Get the TimeStamp.
+ //
+ if (Ticker == 0) {
+ Ticker = GetPerformanceCounter ();
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ } else if (Ticker == 1) {
+ TimeStamp = 0;
+ } else {
+ TimeStamp = GetTimeInNanoSecond (Ticker);
+ }
+
+ //
+ // 4. Fill in the FPDT record according to different Performance Identifier.
+ //
+ switch (PerfId) {
+ case MODULE_START_ID:
+ case MODULE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ //
+ // Cache the offset of start image start record and use to update the start image end record if needed.
+ //
+ if ((PerfId == MODULE_START_ID) && (Attribute == PerfEntry)) {
+ mCachedLength = mSmmBootPerformanceTable->Header.Length;
+ }
+
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
+ FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);
+ FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+ if ((CallerIdentifier == NULL) && (PerfId == MODULE_END_ID) && (mCachedLength != 0)) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mCachedLength);
+ CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+ mCachedLength = 0;
+ }
+ }
+
+ break;
+
+ case MODULE_LOADIMAGE_START_ID:
+ case MODULE_LOADIMAGE_END_ID:
+ GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ StringPtr = ModuleName;
+ if (PerfId == MODULE_LOADIMAGE_START_ID) {
+ mLoadImageCount++;
+ //
+ // Cache the offset of load image start record and use to be updated by the load image end record if needed.
+ //
+ if ((CallerIdentifier == NULL) && (Attribute == PerfEntry)) {
+ mCachedLength = mSmmBootPerformanceTable->Header.Length;
+ }
+ }
+
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
+ FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+ FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
+ FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
+ FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;
+ CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
+ if ((PerfId == MODULE_LOADIMAGE_END_ID) && (mCachedLength != 0)) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mCachedLength);
+ CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
+ mCachedLength = 0;
+ }
+ }
+
+ break;
+
+ case PERF_EVENTSIGNAL_START_ID:
+ case PERF_EVENTSIGNAL_END_ID:
+ case PERF_CALLBACK_START_ID:
+ case PERF_CALLBACK_END_ID:
+ if ((String == NULL) || (Guid == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringPtr = String;
+ if (AsciiStrLen (String) == 0) {
+ StringPtr = "unknown name";
+ }
+
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
+ CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
+ }
+
+ break;
+
+ case PERF_EVENT_ID:
+ case PERF_FUNCTION_START_ID:
+ case PERF_FUNCTION_END_ID:
+ case PERF_INMODULE_START_ID:
+ case PERF_INMODULE_END_ID:
+ case PERF_CROSSMODULE_START_ID:
+ case PERF_CROSSMODULE_END_ID:
+ // MU_CHANGE [BEGIN] - CodeQL change
+ Status = GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get Module Info from Handle! Status = %r\n", Status));
+ }
+
+ StringPtr = NULL;
+
+ if (String != NULL) {
+ StringPtr = String;
+ } else if (ModuleName != NULL) {
+ StringPtr = ModuleName;
+ }
+
+ if ((StringPtr == NULL) || (AsciiStrLen (StringPtr) == 0)) {
+ StringPtr = "unknown name";
+ }
+
+ // MU_CHANGE [END] - CodeQL change
+
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+
+ break;
+
+ default:
+ if (Attribute != PerfEntry) {
+ // MU_CHANGE [BEGIN] - CodeQL change
+ Status = GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get Module Info from Handle! Status = %r\n", Status));
+ }
+
+ StringPtr = NULL;
+
+ if (String != NULL) {
+ StringPtr = String;
+ } else if (ModuleName != NULL) {
+ StringPtr = ModuleName;
+ }
+
+ if ((StringPtr == NULL) || (AsciiStrLen (StringPtr) == 0)) {
+ StringPtr = "unknown name";
+ }
+
+ // MU_CHANGE [END] - CodeQL change
+
+ if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+ }
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ //
+ // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
+ //
+ if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+ if (StringPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+ FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
+ FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
+ if (Guid != NULL) {
+ //
+ // Cache the event guid in string event record.
+ //
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ } else {
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+ }
+
+ if (AsciiStrLen (StringPtr) == 0) {
+ StringPtr = "unknown name";
+ }
+
+ CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
+
+ if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
+ FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
+ }
+
+ if (((PerfId == MODULE_LOADIMAGE_END_ID) || (PerfId == MODULE_END_ID)) && (mCachedLength != 0)) {
+ CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mCachedLength);
+ if (PerfId == MODULE_LOADIMAGE_END_ID) {
+ DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ StringLen = AsciiStrLen (StringPtr);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+
+ CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+ AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);
+ } else if (PerfId == MODULE_END_ID) {
+ DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+ StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);
+ if (StringLen >= DestMax) {
+ StringLen = DestMax -1;
+ }
+
+ CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+ AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
+ }
+
+ mCachedLength = 0;
+ }
+ }
+
+ //
+ // 5. Update the length of the used buffer after fill in the record.
+ //
+ mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
+ mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for report MM boot records.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtSmiHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
+ UINTN BootRecordOffset;
+ UINTN BootRecordSize;
+ VOID *BootRecordData;
+ UINTN TempCommBufferSize;
+ UINT8 *BootRecordBuffer;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!IsCommBufferValidInternal ((UINTN)CommBuffer, TempCommBufferSize)) {
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
+ }
+
+ SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE *)CommBuffer;
+
+ Status = EFI_SUCCESS;
+
+ switch (SmmCommData->Function) {
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE:
+ DEBUG ((DEBUG_VERBOSE, "[%a] - SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE entry.\n", __func__));
+ if (mSmmBootPerformanceTable != NULL) {
+ mBootRecordSize = mSmmBootPerformanceTable->Header.Length - sizeof (SMM_BOOT_PERFORMANCE_TABLE);
+ }
+
+ SmmCommData->BootRecordSize = mBootRecordSize;
+ break;
+
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA:
+ DEBUG ((DEBUG_VERBOSE, "[%a] - SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA entry.\n", __func__));
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET:
+ DEBUG ((DEBUG_VERBOSE, "[%a] - SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET entry.\n", __func__));
+ BootRecordOffset = SmmCommData->BootRecordOffset;
+ BootRecordData = SmmCommData->BootRecordData;
+ BootRecordSize = SmmCommData->BootRecordSize;
+
+ if (BootRecordOffset >= mBootRecordSize) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (BootRecordData == NULL) {
+ BootRecordData = (UINT8 *)SmmCommData + sizeof (SMM_BOOT_RECORD_COMMUNICATE);
+ } else if (!IsBufferOutsideMmValidInternal ((UINTN)BootRecordData, BootRecordSize)) {
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ //
+ // Sanity check
+ //
+ if (BootRecordSize > mBootRecordSize - BootRecordOffset) {
+ BootRecordSize = mBootRecordSize - BootRecordOffset;
+ }
+
+ // Note: Comm size passed to this handler already has OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) removed.
+ if ((SmmCommData->BootRecordData == NULL) && (BootRecordSize - BootRecordOffset > TempCommBufferSize - sizeof (SMM_BOOT_RECORD_COMMUNICATE))) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ SmmCommData->BootRecordSize = BootRecordSize;
+ BootRecordBuffer = ((UINT8 *)(mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);
+ CopyMem (
+ (UINT8 *)BootRecordData,
+ BootRecordBuffer + BootRecordOffset,
+ BootRecordSize
+ );
+ mFpdtDataIsReported = TRUE;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+ SmmCommData->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the Event call back function is triggered in SMM to notify the Library
+ the system is entering runtime phase.
+
+ @param[in] Protocol Points to the protocol's unique identifier
+ @param[in] Interface Points to the interface instance
+ @param[in] Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully
+ **/
+EFI_STATUS
+EFIAPI
+SmmCorePerformanceLibExitBootServicesCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ //
+ // Disable performance measurement after ExitBootServices because
+ // 1. Performance measurement might impact SMI latency at runtime;
+ // 2. Performance log is copied to non SMRAM at ReadyToBoot so runtime performance
+ // log is not useful.
+ //
+ mPerformanceMeasurementEnabled = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Common initialization code for the MM Core Performance Library.
+
+ @retval EFI_SUCCESS The MM Core Performance Library was initialized successfully.
+ @retval Others The MM Core Performance Library was not initialized successfully.
+ **/
+EFI_STATUS
+InitializeMmCorePerformanceLibCommon (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_HANDLE MmiHandle;
+ VOID *Registration;
+
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mSmmFpdtLock);
+
+ //
+ // Install the protocol interfaces for MM performance library instance.
+ //
+ Handle = NULL;
+ Status = gMmst->MmInstallProtocolInterface (
+ &Handle,
+ &gEdkiiSmmPerformanceMeasurementProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPerformanceMeasurementInterface
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register MMI handler.
+ //
+ MmiHandle = NULL;
+ Status = gMmst->MmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &MmiHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Register callback function for ExitBootServices event.
+ //
+ Status = gMmst->MmRegisterProtocolNotify (
+ &gEdkiiSmmExitBootServicesProtocolGuid,
+ SmmCorePerformanceLibExitBootServicesCallback,
+ &Registration
+ );
+
+ return Status;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID.
+ @param Guid - Pointer to a GUID.
+ @param String - Pointer to a string describing the measurement.
+ @param TimeStamp - 64-bit time stamp.
+ @param Address - Pointer to a location in memory relevant to the measurement.
+ @param Identifier - Performance identifier describing the type of measurement.
+ @param Attribute - The attribute of the measurement. According to attribute can create a start
+ record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
+ or a general record for other Perf macros.
+
+ @retval EFI_SUCCESS - Successfully created performance record.
+ @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId.
+**/
+EFI_STATUS
+EFIAPI
+CreatePerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier OPTIONAL,
+ IN CONST VOID *Guid OPTIONAL,
+ IN CONST CHAR8 *String OPTIONAL,
+ IN UINT64 TimeStamp OPTIONAL,
+ IN UINT64 Address OPTIONAL,
+ IN UINT32 Identifier,
+ IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ AcquireSpinLock (&mSmmFpdtLock);
+ Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);
+ ReleaseSpinLock (&mSmmFpdtLock);
+ return Status;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle OPTIONAL,
+ IN CONST CHAR8 *Token OPTIONAL,
+ IN CONST CHAR8 *Module OPTIONAL,
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle OPTIONAL,
+ IN CONST CHAR8 *Token OPTIONAL,
+ IN CONST CHAR8 *Module OPTIONAL,
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ CONST CHAR8 *String;
+
+ if (Token != NULL) {
+ String = Token;
+ } else if (Module != NULL) {
+ String = Module;
+ } else {
+ String = NULL;
+ }
+
+ return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ !!! Not Support!!!
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ return 0;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle OPTIONAL,
+ IN CONST CHAR8 *Token OPTIONAL,
+ IN CONST CHAR8 *Module OPTIONAL,
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle OPTIONAL,
+ IN CONST CHAR8 *Token OPTIONAL,
+ IN CONST CHAR8 *Module OPTIONAL,
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ !!! Not Support!!!
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ return 0;
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return mPerformanceMeasurementEnabled;
+}
+
+/**
+ Create performance record with event description and a timestamp.
+
+ @param CallerIdentifier - Image handle or pointer to caller ID GUID
+ @param Guid - Pointer to a GUID
+ @param String - Pointer to a string describing the measurement
+ @param Address - Pointer to a location in memory relevant to the measurement
+ @param Identifier - Performance identifier describing the type of measurement
+
+ @retval RETURN_SUCCESS - Successfully created performance record
+ @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
+ @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+ pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+ IN CONST VOID *CallerIdentifier,
+ IN CONST VOID *Guid OPTIONAL,
+ IN CONST CHAR8 *String OPTIONAL,
+ IN UINT64 Address OPTIONAL,
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+}
+
+/**
+ Check whether the specified performance measurement can be logged.
+
+ This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
+ and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+ @param Type - Type of the performance measurement entry.
+
+ @retval TRUE The performance measurement can be logged.
+ @retval FALSE The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+ IN CONST UINTN Type
+ )
+{
+ //
+ // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
+ //
+ if (PerformanceMeasurementEnabled () && ((PcdGet8 (PcdPerformanceLibraryPropertyMask) & Type) == 0)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
index bb96fdcd7c..ece5bd28e1 100644
--- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
@@ -17,972 +17,172 @@
SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
Copyright (c) 2011 - 2023, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
+MU_CHANGE [WHOLE FILE] - Standalone MM Perf Support
+
**/
#include "SmmCorePerformanceLibInternal.h"
-#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
-#define FIRMWARE_RECORD_BUFFER 0x1000
-#define CACHE_HANDLE_GUID_COUNT 0x100
-
-SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;
-
-typedef struct {
- EFI_HANDLE Handle;
- CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
- EFI_GUID ModuleGuid;
-} HANDLE_GUID_MAP;
-
-HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
-UINTN mCachePairCount = 0;
+#include
+#include
+#include
+#include
+#include
-UINT32 mPerformanceLength = sizeof (SMM_BOOT_PERFORMANCE_TABLE);
-UINT32 mMaxPerformanceLength = 0;
-UINT32 mLoadImageCount = 0;
-BOOLEAN mFpdtDataIsReported = FALSE;
-BOOLEAN mLackSpaceIsReport = FALSE;
-CHAR8 *mPlatformLanguage = NULL;
-SPIN_LOCK mSmmFpdtLock;
PERFORMANCE_PROPERTY mPerformanceProperty;
-UINT32 mCachedLength = 0;
-UINT32 mBootRecordSize = 0;
-BOOLEAN mPerformanceMeasurementEnabled;
-
-//
-// Interfaces for SMM PerformanceMeasurement Protocol.
-//
-EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
- CreatePerformanceMeasurement,
-};
+extern BOOLEAN mPerformanceMeasurementEnabled;
/**
- Return the pointer to the FPDT record in the allocated memory.
+ A library internal MM-instance specific implementation to check if a buffer outside MM is valid.
- @param RecordSize The size of FPDT record.
- @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.
+ This function is provided so Standalone MM and Traditional MM may use a different implementation
+ of data buffer check logic.
- @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.
- @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.
-**/
-EFI_STATUS
-GetFpdtRecordPtr (
- IN UINT8 RecordSize,
- IN OUT FPDT_RECORD_PTR *FpdtRecordPtr
- )
-{
- if (mFpdtDataIsReported) {
- //
- // Append Boot records after Smm boot performance records have been reported.
- //
- if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
- if (!mLackSpaceIsReport) {
- DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));
- mLackSpaceIsReport = TRUE;
- }
-
- return EFI_OUT_OF_RESOURCES;
- } else {
- //
- // Covert buffer to FPDT Ptr Union type.
- //
- FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
- }
- } else {
- //
- // Check if pre-allocated buffer is full
- //
- if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
- mSmmBootPerformanceTable = ReallocatePool (
- mPerformanceLength,
- mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,
- mSmmBootPerformanceTable
- );
-
- if (mSmmBootPerformanceTable == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- mSmmBootPerformanceTable->Header.Length = mPerformanceLength;
- mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;
- }
-
- //
- // Covert buffer to FPDT Ptr Union type.
- //
- FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
- }
-
- FpdtRecordPtr->RecordHeader->Length = 0;
- return EFI_SUCCESS;
-}
-
-/**
-Check whether the Token is a known one which is uesed by core.
-
-@param Token Pointer to a Null-terminated ASCII string
-
-@retval TRUE Is a known one used by core.
-@retval FALSE Not a known one.
+ @param[in] Buffer The buffer start address to be checked.
+ @param[in] Length The buffer length to be checked.
+ @retval TRUE This buffer is valid per processor architecture.
+ @retval FALSE This buffer is not valid per processor architecture.
**/
BOOLEAN
-IsKnownTokens (
- IN CONST CHAR8 *Token
+IsBufferOutsideMmValidInternal (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
)
{
- if (Token == NULL) {
- return FALSE;
- }
-
- if ((AsciiStrCmp (Token, SEC_TOK) == 0) ||
- (AsciiStrCmp (Token, PEI_TOK) == 0) ||
- (AsciiStrCmp (Token, DXE_TOK) == 0) ||
- (AsciiStrCmp (Token, BDS_TOK) == 0) ||
- (AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0) ||
- (AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0) ||
- (AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0) ||
- (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) ||
- (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) ||
- (AsciiStrCmp (Token, PEIM_TOK) == 0))
- {
- return TRUE;
- } else {
- return FALSE;
- }
+ return SmmIsBufferOutsideSmmValid (Buffer, Length);
}
/**
-Check whether the ID is a known one which map to the known Token.
+ A library internal MM-instance specific implementation to check if a comm buffer is valid.
-@param Identifier 32-bit identifier.
+ This function is provided so Standalone MM and Traditional MM may use a different implementation
+ of comm buffer check logic.
-@retval TRUE Is a known one used by core.
-@retval FALSE Not a known one.
+ @param[in] Buffer The buffer start address to be checked.
+ @param[in] Length The buffer length to be checked.
+ @retval TRUE This communicate buffer is valid per processor architecture.
+ @retval FALSE This communicate buffer is not valid per processor architecture.
**/
BOOLEAN
-IsKnownID (
- IN UINT32 Identifier
- )
-{
- if ((Identifier == MODULE_START_ID) ||
- (Identifier == MODULE_END_ID) ||
- (Identifier == MODULE_LOADIMAGE_START_ID) ||
- (Identifier == MODULE_LOADIMAGE_END_ID) ||
- (Identifier == MODULE_DB_START_ID) ||
- (Identifier == MODULE_DB_END_ID) ||
- (Identifier == MODULE_DB_SUPPORT_START_ID) ||
- (Identifier == MODULE_DB_SUPPORT_END_ID) ||
- (Identifier == MODULE_DB_STOP_START_ID) ||
- (Identifier == MODULE_DB_STOP_END_ID))
- {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Get the FPDT record identifier.
-
- @param Attribute The attribute of the Record.
- PerfStartEntry: Start Record.
- PerfEndEntry: End Record.
- @param Handle Pointer to environment specific context used to identify the component being measured.
- @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.
- @param ProgressID On return, pointer to the ProgressID.
-
- @retval EFI_SUCCESS Get record info successfully.
- @retval EFI_INVALID_PARAMETER No matched FPDT record.
-
-**/
-EFI_STATUS
-GetFpdtRecordId (
- IN PERF_MEASUREMENT_ATTRIBUTE Attribute,
- IN CONST VOID *Handle,
- IN CONST CHAR8 *String,
- OUT UINT16 *ProgressID
+IsCommBufferValidInternal (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
)
{
- //
- // Token to Id.
- //
- if (String != NULL) {
- if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) {
- // "StartImage:"
- if (Attribute == PerfStartEntry) {
- *ProgressID = MODULE_START_ID;
- } else {
- *ProgressID = MODULE_END_ID;
- }
- } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {
- // "LoadImage:"
- if (Attribute == PerfStartEntry) {
- *ProgressID = MODULE_LOADIMAGE_START_ID;
- } else {
- *ProgressID = MODULE_LOADIMAGE_END_ID;
- }
- } else {
- // Pref used in Modules
- if (Attribute == PerfStartEntry) {
- *ProgressID = PERF_INMODULE_START_ID;
- } else {
- *ProgressID = PERF_INMODULE_END_ID;
- }
- }
- } else if (Handle != NULL) {
- // Pref used in Modules
- if (Attribute == PerfStartEntry) {
- *ProgressID = PERF_INMODULE_START_ID;
- } else {
- *ProgressID = PERF_INMODULE_END_ID;
- }
- } else {
- return EFI_UNSUPPORTED;
- }
-
- return EFI_SUCCESS;
+ return SmmIsBufferOutsideSmmValid (Buffer, Length);
}
/**
- Get a human readable module name and module guid for the given image handle.
- If module name can't be found, "" string will return.
- If module guid can't be found, Zero Guid will return.
+ Return a pointer to the loaded image protocol for the given handle.
- @param Handle Image handle or Controller handle.
- @param NameString The ascii string will be filled into it. If not found, null string will return.
- @param BufferSize Size of the input NameString buffer.
- @param ModuleGuid Point to the guid buffer to store the got module guid value.
+ @param[in] Handle A handle to query for the loaded image protocol.
- @retval EFI_SUCCESS Successfully get module name and guid.
- @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.
- @retval other value Module Name can't be got.
+ @return A pointer to a loaded image protocol instance or null if the handle does not support load image protocol.
**/
-EFI_STATUS
-EFIAPI
-GetModuleInfoFromHandle (
- IN EFI_HANDLE Handle,
- OUT CHAR8 *NameString,
- IN UINTN BufferSize,
- OUT EFI_GUID *ModuleGuid OPTIONAL
+EFI_LOADED_IMAGE_PROTOCOL *
+GetLoadedImageProtocol (
+ IN EFI_HANDLE Handle
)
{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
- CHAR8 *PdbFileName;
- EFI_GUID *TempGuid;
- UINTN StartIndex;
- UINTN Index;
- INTN Count;
- BOOLEAN ModuleGuidIsGet;
- UINTN StringSize;
- CHAR16 *StringPtr;
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
-
- if ((NameString == NULL) || (BufferSize == 0)) {
- return EFI_INVALID_PARAMETER;
- }
+ EFI_STATUS Status;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- //
- // Try to get the ModuleGuid and name string form the caached array.
- //
- if (mCachePairCount > 0) {
- for (Count = mCachePairCount - 1; Count >= 0; Count--) {
- if (Handle == mCacheHandleGuidTable[Count].Handle) {
- CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
- AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
- return EFI_SUCCESS;
- }
- }
+ if ((Handle == NULL) || (LoadedImage == NULL)) {
+ return NULL;
}
- Status = EFI_INVALID_PARAMETER;
- LoadedImage = NULL;
- ModuleGuidIsGet = FALSE;
+ LoadedImage = NULL;
//
- // Initialize GUID as zero value.
- //
- TempGuid = &gZeroGuid;
- //
- // Initialize it as "" string.
+ // Try Handle as ImageHandle.
//
- NameString[0] = 0;
-
- if (Handle != NULL) {
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
//
- // Try Handle as ImageHandle.
+ // Try Handle as Controller Handle
//
- Status = gBS->HandleProtocol (
+ Status = gBS->OpenProtocol (
Handle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **)&DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
-
- if (EFI_ERROR (Status)) {
- //
- // Try Handle as Controller Handle
- //
- Status = gBS->OpenProtocol (
- Handle,
- &gEfiDriverBindingProtocolGuid,
- (VOID **)&DriverBinding,
- NULL,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
- //
- // Get Image protocol from ImageHandle
- //
- Status = gBS->HandleProtocol (
- DriverBinding->ImageHandle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- }
- }
- }
-
- if (!EFI_ERROR (Status) && (LoadedImage != NULL)) {
- //
- // Get Module Guid from DevicePath.
- //
- if ((LoadedImage->FilePath != NULL) &&
- (LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH) &&
- (LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP)
- )
- {
- //
- // Determine GUID associated with module logging performance
- //
- ModuleGuidIsGet = TRUE;
- FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath;
- TempGuid = &FvFilePath->FvFileName;
- }
-
- //
- // Method 1 Get Module Name from PDB string.
- //
- PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
- if ((PdbFileName != NULL) && (BufferSize > 0)) {
- StartIndex = 0;
- for (Index = 0; PdbFileName[Index] != 0; Index++) {
- if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
- StartIndex = Index + 1;
- }
- }
-
- //
- // Copy the PDB file name to our temporary string.
- // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
- //
- for (Index = 0; Index < BufferSize - 1; Index++) {
- NameString[Index] = PdbFileName[Index + StartIndex];
- if ((NameString[Index] == 0) || (NameString[Index] == '.')) {
- NameString[Index] = 0;
- break;
- }
- }
-
- if (Index == BufferSize - 1) {
- NameString[Index] = 0;
- }
-
- //
- // Module Name is got.
- //
- goto Done;
- }
- }
-
- if (ModuleGuidIsGet) {
- //
- // Method 2 Try to get the image's FFS UI section by image GUID
- //
- StringPtr = NULL;
- StringSize = 0;
- Status = GetSectionFromAnyFv (
- TempGuid,
- EFI_SECTION_USER_INTERFACE,
- 0,
- (VOID **)&StringPtr,
- &StringSize
- );
-
if (!EFI_ERROR (Status)) {
//
- // Method 3. Get the name string from FFS UI section
+ // Get Image protocol from ImageHandle
//
- for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
- NameString[Index] = (CHAR8)StringPtr[Index];
- }
-
- NameString[Index] = 0;
- FreePool (StringPtr);
- }
- }
-
-Done:
- //
- // Copy Module Guid
- //
- if (ModuleGuid != NULL) {
- CopyGuid (ModuleGuid, TempGuid);
- if (IsZeroGuid (TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
- // Handle is GUID
- CopyGuid (ModuleGuid, (EFI_GUID *)Handle);
- }
- }
-
- //
- // Cache the Handle and Guid pairs.
- //
- if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
- mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
- CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
- AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
- mCachePairCount++;
- }
-
- return Status;
-}
-
-/**
- Copies the string from Source into Destination and updates Length with the
- size of the string.
-
- @param Destination - destination of the string copy
- @param Source - pointer to the source string which will get copied
- @param Length - pointer to a length variable to be updated
-
-**/
-VOID
-CopyStringIntoPerfRecordAndUpdateLength (
- IN OUT CHAR8 *Destination,
- IN CONST CHAR8 *Source,
- IN OUT UINT8 *Length
- )
-{
- UINTN StringLen;
- UINTN DestMax;
-
- ASSERT (Source != NULL);
-
- if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- DestMax = STRING_SIZE;
- } else {
- DestMax = AsciiStrSize (Source);
- if (DestMax > STRING_SIZE) {
- DestMax = STRING_SIZE;
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
}
}
- StringLen = AsciiStrLen (Source);
- if (StringLen >= DestMax) {
- StringLen = DestMax -1;
- }
-
- AsciiStrnCpyS (Destination, DestMax, Source, StringLen);
- *Length += (UINT8)DestMax;
-
- return;
+ return LoadedImage;
}
/**
- Create performance record with event description and a timestamp.
-
- @param CallerIdentifier - Image handle or pointer to caller ID GUID.
- @param Guid - Pointer to a GUID.
- @param String - Pointer to a string describing the measurement.
- @param Ticker - 64-bit time stamp.
- @param Address - Pointer to a location in memory relevant to the measurement.
- @param PerfId - Performance identifier describing the type of measurement.
- @param Attribute - The attribute of the measurement. According to attribute can create a start
- record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
- or a general record for other Perf macros.
+ Get the module name from the PDB file name in the image header.
- @retval EFI_SUCCESS - Successfully created performance record.
- @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
- @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
- pointer or invalid PerfId.
+ @param[in] ModuleGuid The GUID of the module.
+ @param[out] NameString The buffer to store the name string.
+ @param[in] BufferSize The size of the buffer in bytes.
- @retval EFI_SUCCESS - Successfully created performance record
- @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records
- @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
- pointer or invalid PerfId
+ @retval EFI_SUCCESS The name string is successfully retrieved.
+ @retval EFI_NOT_FOUND The module name was not found.
**/
EFI_STATUS
-InsertFpdtRecord (
- IN CONST VOID *CallerIdentifier OPTIONAL,
- IN CONST VOID *Guid OPTIONAL,
- IN CONST CHAR8 *String OPTIONAL,
- IN UINT64 Ticker,
- IN UINT64 Address OPTIONAL,
- IN UINT16 PerfId,
- IN PERF_MEASUREMENT_ATTRIBUTE Attribute
+GetNameFromUiSection (
+ IN EFI_GUID *ModuleGuid,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize
)
-
{
- EFI_STATUS Status;
- EFI_GUID ModuleGuid;
- CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
- FPDT_RECORD_PTR FpdtRecordPtr;
- FPDT_RECORD_PTR CachedFpdtRecordPtr;
- UINT64 TimeStamp;
- CONST CHAR8 *StringPtr;
- UINTN DestMax;
- UINTN StringLen;
- UINT16 ProgressId;
-
- StringPtr = NULL;
- ZeroMem (ModuleName, sizeof (ModuleName));
-
- //
- // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
- // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
- //
- if (Attribute != PerfEntry) {
- //
- // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
- // !!! Note: If the Perf is not the known Token used in the core but have same
- // ID with the core Token, this case will not be supported.
- // And in currtnt usage mode, for the unkown ID, there is a general rule:
- // If it is start pref: the lower 4 bits of the ID should be 0.
- // If it is end pref: the lower 4 bits of the ID should not be 0.
- // If input ID doesn't follow the rule, we will adjust it.
- //
- if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
- return EFI_INVALID_PARAMETER;
- } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
- if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
- PerfId &= 0xFFF0;
- } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
- PerfId += 1;
- }
- }
-
- if (PerfId == 0) {
- //
- // Get ProgressID form the String Token.
- //
- Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- PerfId = ProgressId;
- }
- }
-
- //
- // 2. Get the buffer to store the FPDT record.
- //
- Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // 3. Get the TimeStamp.
- //
- if (Ticker == 0) {
- Ticker = GetPerformanceCounter ();
- TimeStamp = GetTimeInNanoSecond (Ticker);
- } else if (Ticker == 1) {
- TimeStamp = 0;
- } else {
- TimeStamp = GetTimeInNanoSecond (Ticker);
- }
-
- //
- // 4. Fill in the FPDT record according to different Performance Identifier.
- //
- switch (PerfId) {
- case MODULE_START_ID:
- case MODULE_END_ID:
- GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
- StringPtr = ModuleName;
- //
- // Cache the offset of start image start record and use to update the start image end record if needed.
- //
- if ((PerfId == MODULE_START_ID) && (Attribute == PerfEntry)) {
- mCachedLength = mSmmBootPerformanceTable->Header.Length;
- }
-
- if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
- FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);
- FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
- FpdtRecordPtr.GuidEvent->ProgressID = PerfId;
- FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
- CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
- if ((CallerIdentifier == NULL) && (PerfId == MODULE_END_ID) && (mCachedLength != 0)) {
- CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mCachedLength);
- CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
- mCachedLength = 0;
- }
- }
-
- break;
-
- case MODULE_LOADIMAGE_START_ID:
- case MODULE_LOADIMAGE_END_ID:
- GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
- StringPtr = ModuleName;
- if (PerfId == MODULE_LOADIMAGE_START_ID) {
- mLoadImageCount++;
- //
- // Cache the offset of load image start record and use to be updated by the load image end record if needed.
- //
- if ((CallerIdentifier == NULL) && (Attribute == PerfEntry)) {
- mCachedLength = mSmmBootPerformanceTable->Header.Length;
- }
- }
-
- if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
- FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
- FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
- FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
- FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
- FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;
- CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
- if ((PerfId == MODULE_LOADIMAGE_END_ID) && (mCachedLength != 0)) {
- CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mCachedLength);
- CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
- mCachedLength = 0;
- }
- }
-
- break;
-
- case PERF_EVENTSIGNAL_START_ID:
- case PERF_EVENTSIGNAL_END_ID:
- case PERF_CALLBACK_START_ID:
- case PERF_CALLBACK_END_ID:
- if ((String == NULL) || (Guid == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- StringPtr = String;
- if (AsciiStrLen (String) == 0) {
- StringPtr = "unknown name";
- }
-
- if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
- FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
- FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
- FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;
- FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;
- CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
- CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
- CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
- }
-
- break;
-
- case PERF_EVENT_ID:
- case PERF_FUNCTION_START_ID:
- case PERF_FUNCTION_END_ID:
- case PERF_INMODULE_START_ID:
- case PERF_INMODULE_END_ID:
- case PERF_CROSSMODULE_START_ID:
- case PERF_CROSSMODULE_END_ID:
- // MU_CHANGE [BEGIN] - CodeQL change
- Status = GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Failed to get Module Info from Handle! Status = %r\n", Status));
- }
-
- StringPtr = NULL;
-
- if (String != NULL) {
- StringPtr = String;
- } else if (ModuleName != NULL) {
- StringPtr = ModuleName;
- }
-
- if ((StringPtr == NULL) || (AsciiStrLen (StringPtr) == 0)) {
- StringPtr = "unknown name";
- }
-
- // MU_CHANGE [END] - CodeQL change
-
- if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
- FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
- FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
- FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
- FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
- CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
- CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
- }
-
- break;
-
- default:
- if (Attribute != PerfEntry) {
- // MU_CHANGE [BEGIN] - CodeQL change
- Status = GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Failed to get Module Info from Handle! Status = %r\n", Status));
- }
-
- StringPtr = NULL;
-
- if (String != NULL) {
- StringPtr = String;
- } else if (ModuleName != NULL) {
- StringPtr = ModuleName;
- }
-
- if ((StringPtr == NULL) || (AsciiStrLen (StringPtr) == 0)) {
- StringPtr = "unknown name";
- }
-
- // MU_CHANGE [END] - CodeQL change
-
- if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
- FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
- FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
- FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
- FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
- CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
- CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
- }
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- break;
- }
-
- //
- // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
- //
- if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
- if (StringPtr == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
- FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
- FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
- FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
- FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
- if (Guid != NULL) {
- //
- // Cache the event guid in string event record.
- //
- CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
- } else {
- CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
- }
-
- if (AsciiStrLen (StringPtr) == 0) {
- StringPtr = "unknown name";
- }
-
- CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
-
- if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
- FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
- }
-
- if (((PerfId == MODULE_LOADIMAGE_END_ID) || (PerfId == MODULE_END_ID)) && (mCachedLength != 0)) {
- CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)mSmmBootPerformanceTable + mCachedLength);
- if (PerfId == MODULE_LOADIMAGE_END_ID) {
- DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
- StringLen = AsciiStrLen (StringPtr);
- if (StringLen >= DestMax) {
- StringLen = DestMax -1;
- }
-
- CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
- AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);
- } else if (PerfId == MODULE_END_ID) {
- DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
- StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);
- if (StringLen >= DestMax) {
- StringLen = DestMax -1;
- }
-
- CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
- AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
- }
-
- mCachedLength = 0;
+ EFI_STATUS Status;
+ CHAR16 *StringPtr;
+ UINTN Index;
+ UINTN StringSize;
+
+ StringPtr = NULL;
+ StringSize = 0;
+ Status = GetSectionFromAnyFv (
+ ModuleGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **)&StringPtr,
+ &StringSize
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
+ NameString[Index] = (CHAR8)StringPtr[Index];
}
- }
-
- //
- // 5. Update the length of the used buffer after fill in the record.
- //
- mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
- mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
-
- return EFI_SUCCESS;
-}
-
-/**
- Communication service SMI Handler entry.
-
- This SMI handler provides services for report MM boot records.
- Caution: This function may receive untrusted input.
- Communicate buffer and buffer size are external input, so this function will do basic validation.
-
- @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
- @param[in] RegisterContext Points to an optional handler context which was specified when the
- handler was registered.
- @param[in, out] CommBuffer A pointer to a collection of data in memory that will
- be conveyed from a non-MM environment into an MM environment.
- @param[in, out] CommBufferSize The size of the CommBuffer.
-
- @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
- should still be called.
- @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
- still be called.
- @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
- be called.
- @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
-
-**/
-EFI_STATUS
-EFIAPI
-FpdtSmiHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *RegisterContext,
- IN OUT VOID *CommBuffer,
- IN OUT UINTN *CommBufferSize
- )
-{
- EFI_STATUS Status;
- SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
- UINTN BootRecordOffset;
- UINTN BootRecordSize;
- VOID *BootRecordData;
- UINTN TempCommBufferSize;
- UINT8 *BootRecordBuffer;
-
- //
- // If input is invalid, stop processing this SMI
- //
- if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
- return EFI_SUCCESS;
- }
-
- TempCommBufferSize = *CommBufferSize;
-
- if (TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {
- return EFI_SUCCESS;
+ NameString[Index] = 0;
+ FreePool (StringPtr);
}
- if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
- DEBUG ((DEBUG_ERROR, "FpdtSmiHandler: MM communication data buffer in MMRAM or overflow!\n"));
- return EFI_SUCCESS;
- }
-
- SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE *)CommBuffer;
-
- Status = EFI_SUCCESS;
-
- switch (SmmCommData->Function) {
- case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE:
- if (mSmmBootPerformanceTable != NULL) {
- mBootRecordSize = mSmmBootPerformanceTable->Header.Length - sizeof (SMM_BOOT_PERFORMANCE_TABLE);
- }
-
- SmmCommData->BootRecordSize = mBootRecordSize;
- break;
-
- case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA:
- Status = EFI_UNSUPPORTED;
- break;
-
- case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET:
- BootRecordOffset = SmmCommData->BootRecordOffset;
- BootRecordData = SmmCommData->BootRecordData;
- BootRecordSize = SmmCommData->BootRecordSize;
- if ((BootRecordData == NULL) || (BootRecordOffset >= mBootRecordSize)) {
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- //
- // Sanity check
- //
- if (BootRecordSize > mBootRecordSize - BootRecordOffset) {
- BootRecordSize = mBootRecordSize - BootRecordOffset;
- }
-
- SmmCommData->BootRecordSize = BootRecordSize;
- if (!SmmIsBufferOutsideSmmValid ((UINTN)BootRecordData, BootRecordSize)) {
- DEBUG ((DEBUG_ERROR, "FpdtSmiHandler: MM Data buffer in MMRAM or overflow!\n"));
- Status = EFI_ACCESS_DENIED;
- break;
- }
-
- BootRecordBuffer = ((UINT8 *)(mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);
- CopyMem (
- (UINT8 *)BootRecordData,
- BootRecordBuffer + BootRecordOffset,
- BootRecordSize
- );
- mFpdtDataIsReported = TRUE;
- break;
-
- default:
- Status = EFI_UNSUPPORTED;
- }
-
- SmmCommData->ReturnStatus = Status;
-
- return EFI_SUCCESS;
-}
-
-/**
- This is the Event call back function is triggered in SMM to notify the Library
- the system is entering runtime phase.
-
- @param[in] Protocol Points to the protocol's unique identifier
- @param[in] Interface Points to the interface instance
- @param[in] Handle The handle on which the interface was installed
-
- @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully
- **/
-EFI_STATUS
-EFIAPI
-SmmCorePerformanceLibExitBootServicesCallback (
- IN CONST EFI_GUID *Protocol,
- IN VOID *Interface,
- IN EFI_HANDLE Handle
- )
-{
- //
- // Disable performance measurement after ExitBootServices because
- // 1. Performance measurement might impact SMI latency at runtime;
- // 2. Performance log is copied to non SMRAM at ReadyToBoot so runtime performance
- // log is not useful.
- //
- mPerformanceMeasurementEnabled = FALSE;
-
- return EFI_SUCCESS;
+ return Status;
}
/**
- SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
- this function is callbacked to initialize the Smm Performance Lib
+ Initializes the MM Core Performance library after MM services are available.
- @param Event The event of notify protocol.
- @param Context Notify event context.
+ @param[in] Event The event of notify protocol.
+ @param[in] Context Notify event context.
**/
VOID
@@ -992,34 +192,10 @@ InitializeSmmCorePerformanceLib (
IN VOID *Context
)
{
- EFI_HANDLE Handle;
- EFI_HANDLE SmiHandle;
EFI_STATUS Status;
PERFORMANCE_PROPERTY *PerformanceProperty;
- VOID *Registration;
- //
- // Initialize spin lock
- //
- InitializeSpinLock (&mSmmFpdtLock);
-
- //
- // Install the protocol interfaces for SMM performance library instance.
- //
- Handle = NULL;
- Status = gSmst->SmmInstallProtocolInterface (
- &Handle,
- &gEdkiiSmmPerformanceMeasurementProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mPerformanceMeasurementInterface
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register SMI handler.
- //
- SmiHandle = NULL;
- Status = gSmst->SmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &SmiHandle);
+ Status = InitializeMmCorePerformanceLibCommon ();
ASSERT_EFI_ERROR (Status);
Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **)&PerformanceProperty);
@@ -1036,16 +212,6 @@ InitializeSmmCorePerformanceLib (
Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
ASSERT_EFI_ERROR (Status);
}
-
- //
- // Register callback function for ExitBootServices event.
- //
- Status = gSmst->SmmRegisterProtocolNotify (
- &gEdkiiSmmExitBootServicesProtocolGuid,
- SmmCorePerformanceLibExitBootServicesCallback,
- &Registration
- );
- ASSERT_EFI_ERROR (Status);
}
/**
@@ -1073,6 +239,7 @@ SmmCorePerformanceLibConstructor (
mPerformanceMeasurementEnabled = (BOOLEAN)((PcdGet8 (PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
if (!PerformanceMeasurementEnabled ()) {
+ DEBUG ((DEBUG_WARN, "[%a] - Performance library is linked but performance tracing is not enabled.\n", __func__));
//
// Do not initialize performance infrastructure if not required.
//
@@ -1104,401 +271,3 @@ SmmCorePerformanceLibConstructor (
return EFI_SUCCESS;
}
-
-/**
- Create performance record with event description and a timestamp.
-
- @param CallerIdentifier - Image handle or pointer to caller ID GUID.
- @param Guid - Pointer to a GUID.
- @param String - Pointer to a string describing the measurement.
- @param TimeStamp - 64-bit time stamp.
- @param Address - Pointer to a location in memory relevant to the measurement.
- @param Identifier - Performance identifier describing the type of measurement.
- @param Attribute - The attribute of the measurement. According to attribute can create a start
- record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
- or a general record for other Perf macros.
-
- @retval EFI_SUCCESS - Successfully created performance record.
- @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
- @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
- pointer or invalid PerfId.
-**/
-EFI_STATUS
-EFIAPI
-CreatePerformanceMeasurement (
- IN CONST VOID *CallerIdentifier OPTIONAL,
- IN CONST VOID *Guid OPTIONAL,
- IN CONST CHAR8 *String OPTIONAL,
- IN UINT64 TimeStamp OPTIONAL,
- IN UINT64 Address OPTIONAL,
- IN UINT32 Identifier,
- IN PERF_MEASUREMENT_ATTRIBUTE Attribute
- )
-{
- EFI_STATUS Status;
-
- Status = EFI_SUCCESS;
-
- AcquireSpinLock (&mSmmFpdtLock);
- Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);
- ReleaseSpinLock (&mSmmFpdtLock);
- return Status;
-}
-
-/**
- Adds a record at the end of the performance measurement log
- that records the start time of a performance measurement.
-
- Adds a record to the end of the performance measurement log
- that contains the Handle, Token, Module and Identifier.
- The end time of the new record must be set to zero.
- If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
- If TimeStamp is zero, the start time in the record is filled in with the value
- read from the current time stamp.
-
- @param Handle Pointer to environment specific context used
- to identify the component being measured.
- @param Token Pointer to a Null-terminated ASCII string
- that identifies the component being measured.
- @param Module Pointer to a Null-terminated ASCII string
- that identifies the module being measured.
- @param TimeStamp 64-bit time stamp.
- @param Identifier 32-bit identifier. If the value is 0, the created record
- is same as the one created by StartPerformanceMeasurement.
-
- @retval RETURN_SUCCESS The start of the measurement was recorded.
- @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
-
-**/
-RETURN_STATUS
-EFIAPI
-StartPerformanceMeasurementEx (
- IN CONST VOID *Handle OPTIONAL,
- IN CONST CHAR8 *Token OPTIONAL,
- IN CONST CHAR8 *Module OPTIONAL,
- IN UINT64 TimeStamp,
- IN UINT32 Identifier
- )
-{
- CONST CHAR8 *String;
-
- if (Token != NULL) {
- String = Token;
- } else if (Module != NULL) {
- String = Module;
- } else {
- String = NULL;
- }
-
- return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
-}
-
-/**
- Searches the performance measurement log from the beginning of the log
- for the first matching record that contains a zero end time and fills in a valid end time.
-
- Searches the performance measurement log from the beginning of the log
- for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
- If the record can not be found then return RETURN_NOT_FOUND.
- If the record is found and TimeStamp is not zero,
- then the end time in the record is filled in with the value specified by TimeStamp.
- If the record is found and TimeStamp is zero, then the end time in the matching record
- is filled in with the current time stamp value.
-
- @param Handle Pointer to environment specific context used
- to identify the component being measured.
- @param Token Pointer to a Null-terminated ASCII string
- that identifies the component being measured.
- @param Module Pointer to a Null-terminated ASCII string
- that identifies the module being measured.
- @param TimeStamp 64-bit time stamp.
- @param Identifier 32-bit identifier. If the value is 0, the found record
- is same as the one found by EndPerformanceMeasurement.
-
- @retval RETURN_SUCCESS The end of the measurement was recorded.
- @retval RETURN_NOT_FOUND The specified measurement record could not be found.
-
-**/
-RETURN_STATUS
-EFIAPI
-EndPerformanceMeasurementEx (
- IN CONST VOID *Handle OPTIONAL,
- IN CONST CHAR8 *Token OPTIONAL,
- IN CONST CHAR8 *Module OPTIONAL,
- IN UINT64 TimeStamp,
- IN UINT32 Identifier
- )
-{
- CONST CHAR8 *String;
-
- if (Token != NULL) {
- String = Token;
- } else if (Module != NULL) {
- String = Module;
- } else {
- String = NULL;
- }
-
- return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
-}
-
-/**
- Attempts to retrieve a performance measurement log entry from the performance measurement log.
- It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
- and then assign the Identifier with 0.
-
- !!! Not Support!!!
-
- Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
- zero on entry, then an attempt is made to retrieve the first entry from the performance log,
- and the key for the second entry in the log is returned. If the performance log is empty,
- then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
- log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
- returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
- retrieved and an implementation specific non-zero key value that specifies the end of the performance
- log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
- is retrieved and zero is returned. In the cases where a performance log entry can be returned,
- the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
- If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
- If Handle is NULL, then ASSERT().
- If Token is NULL, then ASSERT().
- If Module is NULL, then ASSERT().
- If StartTimeStamp is NULL, then ASSERT().
- If EndTimeStamp is NULL, then ASSERT().
- If Identifier is NULL, then ASSERT().
-
- @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
- 0, then the first performance measurement log entry is retrieved.
- On exit, the key of the next performance log entry.
- @param Handle Pointer to environment specific context used to identify the component
- being measured.
- @param Token Pointer to a Null-terminated ASCII string that identifies the component
- being measured.
- @param Module Pointer to a Null-terminated ASCII string that identifies the module
- being measured.
- @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
- was started.
- @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
- was ended.
- @param Identifier Pointer to the 32-bit identifier that was recorded.
-
- @return The key for the next performance log entry (in general case).
-
-**/
-UINTN
-EFIAPI
-GetPerformanceMeasurementEx (
- IN UINTN LogEntryKey,
- OUT CONST VOID **Handle,
- OUT CONST CHAR8 **Token,
- OUT CONST CHAR8 **Module,
- OUT UINT64 *StartTimeStamp,
- OUT UINT64 *EndTimeStamp,
- OUT UINT32 *Identifier
- )
-{
- return 0;
-}
-
-/**
- Adds a record at the end of the performance measurement log
- that records the start time of a performance measurement.
-
- Adds a record to the end of the performance measurement log
- that contains the Handle, Token, and Module.
- The end time of the new record must be set to zero.
- If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
- If TimeStamp is zero, the start time in the record is filled in with the value
- read from the current time stamp.
-
- @param Handle Pointer to environment specific context used
- to identify the component being measured.
- @param Token Pointer to a Null-terminated ASCII string
- that identifies the component being measured.
- @param Module Pointer to a Null-terminated ASCII string
- that identifies the module being measured.
- @param TimeStamp 64-bit time stamp.
-
- @retval RETURN_SUCCESS The start of the measurement was recorded.
- @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
-
-**/
-RETURN_STATUS
-EFIAPI
-StartPerformanceMeasurement (
- IN CONST VOID *Handle OPTIONAL,
- IN CONST CHAR8 *Token OPTIONAL,
- IN CONST CHAR8 *Module OPTIONAL,
- IN UINT64 TimeStamp
- )
-{
- return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
-}
-
-/**
- Searches the performance measurement log from the beginning of the log
- for the first matching record that contains a zero end time and fills in a valid end time.
-
- Searches the performance measurement log from the beginning of the log
- for the first record that matches Handle, Token, and Module and has an end time value of zero.
- If the record can not be found then return RETURN_NOT_FOUND.
- If the record is found and TimeStamp is not zero,
- then the end time in the record is filled in with the value specified by TimeStamp.
- If the record is found and TimeStamp is zero, then the end time in the matching record
- is filled in with the current time stamp value.
-
- @param Handle Pointer to environment specific context used
- to identify the component being measured.
- @param Token Pointer to a Null-terminated ASCII string
- that identifies the component being measured.
- @param Module Pointer to a Null-terminated ASCII string
- that identifies the module being measured.
- @param TimeStamp 64-bit time stamp.
-
- @retval RETURN_SUCCESS The end of the measurement was recorded.
- @retval RETURN_NOT_FOUND The specified measurement record could not be found.
-
-**/
-RETURN_STATUS
-EFIAPI
-EndPerformanceMeasurement (
- IN CONST VOID *Handle OPTIONAL,
- IN CONST CHAR8 *Token OPTIONAL,
- IN CONST CHAR8 *Module OPTIONAL,
- IN UINT64 TimeStamp
- )
-{
- return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
-}
-
-/**
- Attempts to retrieve a performance measurement log entry from the performance measurement log.
- It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
- and then eliminate the Identifier.
-
- !!! Not Support!!!
-
- Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
- zero on entry, then an attempt is made to retrieve the first entry from the performance log,
- and the key for the second entry in the log is returned. If the performance log is empty,
- then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
- log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
- returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
- retrieved and an implementation specific non-zero key value that specifies the end of the performance
- log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
- is retrieved and zero is returned. In the cases where a performance log entry can be returned,
- the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
- If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
- If Handle is NULL, then ASSERT().
- If Token is NULL, then ASSERT().
- If Module is NULL, then ASSERT().
- If StartTimeStamp is NULL, then ASSERT().
- If EndTimeStamp is NULL, then ASSERT().
-
- @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
- 0, then the first performance measurement log entry is retrieved.
- On exit, the key of the next performance log entry.
- @param Handle Pointer to environment specific context used to identify the component
- being measured.
- @param Token Pointer to a Null-terminated ASCII string that identifies the component
- being measured.
- @param Module Pointer to a Null-terminated ASCII string that identifies the module
- being measured.
- @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
- was started.
- @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
- was ended.
-
- @return The key for the next performance log entry (in general case).
-
-**/
-UINTN
-EFIAPI
-GetPerformanceMeasurement (
- IN UINTN LogEntryKey,
- OUT CONST VOID **Handle,
- OUT CONST CHAR8 **Token,
- OUT CONST CHAR8 **Module,
- OUT UINT64 *StartTimeStamp,
- OUT UINT64 *EndTimeStamp
- )
-{
- return 0;
-}
-
-/**
- Returns TRUE if the performance measurement macros are enabled.
-
- This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
- PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
-
- @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
- PcdPerformanceLibraryPropertyMask is set.
- @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
- PcdPerformanceLibraryPropertyMask is clear.
-
-**/
-BOOLEAN
-EFIAPI
-PerformanceMeasurementEnabled (
- VOID
- )
-{
- return mPerformanceMeasurementEnabled;
-}
-
-/**
- Create performance record with event description and a timestamp.
-
- @param CallerIdentifier - Image handle or pointer to caller ID GUID
- @param Guid - Pointer to a GUID
- @param String - Pointer to a string describing the measurement
- @param Address - Pointer to a location in memory relevant to the measurement
- @param Identifier - Performance identifier describing the type of measurement
-
- @retval RETURN_SUCCESS - Successfully created performance record
- @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
- @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
- pointer or invalid PerfId
-
-**/
-RETURN_STATUS
-EFIAPI
-LogPerformanceMeasurement (
- IN CONST VOID *CallerIdentifier,
- IN CONST VOID *Guid OPTIONAL,
- IN CONST CHAR8 *String OPTIONAL,
- IN UINT64 Address OPTIONAL,
- IN UINT32 Identifier
- )
-{
- return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
-}
-
-/**
- Check whether the specified performance measurement can be logged.
-
- This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
- and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
-
- @param Type - Type of the performance measurement entry.
-
- @retval TRUE The performance measurement can be logged.
- @retval FALSE The performance measurement can NOT be logged.
-
-**/
-BOOLEAN
-EFIAPI
-LogPerformanceMeasurementEnabled (
- IN CONST UINTN Type
- )
-{
- //
- // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
- //
- if (PerformanceMeasurementEnabled () && ((PcdGet8 (PcdPerformanceLibraryPropertyMask) & Type) == 0)) {
- return TRUE;
- }
-
- return FALSE;
-}
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
index 9a7e14e80c..bcd2f420b3 100644
--- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
@@ -9,20 +9,20 @@
# SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
#
# Copyright (c) 2011 - 2023, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation. MU_CHANGE - Standalone MM Perf Support
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
- INF_VERSION = 0x00010005
+ INF_VERSION = 0x0001001B # MU_CHANGE - Standalone MM Perf Support
BASE_NAME = SmmCorePerformanceLib
MODULE_UNI_FILE = SmmCorePerformanceLib.uni
FILE_GUID = 36290D10-0F47-42c1-BBCE-E191C7928DCF
MODULE_TYPE = SMM_CORE
VERSION_STRING = 1.0
- PI_SPECIFICATION_VERSION = 0x0001000A
+ PI_SPECIFICATION_VERSION = 0x00010032 # MU_CHANGE - Standalone MM Perf Support
LIBRARY_CLASS = PerformanceLib|SMM_CORE
-
CONSTRUCTOR = SmmCorePerformanceLibConstructor
#
@@ -32,33 +32,35 @@
#
[Sources]
- SmmCorePerformanceLib.c
+ MmCorePerformanceLib.c # MU_CHANGE - Standalone MM Perf Support
SmmCorePerformanceLibInternal.h
+ SmmCorePerformanceLib.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
-
+# MU_CHANGE [BEGIN] - Standalone MM Perf Support
[LibraryClasses]
- MemoryAllocationLib
- UefiBootServicesTableLib
- PcdLib
- TimerLib
- BaseMemoryLib
BaseLib
+ BaseMemoryLib
DebugLib
- SynchronizationLib
- SmmServicesTableLib
+ DxeServicesLib
+ MemoryAllocationLib
+ MmServicesTableLib
+ PcdLib
+ PeCoffGetEntryPointLib
SmmMemLib
+ SynchronizationLib
+ TimerLib
+ UefiBootServicesTableLib
UefiLib
- ReportStatusCodeLib
- PeCoffGetEntryPointLib
- DxeServicesLib
+# MU_CHANGE [END] - Standalone MM Perf Support
[Protocols]
gEfiSmmBase2ProtocolGuid ## CONSUMES
- gEdkiiSmmExitBootServicesProtocolGuid ## CONSUMES
+ gEdkiiSmmExitBootServicesProtocolGuid ## CONSUMES ## NOTIFY # MU_CHANGE - Standalone MM Perf Support
+ gEfiLoadedImageProtocolGuid ## CONSUMES # MU_CHANGE - Standalone MM Perf Support
[Guids]
## PRODUCES ## SystemTable
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
index 62b496484c..a1ed40010f 100644
--- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
@@ -5,6 +5,7 @@
library instance at its constructor.
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation. MU_CHANGE - Standalone MM Perf Support
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -12,32 +13,135 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#ifndef _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
#define _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
-#include
-#include
+// MU_CHANGE [BEGIN] - Standalone MM Perf Support
+#include
#include
#include
+#include
+#include
#include
-#include
-#include
-#include
-#include
#include
#include
-#include
-#include
-#include
-#include
+#include
#include
-#include
-#include
-#include
-#include
+#include
+#include
#include
+#include
+#include
+#include
+#include
-#include
-#include
#include
+#include
+
+#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
+#define FIRMWARE_RECORD_BUFFER 0x1000
+#define CACHE_HANDLE_GUID_COUNT 0x100
+
+//
+// Library internal function declarations
+//
+
+/**
+ Return a pointer to the loaded image protocol for the given handle.
+
+ @param[in] Handle A handle to query for the loaded image protocol.
+
+ @return A pointer to a loaded image protocol instance or null if the handle does not support load image protocol.
+**/
+EFI_LOADED_IMAGE_PROTOCOL *
+GetLoadedImageProtocol (
+ IN EFI_HANDLE Handle
+ );
+
+/**
+ Get the module name from the PDB file name in the image header.
+
+ @param[in] ImageBase The base address of the image.
+ @param[out] NameString The buffer to store the name string.
+ @param[in] BufferSize The size of the buffer in bytes.
+
+ @retval EFI_SUCCESS The name string is successfully retrieved.
+ @retval EFI_INVALID_PARAMETER A pointer argument provided is null.
+ @retval EFI_NOT_FOUND The module name was not found.
+
+**/
+EFI_STATUS
+GetModuleNameFromPdbString (
+ IN VOID *ImageBase,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize
+ );
+
+/**
+ Get the module name from the PDB file name in the image header.
+
+ @param[in] ModuleGuid The GUID of the module.
+ @param[out] NameString The buffer to store the name string.
+ @param[in] BufferSize The size of the buffer in bytes.
+
+ @retval EFI_SUCCESS The name string is successfully retrieved.
+ @retval EFI_NOT_FOUND The module name was not found.
+
+**/
+EFI_STATUS
+GetNameFromUiSection (
+ IN EFI_GUID *ModuleGuid,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize
+ );
+
+/**
+ Common initialization code for the MM Core Performance Library.
+
+ @retval EFI_SUCCESS The MM Core Performance Library was initialized successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to initialize the MM Core Performance Library.
+ @retval Others The MM Core Performance Library was not initialized successfully.
+ **/
+EFI_STATUS
+InitializeMmCorePerformanceLibCommon (
+ VOID
+ );
+
+/**
+ A library internal MM-instance specific implementation to check if a buffer outside MM is valid.
+
+ This function is provided so Standalone MM and Traditional MM may use a different implementation
+ of data buffer check logic.
+
+ @param[in] Buffer The buffer start address to be checked.
+ @param[in] Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture.
+ @retval FALSE This buffer is not valid per processor architecture.
+**/
+BOOLEAN
+IsBufferOutsideMmValidInternal (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ );
+
+/**
+ A library internal MM-instance specific implementation to check if a comm buffer is valid.
+
+ This function is provided so Standalone MM and Traditional MM may use a different implementation
+ of comm buffer check logic.
+
+ @param[in] Buffer The buffer start address to be checked.
+ @param[in] Length The buffer length to be checked.
+
+ @retval TRUE This communicate buffer is valid per processor architecture.
+ @retval FALSE This communicate buffer is not valid per processor architecture.
+**/
+BOOLEAN
+IsCommBufferValidInternal (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ );
+
+// MU_CHANGE [END] - Standalone MM Perf Support
//
// Interface declarations for SMM PerformanceMeasurement Protocol.
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.c b/MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.c
new file mode 100644
index 0000000000..c492602e95
--- /dev/null
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.c
@@ -0,0 +1,150 @@
+/** @file
+ This library is mainly used by the Standalone MM Core to start performance logging to ensure that
+ Standalone MM Performance and PerformanceEx Protocol are installed as early as possible in the MM phase.
+
+ Caution: This module requires additional review when modified.
+ - This driver will have external input - performance data and communicate buffer in MM mode.
+ - This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
+
+ Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ MU_CHANGE [WHOLE FILE] - Standalone MM Perf Support
+
+**/
+
+#include "SmmCorePerformanceLibInternal.h"
+
+#include
+
+extern BOOLEAN mPerformanceMeasurementEnabled;
+
+/**
+ A library internal MM-instance specific implementation to check if a buffer outside MM is valid.
+
+ This function is provided so Standalone MM and Traditional MM may use a different implementation
+ of data buffer check logic.
+
+ @param[in] Buffer The buffer start address to be checked.
+ @param[in] Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture.
+ @retval FALSE This buffer is not valid per processor architecture.
+**/
+BOOLEAN
+IsBufferOutsideMmValidInternal (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ return MmIsBufferOutsideMmValid (Buffer, Length);
+}
+
+/**
+ A library internal MM-instance specific implementation to check if a comm buffer is valid.
+
+ This function is provided so Standalone MM and Traditional MM may use a different implementation
+ of comm buffer check logic.
+
+ @param[in] Buffer The buffer start address to be checked.
+ @param[in] Length The buffer length to be checked.
+
+ @retval TRUE This communicate buffer is valid per processor architecture.
+ @retval FALSE This communicate buffer is not valid per processor architecture.
+**/
+BOOLEAN
+IsCommBufferValidInternal (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ return MmCommBufferValid (Buffer, Length);
+}
+
+/**
+ Return a pointer to the loaded image protocol for the given handle.
+
+ @param[in] Handle A handle to query for the loaded image protocol.
+
+ @return A pointer to a loaded image protocol instance or null if the handle does not support load image protocol.
+**/
+EFI_LOADED_IMAGE_PROTOCOL *
+GetLoadedImageProtocol (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ LoadedImage = NULL;
+ gMmst->MmHandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ return LoadedImage;
+}
+
+/**
+ Get the module name from the PDB file name in the image header.
+
+ @param[in] ModuleGuid The GUID of the module.
+ @param[out] NameString The buffer to store the name string.
+ @param[in] BufferSize The size of the buffer in bytes.
+
+ @retval EFI_SUCCESS The name string is successfully retrieved.
+ @retval EFI_NOT_FOUND The module name was not found.
+
+**/
+EFI_STATUS
+GetNameFromUiSection (
+ IN EFI_GUID *ModuleGuid,
+ OUT CHAR8 *NameString,
+ IN UINTN BufferSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ The constructor function initializes the Standalone MM Core performance library.
+
+ It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
+
+ @param[in] ImageHandle The firmware allocated handle for the image.
+ @param[in] MmSystemTable A pointer to the MM System Table.
+
+ @retval EFI_SUCCESS The constructor successfully gets HobList.
+ @retval Other value The constructor can't get HobList.
+
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmCorePerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mPerformanceMeasurementEnabled = (BOOLEAN)((FixedPcdGet8 (PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+
+ if (!PerformanceMeasurementEnabled ()) {
+ DEBUG ((DEBUG_WARN, "[%a] - Performance library is linked but performance tracing is not enabled.\n", __func__));
+ //
+ // Do not initialize performance infrastructure if not required.
+ //
+ return EFI_SUCCESS;
+ }
+
+ Status = InitializeMmCorePerformanceLibCommon ();
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.inf b/MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.inf
new file mode 100644
index 0000000000..5482ead294
--- /dev/null
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.inf
@@ -0,0 +1,55 @@
+## @file
+# Performance library instance used by a Standalone MM Core or very early Standlaone MM module.
+#
+# Installs the MM performance measurement protocol and returns MM performance data via MM communicate.
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# MU_CHANGE [WHOLE FILE] - Standalone MM Perf Support
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = StandaloneMmCorePerformanceLib
+ FILE_GUID = 8585D462-DE63-4080-882A-A73974CE5609
+ MODULE_TYPE = MM_CORE_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = PerformanceLib|MM_CORE_STANDALONE MM_STANDALONE
+ CONSTRUCTOR = StandaloneMmCorePerformanceLibConstructor
+
+[Sources]
+ MmCorePerformanceLib.c
+ SmmCorePerformanceLibInternal.h
+ StandaloneMmCorePerformanceLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ MemLib
+ MmServicesTableLib
+ PcdLib
+ PeCoffGetEntryPointLib
+ SynchronizationLib
+ TimerLib
+
+[Protocols]
+ gEdkiiSmmExitBootServicesProtocolGuid ## CONSUMES ## NOTIFY
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiFirmwarePerformanceGuid ## SOMETIMES_PRODUCES # SmiHandlerRegister
+ gEdkiiSmmPerformanceMeasurementProtocolGuid ## PRODUCES # Install protocol
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly ## CONSUMES
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index b300f61023..30790c0021 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -574,6 +574,7 @@
MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf
MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
+ MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.inf # MU_CHANGE - Standalone MM Perf Support
MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf