Update the performance library instances in MdeModulePkg to implement the APIs used for new added Perf macros.
Cc: Liming Gao <liming....@intel.com> Cc: Star Zeng <star.z...@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Dandan Bi <dandan...@intel.com> --- .../DxeCorePerformanceLib/DxeCorePerformanceLib.c | 664 +++++++++++++++++++-- .../DxeCorePerformanceLib.inf | 1 + .../DxeCorePerformanceLibInternal.h | 1 + .../Library/DxePerformanceLib/DxePerformanceLib.c | 68 +++ .../Library/PeiPerformanceLib/PeiPerformanceLib.c | 442 ++++++++++++-- .../SmmCorePerformanceLib/SmmCorePerformanceLib.c | 440 ++++++++++++-- .../Library/SmmPerformanceLib/SmmPerformanceLib.c | 68 +++ 7 files changed, 1550 insertions(+), 134 deletions(-) diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c index 79820605184..68724ce9e1c 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c @@ -69,17 +69,19 @@ UINTN mCachePairCount = 0; UINT32 mLoadImageCount = 0; UINT32 mPerformanceLength = 0; UINT32 mMaxPerformanceLength = 0; UINT32 mBootRecordSize = 0; UINT32 mBootRecordMaxSize = 0; +UINT32 mCachedLength = 0; BOOLEAN mFpdtBufferIsReported = FALSE; BOOLEAN mLackSpaceIsReported = FALSE; CHAR8 *mPlatformLanguage = NULL; UINT8 *mPerformancePointer = NULL; UINT8 *mBootRecordBuffer = NULL; BOOLEAN mLockInsertRecord = FALSE; +CHAR8 *mDevicePathString = NULL; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevicePathToText = NULL; // // Interfaces for PerformanceMeasurement Protocol. @@ -88,10 +90,64 @@ EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = { CreatePerformanceMeasurement, }; PERFORMANCE_PROPERTY mPerformanceProperty; +/** + 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 (mFpdtBufferIsReported) { + // + // Append Boot records to the boot performance table. + // + if (mBootRecordSize + RecordSize > mBootRecordMaxSize) { + if (!mLackSpaceIsReported) { + DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n")); + mLackSpaceIsReported = TRUE; + } + return EFI_OUT_OF_RESOURCES; + } else { + // + // Save boot record into BootPerformance table + // + FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mBootRecordSize); + } + } else { + // + // Check if pre-allocated buffer is full + // + if (mPerformanceLength + RecordSize > mMaxPerformanceLength) { + mPerformancePointer = ReallocatePool ( + mPerformanceLength, + mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER, + mPerformancePointer + ); + if (mPerformancePointer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER; + } + // + // Covert buffer to FPDT Ptr Union type. + // + FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength); + } + 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 @@ -814,49 +870,13 @@ InsertFpdtMeasurement ( Identifier += 1; } RecordInfo.ProgressID = (UINT16)Identifier; } - if (mFpdtBufferIsReported) { - // - // Append Boot records to the boot performance table. - // - if (mBootRecordSize + RecordInfo.RecordSize > mBootRecordMaxSize) { - if (!mLackSpaceIsReported) { - DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n")); - mLackSpaceIsReported = TRUE; - } - return EFI_OUT_OF_RESOURCES; - } else { - // - // Save boot record into BootPerformance table - // - FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mBootRecordSize); - mBootRecordSize += RecordInfo.RecordSize; - mAcpiBootPerformanceTable->Header.Length += RecordInfo.RecordSize; - } - } else { - // - // Check if pre-allocated buffer is full - // - if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) { - mPerformancePointer = ReallocatePool ( - mPerformanceLength, - mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER, - mPerformancePointer - ); - - if (mPerformancePointer == NULL) { - return EFI_OUT_OF_RESOURCES; - } - mMaxPerformanceLength = mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER; - } - // - // Covert buffer to FPDT Ptr Union type. - // - FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength); - mPerformanceLength += RecordInfo.RecordSize; + Status = GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; } // // Get the TimeStamp. // @@ -942,11 +962,16 @@ InsertFpdtMeasurement ( // // Record is not supported in current DXE phase, return EFI_ABORTED // return EFI_UNSUPPORTED; } - + if (mFpdtBufferIsReported) { + mBootRecordSize += FpdtRecordPtr.RecordHeader->Length; + mAcpiBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length; + } else { + mPerformanceLength += FpdtRecordPtr.RecordHeader->Length; + } return EFI_SUCCESS; } /** Dumps all the PEI performance. @@ -1038,10 +1063,512 @@ ReportFpdtRecordBuffer ( // mFpdtBufferIsReported = TRUE; } } +/** + Get a string description for device for the given controller handle. + If ComponentName2 GetControllerName is supported, the value is + included in the string,followed by device path, otherwise just device path. + + @param Handle - Image handle + @param ControllerHandle - Controller handle. + @param Length - Pointer to record length to be updated + + @retval EFI_SUCCESS - Successfully got string description for device + @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor DevicePath were found. + +**/ +EFI_STATUS +GetDeviceInfoFromHandleAndUpdateLength ( + IN CONST VOID *Handle, + IN EFI_HANDLE ControllerHandle, + IN OUT UINT8 *Length + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol; + EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; + EFI_STATUS Status; + CHAR16 *StringPtr; + CHAR8 *AsciiStringPtr; + UINTN ControllerNameStringSize; + UINTN DevicePathStringSize; + + ControllerNameStringSize = 0; + + Status = gBS->HandleProtocol ( + (EFI_HANDLE) Handle, + &gEfiComponentName2ProtocolGuid, + (VOID **) &ComponentName2 + ); + + if (!EFI_ERROR(Status)) { + // + // Get the current platform language setting + // + if (mPlatformLanguage == NULL) { + GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&mPlatformLanguage, NULL); + } + + Status = ComponentName2->GetControllerName ( + ComponentName2, + ControllerHandle, + NULL, + mPlatformLanguage != NULL ? mPlatformLanguage:"en-US", + &StringPtr + ); + } + + if (!EFI_ERROR (Status)) { + // + // This will produce the size of the unicode string, which is twice as large as the ASCII one + // This must be an even number, so ok to divide by 2 + // + ControllerNameStringSize = StrSize(StringPtr) / 2; + + // + // The + 1 is because we want to add a space between the ControllerName and the device path + // + if ((ControllerNameStringSize + (*Length) + 1) > FPDT_MAX_PERF_RECORD_SIZE) { + // + // Only copy enough to fill MAX_PERF_RECORD_SIZE worth of the record + // + ControllerNameStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length) - 1; + } + + mDevicePathString = AllocateZeroPool (ControllerNameStringSize + 1); + if (mDevicePathString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UnicodeStrToAsciiStrS(StringPtr, mDevicePathString, ControllerNameStringSize); + + // + // Add a space in the end of the ControllerName + // + AsciiStringPtr = mDevicePathString + ControllerNameStringSize - 1; + *AsciiStringPtr = 0x20; + AsciiStringPtr++; + *AsciiStringPtr = 0; + ControllerNameStringSize++; + + *Length += (UINT8)ControllerNameStringSize; + } + + // + // This function returns the device path protocol from the handle specified by Handle. If Handle is + // NULL or Handle does not contain a device path protocol, then NULL is returned. + // + DevicePathProtocol = DevicePathFromHandle(ControllerHandle); + + if (DevicePathProtocol != NULL) { + StringPtr = ConvertDevicePathToText (DevicePathProtocol, TRUE, FALSE); + if (StringPtr != NULL) { + // + // This will produce the size of the unicode string, which is twice as large as the ASCII one + // This must be an even number, so ok to divide by 2 + // + DevicePathStringSize = StrSize(StringPtr) / 2; + + if ((DevicePathStringSize + (*Length)) > FPDT_MAX_PERF_RECORD_SIZE) { + // + // Only copy enough to fill MAX_PERF_RECORD_SIZE worth of the record + // + DevicePathStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length); + } + if (ControllerNameStringSize != 0) { + mDevicePathString = ReallocatePool( + ControllerNameStringSize + 1, + ControllerNameStringSize + DevicePathStringSize + 1, + mDevicePathString + ); + } else { + mDevicePathString = AllocateZeroPool(DevicePathStringSize + 1); + } + if (mDevicePathString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + if (ControllerNameStringSize != 0) { + AsciiStringPtr = mDevicePathString + ControllerNameStringSize - 1; + } else { + AsciiStringPtr = mDevicePathString; + } + + UnicodeStrToAsciiStrS(StringPtr, AsciiStringPtr, DevicePathStringSize); + *Length += (UINT8)DevicePathStringSize; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; +} + +/** + Get the FPDT record size. + + @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 Address Pointer to a location in memory relevant to the measurement. + For DriverBinding Perf, it's the Controller handle. + For other Perf, it's NULL. + @param PerfId Performance identifier. + @param RecordSize On return, pointer to the size of record. + + @retval EFI_SUCCESS Get record size successfully. + @retval EFI_INVALID_PARAMETER Invalid Performance identifier. + +**/ +EFI_STATUS +GetFpdtRecordSize ( + IN CONST VOID *Handle, + IN CONST CHAR8 *String, + IN UINT64 Address, + IN UINT16 PerfId, + OUT UINT8 *RecordSize + ) +{ + UINTN StringSize; + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + if (PerfId == MODULE_DB_SUPPORT_START_ID || PerfId == MODULE_DB_SUPPORT_END_ID) { + return EFI_UNSUPPORTED; + } + *RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE); + } else { + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + *RecordSize = sizeof (FPDT_GUID_EVENT_RECORD); + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case MODULE_DB_START_ID: + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case MODULE_DB_END_ID: + *RecordSize = sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD); + GetDeviceInfoFromHandleAndUpdateLength(Handle, (EFI_HANDLE)(UINTN)Address, RecordSize); + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize = AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize = STRING_SIZE; + } + *RecordSize = (UINT8)(sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + StringSize); + 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: + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize = AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize = STRING_SIZE; + } + *RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + + 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 Address - Pointer to a location in memory relevant to the measurement + @param PerfId - Performance identifier describing the type of measurement + + @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 Address, OPTIONAL + IN UINT16 PerfId + ) +{ + EFI_GUID ModuleGuid; + CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH]; + FPDT_RECORD_PTR FpdtRecordPtr; + FPDT_RECORD_PTR CachedFpdtRecordPtr; + UINT64 TimeStamp; + UINT64 TimeStampCounter; + CONST CHAR8 *StringPtr; + UINT8 RecordSize; + UINTN DestMax; + UINTN StringLen; + EFI_STATUS Status; + + StringPtr = NULL; + RecordSize = 0; + ZeroMem (ModuleName, sizeof (ModuleName)); + + Status = GetFpdtRecordSize(CallerIdentifier, String, Address, PerfId, &RecordSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the TimeStamp. + // + TimeStampCounter = GetPerformanceCounter (); + TimeStamp = GetTimeInNanoSecond (TimeStampCounter); + + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + // + // Get the ModuleGuid and ModuleName from the handle. + // + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + StringPtr = ModuleName; + if (PerfId == MODULE_START_ID) { + if (mFpdtBufferIsReported) { + mCachedLength = mBootRecordSize; + } else { + mCachedLength = mPerformanceLength; + } + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE; + FpdtRecordPtr.GuidEvent->Header.Length = RecordSize; + 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 (PerfId == MODULE_END_ID && mCachedLength != 0) { + if (mFpdtBufferIsReported) { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength); + } else { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength); + } + CopyMem (&CachedFpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.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 ++; + if (mFpdtBufferIsReported) { + mCachedLength = mBootRecordSize; + } else { + mCachedLength = mPerformanceLength; + } + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordSize; + 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) { + if (mFpdtBufferIsReported) { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength); + } else { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength); + } + CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid)); + mCachedLength = 0; + } + } + break; + + case MODULE_DB_START_ID: + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + if (Address == 0) { + return EFI_INVALID_PARAMETER; + } + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + StringPtr = ModuleName; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordSize; + FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId; + FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp; + FpdtRecordPtr.GuidQwordEvent->Qword = Address; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid)); + } + break; + + case MODULE_DB_END_ID: + if (Address == 0) { + return EFI_INVALID_PARAMETER; + } + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + StringPtr = ModuleName; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordStringEvent->Header.Type = FPDT_GUID_QWORD_STRING_EVENT_TYPE; + FpdtRecordPtr.GuidQwordStringEvent->Header.Length = RecordSize; + FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.GuidQwordStringEvent->ProgressID = PerfId; + FpdtRecordPtr.GuidQwordStringEvent->Timestamp = TimeStamp; + FpdtRecordPtr.GuidQwordStringEvent->Qword = Address; + CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordStringEvent->Guid)); + DestMax = (RecordSize - sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD)) / sizeof (CHAR8); + if (mDevicePathString != NULL) { + AsciiStrCpyS (FpdtRecordPtr.GuidQwordStringEvent->String, DestMax, mDevicePathString); + FreePool (mDevicePathString); + mDevicePathString = NULL; + } + } + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (CallerIdentifier == NULL || Guid ==NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Cache the event guid in string event record when PcdEdkiiFpdtStringRecordEnableOnly == TRUE + // + CopyGuid (&ModuleGuid, Guid); + StringPtr = String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length = RecordSize; + 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)); + DestMax = (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, StringPtr, StringLen); + } + 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: + if (CallerIdentifier == NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + CopyGuid (&ModuleGuid, (EFI_GUID *) CallerIdentifier); + StringPtr = String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; + DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); + if (StringPtr != NULL && AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; + } + if (StringPtr != NULL) { + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + } + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + + if ((PerfId == MODULE_LOADIMAGE_END_ID) || (PerfId == MODULE_END_ID)) { + if (mCachedLength != 0) { + if (mFpdtBufferIsReported) { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength); + } else { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength); + } + CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + mCachedLength = 0; + } + } + } + if (mFpdtBufferIsReported) { + mBootRecordSize += FpdtRecordPtr.RecordHeader->Length; + mAcpiBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length; + } else { + mPerformanceLength += FpdtRecordPtr.RecordHeader->Length; + } + return EFI_SUCCESS; +} + /** The constructor function initializes Performance infrastructure for DXE phase. The constructor function publishes Performance and PerformanceEx protocol, allocates memory to log DXE performance and merges PEI performance data to DXE performance log. @@ -1162,10 +1689,12 @@ CreatePerformanceMeasurement ( if (Attribute == PerfStartEntry) { Status = InsertFpdtMeasurement (TRUE, CallerIdentifier, String, String, TimeStamp, Identifier); } else if (Attribute == PerfEndEntry) { Status = InsertFpdtMeasurement (FALSE, CallerIdentifier, String, String, TimeStamp, Identifier); + } else if ( Attribute == PerfEntry) { + Status = InsertFpdtRecord (CallerIdentifier, Guid, String, Address, (UINT16) Identifier); } mLockInsertRecord = FALSE; return Status; } @@ -1470,5 +1999,60 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); } + +/** + 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/DxeCorePerformanceLib/DxeCorePerformanceLib.inf b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf index 68cd76da5b3..3e77f9cd57a 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf @@ -59,10 +59,11 @@ DebugLib UefiLib ReportStatusCodeLib DxeServicesLib PeCoffGetEntryPointLib + DevicePathLib [Protocols] gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h index f9800e34941..a96f4081503 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h @@ -40,10 +40,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include <Library/HobLib.h> #include <Library/BaseLib.h> #include <Library/BaseMemoryLib.h> #include <Library/TimerLib.h> #include <Library/PcdLib.h> +#include <Library/DevicePathLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/UefiLib.h> #include <Library/ReportStatusCodeLib.h> diff --git a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c index 9ed50d22b8d..664e8261af9 100644 --- a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c +++ b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c @@ -376,5 +376,73 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); } + +/** + 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 + ) +{ + EFI_STATUS Status; + + Status = GetPerformanceMeasurementProtocol (); + if (EFI_ERROR (Status)) { + return RETURN_OUT_OF_RESOURCES; + } + + if (mPerformanceMeasurement != NULL) { + Status = mPerformanceMeasurement->CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry); + } else { + ASSERT (FALSE); + } + + return (RETURN_STATUS) Status; +} + +/** + 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/PeiPerformanceLib/PeiPerformanceLib.c b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c index f770a35a995..d7b652c5771 100644 --- a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c +++ b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c @@ -31,11 +31,88 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include <Library/TimerLib.h> #include <Library/PcdLib.h> #include <Library/BaseMemoryLib.h> #define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8)) -#define MAX_RECORD_SIZE (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE) +#define PEI_MAX_RECORD_SIZE (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + STRING_SIZE) + +/** + 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. + @param PeiPerformanceLogHeader Pointer to the header of the PEI Performance records in the GUID Hob. + + @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, + IN OUT FPDT_PEI_EXT_PERF_HEADER **PeiPerformanceLogHeader +) +{ + UINT16 PeiPerformanceLogEntries; + UINTN PeiPerformanceSize; + UINT8 *PeiFirmwarePerformance; + EFI_HOB_GUID_TYPE *GuidHob; + + // + // Get the number of PeiPerformanceLogEntries form PCD. + // + PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ? + PcdGet16 (PcdMaxPeiPerformanceLogEntries16) : + PcdGet8 (PcdMaxPeiPerformanceLogEntries)); + + // + // Create GUID HOB Data. + // + GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid); + PeiFirmwarePerformance = NULL; + while (GuidHob != NULL) { + // + // PEI Performance HOB was found, then return the existing one. + // + PeiFirmwarePerformance = (UINT8*)GET_GUID_HOB_DATA (GuidHob); + *PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance; + if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize > PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE) { + (*PeiPerformanceLogHeader)->HobIsFull = TRUE; + } + if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize <= PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE) { + FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + (*PeiPerformanceLogHeader)->SizeOfAllEntries); + break; + } + // + // Previous HOB is used, then find next one. + // + GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob)); + } + + if (GuidHob == NULL) { + // + // PEI Performance HOB was not found, then build one. + // + PeiPerformanceSize = sizeof (FPDT_PEI_EXT_PERF_HEADER) + + PEI_MAX_RECORD_SIZE * PeiPerformanceLogEntries; + PeiFirmwarePerformance = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize); + if (PeiFirmwarePerformance != NULL) { + ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize); + (*PeiPerformanceLogHeader) = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance; + FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER)); + } + } + + if (PeiFirmwarePerformance == NULL) { + // + // there is no enough resource to store performance data + // + return EFI_OUT_OF_RESOURCES; + } + + 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 @@ -240,23 +317,19 @@ InsertPeiFpdtMeasurement ( IN CONST CHAR8 *Module, OPTIONAL IN UINT64 Ticker, IN UINT32 Identifier ) { - EFI_HOB_GUID_TYPE *GuidHob; - UINTN PeiPerformanceSize; - UINT8 *PeiFirmwarePerformance; - FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; FPDT_RECORD_PTR FpdtRecordPtr; FPDT_BASIC_RECORD_INFO RecordInfo; CONST VOID *ModuleGuid; UINTN DestMax; UINTN StrLength; CONST CHAR8 *StringPtr; EFI_STATUS Status; - UINT16 PeiPerformanceLogEntries; UINT64 TimeStamp; + FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; StringPtr = NULL; FpdtRecordPtr.RecordHeader = NULL; PeiPerformanceLogHeader = NULL; @@ -286,60 +359,13 @@ InsertPeiFpdtMeasurement ( Identifier += 1; } RecordInfo.ProgressID = (UINT16)Identifier; } - // - // Get the number of PeiPerformanceLogEntries form PCD. - // - PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ? - PcdGet16 (PcdMaxPeiPerformanceLogEntries16) : - PcdGet8 (PcdMaxPeiPerformanceLogEntries)); - - // - // Create GUID HOB Data. - // - GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid); - PeiFirmwarePerformance = NULL; - while (GuidHob != NULL) { - // - // PEI Performance HOB was found, then return the existing one. - // - PeiFirmwarePerformance = (UINT8*)GET_GUID_HOB_DATA (GuidHob); - PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance; - if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize > PeiPerformanceLogEntries * MAX_RECORD_SIZE) { - PeiPerformanceLogHeader->HobIsFull = TRUE; - } - if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize <= PeiPerformanceLogEntries * MAX_RECORD_SIZE) { - FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + PeiPerformanceLogHeader->SizeOfAllEntries); - break; - } - // - // Previous HOB is used, then find next one. - // - GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob)); - } - - if (GuidHob == NULL) { - // - // PEI Performance HOB was not found, then build one. - // - PeiPerformanceSize = sizeof (FPDT_PEI_EXT_PERF_HEADER) + - MAX_RECORD_SIZE * PeiPerformanceLogEntries; - PeiFirmwarePerformance = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize); - if (PeiFirmwarePerformance != NULL) { - ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize); - } - PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance; - FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER)); - } - - if (PeiFirmwarePerformance == NULL) { - // - // there is no enough resource to store performance data - // - return EFI_OUT_OF_RESOURCES; + Status = GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr, &PeiPerformanceLogHeader); + if (EFI_ERROR (Status)) { + return Status; } // // Get the TimeStamp. // @@ -690,5 +716,309 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); } + +/** + Get the FPDT record size. + + @param String Pointer to a Null-terminated ASCII string + that identifies the component being measured. + @param PerfId Performance identifier. + @param RecordSize On return, pointer to the size of record. + + @retval EFI_SUCCESS Get record size successfully. + @retval EFI_INVALID_PARAMETER Invalid Performance identifier. + +**/ +EFI_STATUS +GetFpdtRecordSize ( + IN CONST CHAR8 *String, + IN UINT16 PerfId, + OUT UINT8 *RecordSize + ) +{ + UINTN StringSize; + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + *RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE; + } else { + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + *RecordSize = sizeof (FPDT_GUID_EVENT_RECORD); + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize = AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize = STRING_SIZE; + } + *RecordSize = (UINT8) (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + StringSize); + 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: + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize = AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize = STRING_SIZE; + } + *RecordSize = (UINT8) (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + 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 Address - Pointer to a location in memory relevant to the measurement + @param PerfId - Performance identifier describing the type of measurement + + @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 +CreateFpdtRecord ( + IN CONST VOID *CallerIdentifier, OPTIONAL + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 Address, OPTIONAL + IN UINT16 PerfId + ) +{ + FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; + FPDT_RECORD_PTR FpdtRecordPtr; + CONST CHAR8 *StringPtr; + EFI_STATUS Status; + UINT64 TimeStamp; + UINT64 TimeStampCounter; + UINT8 RecordSize; + UINTN DestMax; + UINTN StringLen; + + StringPtr = NULL; + RecordSize = 0; + + Status = GetFpdtRecordSize(String, PerfId, &RecordSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr, &PeiPerformanceLogHeader); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the TimeStamp. + // + TimeStampCounter = GetPerformanceCounter (); + TimeStamp = GetTimeInNanoSecond (TimeStampCounter); + + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + if (CallerIdentifier == NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr = PEIM_TOK; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE; + FpdtRecordPtr.GuidEvent->Header.Length = RecordSize;; + FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.GuidEvent->ProgressID = PerfId; + FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp; + CopyMem (&FpdtRecordPtr.GuidEvent->Guid, CallerIdentifier, sizeof (EFI_GUID)); + PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize; + } + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + if (CallerIdentifier == NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr = LOAD_IMAGE_TOK; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordSize;; + FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId; + FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp; + if (PerfId == MODULE_LOADIMAGE_START_ID) { + PeiPerformanceLogHeader->LoadImageCount++; + } + FpdtRecordPtr.GuidQwordEvent->Qword = PeiPerformanceLogHeader->LoadImageCount; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, CallerIdentifier, sizeof (EFI_GUID)); + PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize; + } + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (CallerIdentifier == NULL || Guid ==NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr = String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length = RecordSize; + 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)); + DestMax = (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, StringPtr, StringLen); + PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize; + } + 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: + if (CallerIdentifier == NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr = String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, sizeof (EFI_GUID)); + DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordSize; + 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 (EFI_GUID)); + } else { + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, sizeof (EFI_GUID)); + } + DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize; + } + + 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 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)CreateFpdtRecord (CallerIdentifier, Guid, String, Address, (UINT16)Identifier); +} + +/** + 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 e630773562f..efbde88220b 100644 --- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c +++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c @@ -45,23 +45,83 @@ typedef struct { HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT]; UINTN mCachePairCount = 0; UINT32 mPerformanceLength = 0; UINT32 mMaxPerformanceLength = 0; +UINT32 mLoadImageCount = 0; BOOLEAN mFpdtDataIsReported = FALSE; BOOLEAN mLackSpaceIsReport = FALSE; CHAR8 *mPlatformLanguage = NULL; SPIN_LOCK mSmmFpdtLock; PERFORMANCE_PROPERTY mPerformanceProperty; +UINT32 mCachedLength = 0; // // Interfaces for SMM PerformanceMeasurement Protocol. // EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = { CreatePerformanceMeasurement, }; +/** + 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_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 + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordSize + FIRMWARE_RECORD_BUFFER, + mSmmBootPerformanceTable + ); + + if (mSmmBootPerformanceTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mSmmBootPerformanceTable->Header.Length = sizeof (SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength; + mMaxPerformanceLength = mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + 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 @@ -506,49 +566,14 @@ InsertFpdtMeasurement ( Identifier += 1; } RecordInfo.ProgressID = (UINT16)Identifier; } - if (mFpdtDataIsReported) { - // - // Append Boot records after Smm boot performance records have been reported. - // - if (mPerformanceLength + RecordInfo.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 + RecordInfo.RecordSize > mMaxPerformanceLength) { - mSmmBootPerformanceTable = ReallocatePool ( - mPerformanceLength, - mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER, - mSmmBootPerformanceTable - ); - - if (mSmmBootPerformanceTable == NULL) { - return EFI_OUT_OF_RESOURCES; - } - mSmmBootPerformanceTable->Header.Length = sizeof (SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength; - mMaxPerformanceLength = mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.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); + Status = GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; } - FpdtRecordPtr.RecordHeader->Length = 0; // // Get the TimeStamp. // if (Ticker == 0) { @@ -630,10 +655,289 @@ InsertFpdtMeasurement ( mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length; return EFI_SUCCESS; } +/** + Get the FPDT record size. + + @param String Pointer to a Null-terminated ASCII string + that identifies the component being measured. + @param PerfId Performance identifier. + @param RecordSize On return, pointer to the size of record. + + @retval EFI_SUCCESS Get record size successfully. + @retval EFI_INVALID_PARAMETER Invalid Performance identifier. + +**/ +EFI_STATUS +GetFpdtRecordSize ( + IN CONST CHAR8 *String, + IN UINT16 PerfId, + OUT UINT8 *RecordSize + ) +{ + UINTN StringSize; + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + *RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE); + } else { + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + *RecordSize = sizeof (FPDT_GUID_EVENT_RECORD); + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize = AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize = STRING_SIZE; + } + *RecordSize = (UINT8) (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + StringSize); + 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: + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize = AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize = STRING_SIZE; + } + *RecordSize = (UINT8) (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + 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 Address - Pointer to a location in memory relevant to the measurement + @param PerfId - Performance identifier describing the type of measurement + + @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 Address, OPTIONAL + IN UINT16 PerfId + ) +{ + EFI_STATUS Status; + EFI_GUID ModuleGuid; + CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH]; + FPDT_RECORD_PTR FpdtRecordPtr; + FPDT_RECORD_PTR CachedFpdtRecordPtr; + UINT64 TimeStamp; + UINT64 TimeStampCounter; + CONST CHAR8 *StringPtr; + UINT8 RecordSize; + UINTN DestMax; + UINTN StringLen; + + StringPtr = NULL; + RecordSize = 0; + ZeroMem (ModuleName, sizeof (ModuleName)); + + Status = GetFpdtRecordSize(String, PerfId, &RecordSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the TimeStamp. + // + TimeStampCounter = GetPerformanceCounter (); + TimeStamp = GetTimeInNanoSecond (TimeStampCounter); + + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + // + // Get the ModuleGuid from the handle. + // + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + StringPtr = ModuleName; + if (PerfId == MODULE_START_ID) { + mCachedLength = mSmmBootPerformanceTable->Header.Length; + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE; + FpdtRecordPtr.GuidEvent->Header.Length = RecordSize; + 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 (PerfId == MODULE_END_ID && mCachedLength != 0) { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength); + CopyMem (&CachedFpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.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++; + mCachedLength = mSmmBootPerformanceTable->Header.Length; + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordSize; + 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 (CallerIdentifier == NULL || Guid ==NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Cache the event guid in string event record when PcdEdkiiFpdtStringRecordEnableOnly == TRUE + // + CopyGuid (&ModuleGuid, Guid); + StringPtr = String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length = RecordSize; + 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)); + DestMax = (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, StringPtr, StringLen); + } + 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: + if (CallerIdentifier == NULL || String == NULL) { + return EFI_INVALID_PARAMETER; + } + CopyGuid (&ModuleGuid, (EFI_GUID *) CallerIdentifier); + StringPtr = String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; + DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); + if (StringPtr != NULL && AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; + } + if (StringPtr != NULL) { + StringLen = AsciiStrLen (StringPtr); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + } + + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + + if ((PerfId == MODULE_LOADIMAGE_END_ID) || (PerfId == MODULE_END_ID)) { + if (mCachedLength != 0) { + CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength); + CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen); + mCachedLength = 0; + } + } + } + + // + // Update the cached FPDT record buffer. + // + mPerformanceLength += FpdtRecordPtr.RecordHeader->Length; + mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length; + + return EFI_SUCCESS; +} + /** SmmReadyToBoot protocol notification event handler. @param Protocol Points to the protocol's unique identifier @param Interface Points to the interface instance @@ -814,15 +1118,19 @@ CreatePerformanceMeasurement( IN PERF_MEASUREMENT_ATTRIBUTE Attribute ) { EFI_STATUS Status; + Status = EFI_SUCCESS; + AcquireSpinLock (&mSmmFpdtLock); if (Attribute == PerfStartEntry) { Status = InsertFpdtMeasurement (TRUE, CallerIdentifier, String, String, TimeStamp, Identifier); } else if (Attribute == PerfEndEntry) { Status = InsertFpdtMeasurement (FALSE, CallerIdentifier, String, String, TimeStamp, Identifier); + } else if (Attribute == PerfEntry) { + Status = InsertFpdtRecord (CallerIdentifier, Guid, String, Address, (UINT16) Identifier); } ReleaseSpinLock (&mSmmFpdtLock); return Status; } @@ -1125,5 +1433,61 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0); } + +/** + 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/SmmPerformanceLib/SmmPerformanceLib.c b/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c index fd820c0e49c..830037befa6 100644 --- a/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c +++ b/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c @@ -395,5 +395,73 @@ 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 + ) +{ + EFI_STATUS Status; + + Status = GetPerformanceMeasurementProtocol (); + if (EFI_ERROR (Status)) { + return RETURN_OUT_OF_RESOURCES; + } + + if (mPerformanceMeasurement != NULL) { + Status = mPerformanceMeasurement->CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry); + } else { + ASSERT (FALSE); + } + + return (RETURN_STATUS) Status; +} + +/** + 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; +} -- 2.14.3.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel