From 6b4d58a10c5bf186fcf049e41c38316167cb8e2c Mon Sep 17 00:00:00 2001 From: "Bi, Dandan" Date: Fri, 22 Jun 2018 16:56:19 +0800 Subject: [PATCH] MdeModulePkg: Update performance library instances Update the performance library instances in MdeModulePkg to implement the APIs used for new added Perf macros. V2: Share the common logics of creating FPDT record for new added Perf macros and existing Perf macros. Cc: Liming Gao Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Dandan Bi Reviewed-by: Liming Gao --- .../Guid/ExtendedFirmwarePerformance.h | 6 - .../DxeCorePerformanceLib.c | 864 ++++++++++++------ .../DxeCorePerformanceLib.inf | 1 + .../DxeCorePerformanceLibInternal.h | 1 + .../DxePerformanceLib/DxePerformanceLib.c | 68 ++ .../PeiPerformanceLib/PeiPerformanceLib.c | 632 ++++++++----- .../SmmCorePerformanceLib.c | 645 ++++++++----- .../SmmPerformanceLib/SmmPerformanceLib.c | 68 ++ 8 files changed, 1565 insertions(+), 720 deletions(-) diff --git a/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h b/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h index 465b408275..dedb0b82f0 100644 --- a/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h +++ b/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h @@ -220,12 +220,6 @@ typedef struct { #pragma pack() -typedef struct { - UINT16 ProgressID; - UINT16 Type; - UINT8 RecordSize; -} FPDT_BASIC_RECORD_INFO; - // // Union of all FPDT records // diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c index 7982060518..efff5134c7 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c @@ -71,6 +71,7 @@ UINT32 mPerformanceLength = 0; UINT32 mMaxPerformanceLength = 0; UINT32 mBootRecordSize = 0; UINT32 mBootRecordMaxSize = 0; +UINT32 mCachedLength = 0; BOOLEAN mFpdtBufferIsReported = FALSE; BOOLEAN mLackSpaceIsReported = FALSE; @@ -78,6 +79,7 @@ CHAR8 *mPlatformLanguage = NULL; UINT8 *mPerformancePointer = NULL; UINT8 *mBootRecordBuffer = NULL; BOOLEAN mLockInsertRecord = FALSE; +CHAR8 *mDevicePathString = NULL; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevicePathToText = NULL; @@ -90,6 +92,60 @@ EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = { 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. @@ -587,278 +643,351 @@ Done: } /** - Get the FPDT record info. + Get the FPDT record identifier. - @param IsStart TRUE if the performance log is start log. - @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 RecordInfo On return, pointer to the info of the record. - @param UseModuleName Only useful for FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use - Module name to fill the string field in the FPDT_DYNAMIC_STRING_EVENT_RECORD. + @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_UNSUPPORTED No matched FPDT record. + @retval EFI_SUCCESS Get record info successfully. + @retval EFI_INVALID_PARAMETER No matched FPDT record. **/ EFI_STATUS -GetFpdtRecordInfo ( - IN BOOLEAN IsStart, - IN CONST VOID *Handle, - IN CONST CHAR8 *Token, - IN CONST CHAR8 *Module, - OUT FPDT_BASIC_RECORD_INFO *RecordInfo, - IN OUT BOOLEAN *UseModuleName +GetFpdtRecordId ( + IN PERF_MEASUREMENT_ATTRIBUTE Attribute, + IN CONST VOID *Handle, + IN CONST CHAR8 *String, + OUT UINT16 *ProgressID ) { - UINT16 RecordType; - UINTN StringSize; - - RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE; - // - // Token to Type and Id. + // Token to PerfId. // - if (Token != NULL) { - if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) { // "StartImage:" - *UseModuleName = TRUE; - RecordType = FPDT_GUID_EVENT_TYPE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_START_ID; + if (String != NULL) { + if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_START_ID; } else { - RecordInfo->ProgressID = MODULE_END_ID; + *ProgressID = MODULE_END_ID; } - } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" - *UseModuleName = TRUE; - RecordType = FPDT_GUID_QWORD_EVENT_TYPE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID; + } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_LOADIMAGE_START_ID; } else { - RecordInfo->ProgressID = MODULE_LOADIMAGE_END_ID; + *ProgressID = MODULE_LOADIMAGE_END_ID; } - } else if (AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0) { // "DB:Start:" - *UseModuleName = TRUE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_DB_START_ID; - RecordType = FPDT_GUID_QWORD_EVENT_TYPE; + } else if (AsciiStrCmp (String, DRIVERBINDING_START_TOK) == 0) { // "DB:Start:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_DB_START_ID; } else { - RecordInfo->ProgressID = MODULE_DB_END_ID; - RecordType = FPDT_GUID_QWORD_STRING_EVENT_TYPE; + *ProgressID = MODULE_DB_END_ID; } - } else if (AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0) { // "DB:Support:" - *UseModuleName = TRUE; + } else if (AsciiStrCmp (String, DRIVERBINDING_SUPPORT_TOK) == 0) { // "DB:Support:" if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { return RETURN_UNSUPPORTED; } - RecordType = FPDT_GUID_QWORD_EVENT_TYPE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_DB_SUPPORT_START_ID; + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_DB_SUPPORT_START_ID; } else { - RecordInfo->ProgressID = MODULE_DB_SUPPORT_END_ID; + *ProgressID = MODULE_DB_SUPPORT_END_ID; } - } else if (AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0) { // "DB:Stop:" - *UseModuleName = TRUE; + } else if (AsciiStrCmp (String, DRIVERBINDING_STOP_TOK) == 0) { // "DB:Stop:" if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { return RETURN_UNSUPPORTED; } - RecordType = FPDT_GUID_QWORD_EVENT_TYPE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_DB_STOP_START_ID; + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_DB_STOP_START_ID; } else { - RecordInfo->ProgressID = MODULE_DB_STOP_END_ID; + *ProgressID = MODULE_DB_STOP_END_ID; } - } else if (AsciiStrCmp (Token, PEI_TOK) == 0 || // "PEI" - AsciiStrCmp (Token, DXE_TOK) == 0 || // "DXE" - AsciiStrCmp (Token, BDS_TOK) == 0) { // "BDS" - if (IsStart) { - RecordInfo->ProgressID = PERF_CROSSMODULE_START_ID; + } else if (AsciiStrCmp (String, PEI_TOK) == 0 || // "PEI" + AsciiStrCmp (String, DXE_TOK) == 0 || // "DXE" + AsciiStrCmp (String, BDS_TOK) == 0) { // "BDS" + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_CROSSMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_CROSSMODULE_END_ID; + *ProgressID = PERF_CROSSMODULE_END_ID; } } else { // Pref used in Modules. - if (IsStart) { - RecordInfo->ProgressID = PERF_INMODULE_START_ID; + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_INMODULE_END_ID; + *ProgressID = PERF_INMODULE_END_ID; } } - } else if (Handle!= NULL || Module != NULL) { // Pref used in Modules. - if (IsStart) { - RecordInfo->ProgressID = PERF_INMODULE_START_ID; + } else if (Handle!= NULL) { // Pref used in Modules. + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_INMODULE_END_ID; + *ProgressID = PERF_INMODULE_END_ID; } } else { - return EFI_UNSUPPORTED; + return EFI_INVALID_PARAMETER; } + 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); - // - // Get Record size baesed on the record type. - // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with type of FPDT_DYNAMIC_STRING_EVENT_TYPE. - // if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { - RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE; - RecordInfo->RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE; + DestMax = STRING_SIZE; } else { - switch (RecordType) { - case FPDT_GUID_EVENT_TYPE: - RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD); - break; - - case FPDT_DYNAMIC_STRING_EVENT_TYPE: - if (*UseModuleName) { - StringSize = STRING_SIZE; - } else if (Token != NULL) { - StringSize = AsciiStrSize (Token); - } else if (Module != NULL) { - StringSize = AsciiStrSize (Module); - } else { - StringSize = STRING_SIZE; - } - if (StringSize > STRING_SIZE) { - StringSize = STRING_SIZE; - } - RecordInfo->RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize); - break; + 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; +} + +/** + Get a string description for device for the given controller handle and update record + length. If ComponentName2 GetControllerName is supported, the value is included in the string, + followed by device path, otherwise just device path. - case FPDT_GUID_QWORD_EVENT_TYPE: - RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD); - break; + @param Handle - Image handle + @param ControllerHandle - Controller handle. + @param ComponentNameString - Pointer to a location where the string will be saved + @param Length - Pointer to record length to be updated - case FPDT_GUID_QWORD_STRING_EVENT_TYPE: - RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD); - break; + @retval EFI_SUCCESS - Successfully got string description for device + @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor DevicePath were found - default: +**/ +EFI_STATUS +GetDeviceInfoFromHandleAndUpdateLength ( + IN CONST VOID *Handle, + IN EFI_HANDLE ControllerHandle, + OUT CHAR8 *ComponentNameString, + 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) { // - // Record is unsupported yet, return EFI_UNSUPPORTED + // Only copy enough to fill FPDT_MAX_PERF_RECORD_SIZE worth of the record // - return EFI_UNSUPPORTED; + ControllerNameStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length) - 1; } + + UnicodeStrToAsciiStrS(StringPtr, ComponentNameString, ControllerNameStringSize); + + // + // Add a space in the end of the ControllerName + // + AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1; + *AsciiStringPtr = 0x20; + AsciiStringPtr++; + *AsciiStringPtr = 0; + ControllerNameStringSize++; + + *Length += (UINT8)ControllerNameStringSize; } - RecordInfo->Type = RecordType; - return EFI_SUCCESS; + // + // 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 FPDT_MAX_PERF_RECORD_SIZE worth of the record + // + DevicePathStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length); + } + + if (ControllerNameStringSize != 0) { + AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1; + } else { + AsciiStringPtr = ComponentNameString; + } + + UnicodeStrToAsciiStrS(StringPtr, AsciiStringPtr, DevicePathStringSize); + *Length += (UINT8)DevicePathStringSize; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; } /** - Add performance log to FPDT boot record table. + Create performance record with event description and a timestamp. - @param IsStart TRUE if the performance log is start log. - @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 Ticker 64-bit time stamp. - @param Identifier 32-bit identifier. If the value is 0, the created record - is same as the one created by StartGauge of PERFORMANCE_PROTOCOL. + @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 Add FPDT boot record. - @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement. - @retval EFI_UNSUPPORTED No matched FPDT record. + @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 -InsertFpdtMeasurement ( - IN BOOLEAN IsStart, - IN CONST VOID *Handle, OPTIONAL - IN CONST CHAR8 *Token, OPTIONAL - IN CONST CHAR8 *Module, OPTIONAL - IN UINT64 Ticker, - IN UINT32 Identifier +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_GUID ModuleGuid; CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH]; - EFI_STATUS Status; FPDT_RECORD_PTR FpdtRecordPtr; - FPDT_BASIC_RECORD_INFO RecordInfo; + FPDT_RECORD_PTR CachedFpdtRecordPtr; UINT64 TimeStamp; - UINTN DestMax; - UINTN StrLength; CONST CHAR8 *StringPtr; - BOOLEAN UseModuleName; + UINTN DestMax; + UINTN StringLen; + EFI_STATUS Status; + UINT16 ProgressId; StringPtr = NULL; - UseModuleName = FALSE; + ProgressId = 0; ZeroMem (ModuleName, sizeof (ModuleName)); // - // Get record info (type, size, ProgressID and Module Guid). - // - Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, &UseModuleName); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // If PERF_START()/PERF_END() 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. + // 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 ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) { - return EFI_UNSUPPORTED; - } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) { - if (IsStart && ((Identifier & 0x000F) != 0)) { - Identifier &= 0xFFF0; - } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) { - Identifier += 1; - } - RecordInfo.ProgressID = (UINT16)Identifier; - } - - if (mFpdtBufferIsReported) { + if (Attribute != PerfEntry) { // - // Append Boot records to the boot performance table. + // 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 (mBootRecordSize + RecordInfo.RecordSize > mBootRecordMaxSize) { - if (!mLackSpaceIsReported) { - DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n")); - mLackSpaceIsReported = TRUE; + 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; } - return EFI_OUT_OF_RESOURCES; - } else { + } else if (PerfId == 0) { // - // Save boot record into BootPerformance table + // Get ProgressID form the String Token. // - 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; + Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId); + if (EFI_ERROR (Status)) { + return Status; } - mMaxPerformanceLength = mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER; + PerfId = ProgressId; } - // - // Covert buffer to FPDT Ptr Union type. - // - FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength); - mPerformanceLength += RecordInfo.RecordSize; } // - // Get the TimeStamp. + // 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 (); @@ -870,81 +999,248 @@ InsertFpdtMeasurement ( } // - // Get the ModuleName and ModuleGuid form the handle. - // - GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof (ModuleName), &ModuleGuid); - - // - // Fill in the record information. + // 4. Fill in the FPDT record according to different Performance Identifier. // - switch (RecordInfo.Type) { - case FPDT_GUID_EVENT_TYPE: - FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE; - FpdtRecordPtr.GuidEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid)); + 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 (Attribute == PerfEntry && 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 = 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) { + 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 (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid)); + mCachedLength = 0; + } + } break; - case FPDT_DYNAMIC_STRING_EVENT_TYPE: - FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; - FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.DynamicStringEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); - - if (UseModuleName) { - StringPtr = ModuleName; - } else if (Token != NULL) { - StringPtr = Token; - } else if (Module != NULL) { - StringPtr = Module; - } else if (ModuleName != NULL) { - StringPtr = ModuleName; + 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) { + if (mFpdtBufferIsReported) { + mCachedLength = mBootRecordSize; + } else { + mCachedLength = mPerformanceLength; + } + } } - if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) { - StrLength = AsciiStrLen (StringPtr); - DestMax = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); - if (StrLength >= DestMax) { - StrLength = DestMax -1; + 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) { + 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; } - AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength); - } else { - AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name"); } break; - case FPDT_GUID_QWORD_EVENT_TYPE: - FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; - FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidQwordEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid)); - if ((MODULE_LOADIMAGE_START_ID == RecordInfo.ProgressID) && AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) { - mLoadImageCount++; - FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount; + 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: + 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 = 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 = Address; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid)); } break; - case FPDT_GUID_QWORD_STRING_EVENT_TYPE: - FpdtRecordPtr.GuidQwordStringEvent->Header.Type = FPDT_GUID_QWORD_STRING_EVENT_TYPE; - FpdtRecordPtr.GuidQwordStringEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidQwordStringEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidQwordStringEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordStringEvent->Guid)); + case MODULE_DB_END_ID: + 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 = sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD);; + 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)); + if (Address != 0) { + GetDeviceInfoFromHandleAndUpdateLength(CallerIdentifier, (EFI_HANDLE)(UINTN)Address, FpdtRecordPtr.GuidQwordStringEvent->String, &FpdtRecordPtr.GuidQwordStringEvent->Header.Length); + } + } break; - default: + 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; + } // - // Record is not supported in current DXE phase, return EFI_ABORTED + // Cache the event guid in string event record when PcdEdkiiFpdtStringRecordEnableOnly == TRUE // - return EFI_UNSUPPORTED; + CopyGuid (&ModuleGuid, Guid); + StringPtr = String; + 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: + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + if (String != NULL) { + StringPtr = String; + } else { + StringPtr = ModuleName; + } + if (AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; + } + 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) { + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + if (String != NULL) { + StringPtr = String; + } else { + StringPtr = ModuleName; + } + if (AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; + } + 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 ||PerfId == MODULE_DB_SUPPORT_START_ID || PerfId == MODULE_DB_SUPPORT_END_ID) { + 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; + 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) { + 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); + } + 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. + // + if (mFpdtBufferIsReported) { + mBootRecordSize += FpdtRecordPtr.RecordHeader->Length; + mAcpiBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length; + } else { + mPerformanceLength += FpdtRecordPtr.RecordHeader->Length; + } return EFI_SUCCESS; } @@ -1160,11 +1456,8 @@ CreatePerformanceMeasurement ( } mLockInsertRecord = TRUE; - if (Attribute == PerfStartEntry) { - Status = InsertFpdtMeasurement (TRUE, CallerIdentifier, String, String, TimeStamp, Identifier); - } else if (Attribute == PerfEndEntry) { - Status = InsertFpdtMeasurement (FALSE, CallerIdentifier, String, String, TimeStamp, Identifier); - } + Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute); + mLockInsertRecord = FALSE; return Status; @@ -1472,3 +1765,58 @@ PerformanceMeasurementEnabled ( { 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 68cd76da5b..3e77f9cd57 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf @@ -61,6 +61,7 @@ ReportStatusCodeLib DxeServicesLib PeCoffGetEntryPointLib + DevicePathLib [Protocols] gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h index f9800e3494..a96f408150 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h @@ -42,6 +42,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include diff --git a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c index 9ed50d22b8..664e8261af 100644 --- a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c +++ b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c @@ -378,3 +378,71 @@ PerformanceMeasurementEnabled ( { 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 f770a35a99..cd1b0e34ef 100644 --- a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c +++ b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c @@ -23,6 +23,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include #include #include @@ -33,7 +34,85 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #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 > (UINTN)(PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) { + (*PeiPerformanceLogHeader)->HobIsFull = TRUE; + } + if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize <= (UINTN)(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. @@ -100,248 +179,193 @@ IsKnownID ( } /** - Get the FPDT record info. + Get the FPDT record identifier. - @param IsStart TRUE if the performance log is start log. - @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 RecordInfo On return, pointer to the info of the record. + @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_UNSUPPORTED No matched FPDT record. + @retval EFI_SUCCESS Get record info successfully. + @retval EFI_INVALID_PARAMETER No matched FPDT record. **/ EFI_STATUS -GetFpdtRecordInfo ( - IN BOOLEAN IsStart, +GetFpdtRecordId ( + IN BOOLEAN Attribute, IN CONST VOID *Handle, - IN CONST CHAR8 *Token, - IN CONST CHAR8 *Module, - OUT FPDT_BASIC_RECORD_INFO *RecordInfo + IN CONST CHAR8 *String, + OUT UINT16 *ProgressID ) { - UINTN StringSize; - UINT16 RecordType; - - RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE; - // // Get the ProgressID based on the Token. // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with type of FPDT_DYNAMIC_STRING_EVENT_TYPE. // - if (Token != NULL) { - if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" - if (IsStart) { - RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID; + if (String != NULL) { + if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_LOADIMAGE_START_ID; } else { - RecordInfo->ProgressID = MODULE_LOADIMAGE_END_ID; + *ProgressID = MODULE_LOADIMAGE_END_ID; } - if(!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { - RecordType = FPDT_GUID_QWORD_EVENT_TYPE; - } - } else if (AsciiStrCmp (Token, SEC_TOK) == 0 || // "SEC" - AsciiStrCmp (Token, PEI_TOK) == 0) { // "PEI" - if (IsStart) { - RecordInfo->ProgressID = PERF_CROSSMODULE_START_ID; + } else if (AsciiStrCmp (String, SEC_TOK) == 0 || // "SEC" + AsciiStrCmp (String, PEI_TOK) == 0) { // "PEI" + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_CROSSMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_CROSSMODULE_END_ID; + *ProgressID = PERF_CROSSMODULE_END_ID; } - } else if (AsciiStrCmp (Token, PEIM_TOK) == 0) { // "PEIM" - if (IsStart) { - RecordInfo->ProgressID = MODULE_START_ID; + } else if (AsciiStrCmp (String, PEIM_TOK) == 0) { // "PEIM" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_START_ID; } else { - RecordInfo->ProgressID = MODULE_END_ID; - } - if(!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { - RecordType = FPDT_GUID_EVENT_TYPE; + *ProgressID = MODULE_END_ID; } } else { //Pref used in Modules. - if (IsStart) { - RecordInfo->ProgressID = PERF_INMODULE_START_ID; + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_INMODULE_END_ID; + *ProgressID = PERF_INMODULE_END_ID; } } - } else if (Module != NULL || Handle != NULL) { //Pref used in Modules. - if (IsStart) { - RecordInfo->ProgressID = PERF_INMODULE_START_ID; + } else if (Handle != NULL) { //Pref used in Modules. + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_INMODULE_END_ID; + *ProgressID = PERF_INMODULE_END_ID; } } else { - return EFI_UNSUPPORTED; + return EFI_INVALID_PARAMETER; } - // - // Get the Guid and string. - // - if(PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { - RecordInfo->RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE; - } else { - switch (RecordType) { - case FPDT_GUID_EVENT_TYPE: - RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD); - break; + return EFI_SUCCESS; +} - case FPDT_GUID_QWORD_EVENT_TYPE: - RecordInfo->RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD); - break; +/** + Copies the string from Source into Destination and updates Length with the + size of the string. - case FPDT_DYNAMIC_STRING_EVENT_TYPE: - if (Token != NULL) { - StringSize = AsciiStrSize (Token); - } else if (Module != NULL) { - StringSize = AsciiStrSize (Module); - } else { - StringSize = STRING_SIZE; - } - RecordInfo->RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize); - break; + @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 - default: - // - // Other type is unsupported in PEI phase yet, return EFI_UNSUPPORTED - // - return EFI_UNSUPPORTED; +**/ +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; } } - RecordInfo->Type = RecordType; - return EFI_SUCCESS; + StringLen = AsciiStrLen (Source); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + + AsciiStrnCpyS(Destination, DestMax, Source, StringLen); + *Length += (UINT8)DestMax; + + return; } + /** Convert PEI performance log to FPDT String boot record. - @param IsStart TRUE if the performance log is start log. - @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 Ticker 64-bit time stamp. - @param Identifier 32-bit identifier. If the value is 0, the created record - is same as the one created by StartGauge of PERFORMANCE_PROTOCOL. - - @retval EFI_SUCCESS Add FPDT boot record. - @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement. - @retval EFI_UNSUPPORTED No matched FPDT record. + @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. **/ EFI_STATUS -InsertPeiFpdtMeasurement ( - IN BOOLEAN IsStart, - IN CONST VOID *Handle, OPTIONAL - IN CONST CHAR8 *Token, OPTIONAL - IN CONST CHAR8 *Module, OPTIONAL - IN UINT64 Ticker, - IN UINT32 Identifier +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_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; // - // Get record info (type, size, ProgressID and Module Guid). - // - Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // If PERF_START()/PERF_END() 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. + // 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 ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) { - return EFI_UNSUPPORTED; - } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) { - if (IsStart && ((Identifier & 0x000F) != 0)) { - Identifier &= 0xFFF0; - } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) { - 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) { + if (Attribute != PerfEntry) { // - // PEI Performance HOB was not found, then build one. + // 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. // - PeiPerformanceSize = sizeof (FPDT_PEI_EXT_PERF_HEADER) + - MAX_RECORD_SIZE * PeiPerformanceLogEntries; - PeiFirmwarePerformance = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize); - if (PeiFirmwarePerformance != NULL) { - ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize); + if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) { + return EFI_UNSUPPORTED; + } 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; + } + } else if (PerfId == 0) { + Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &PerfId); + if (EFI_ERROR (Status)) { + return Status; + } } - 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; + // + // 2. Get the buffer to store the FPDT record. + // + Status = GetFpdtRecordPtr (PEI_MAX_RECORD_SIZE, &FpdtRecordPtr, &PeiPerformanceLogHeader); + if (EFI_ERROR (Status)) { + return Status; } // - // Get the TimeStamp. + // 3 Get the TimeStamp. // if (Ticker == 0) { Ticker = GetPerformanceCounter (); @@ -353,70 +377,138 @@ InsertPeiFpdtMeasurement ( } // - // Get the ModuleGuid. + // 4.Get the ModuleGuid. // - if (Handle != NULL) { - ModuleGuid = Handle; + if (CallerIdentifier != NULL) { + ModuleGuid = CallerIdentifier; } else { ModuleGuid = &gEfiCallerIdGuid; } - switch (RecordInfo.Type) { - case FPDT_GUID_EVENT_TYPE: - FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE; - FpdtRecordPtr.GuidEvent->Header.Length = RecordInfo.RecordSize;; - FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.GuidEvent->Guid, ModuleGuid, sizeof (EFI_GUID)); - PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize; + // + // 5. Fill in the FPDT record according to different Performance Identifier. + // + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + StringPtr = PEIM_TOK; + 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 (EFI_GUID)); + } break; - case FPDT_GUID_QWORD_EVENT_TYPE: - FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; - FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordInfo.RecordSize;; - FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidQwordEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp; - PeiPerformanceLogHeader->LoadImageCount++; - FpdtRecordPtr.GuidQwordEvent->Qword = PeiPerformanceLogHeader->LoadImageCount; - CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof (EFI_GUID)); - PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize; + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + StringPtr = LOAD_IMAGE_TOK; + 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; + if (PerfId == MODULE_LOADIMAGE_START_ID) { + PeiPerformanceLogHeader->LoadImageCount++; + } + FpdtRecordPtr.GuidQwordEvent->Qword = PeiPerformanceLogHeader->LoadImageCount; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof (EFI_GUID)); + } break; - case FPDT_DYNAMIC_STRING_EVENT_TYPE: - FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; - FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.DynamicStringEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (EFI_GUID)); - PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize; - - if (Token != NULL) { - StringPtr = Token; - } else if (Module != NULL) { - StringPtr = Module; + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String != NULL && AsciiStrLen (String) != 0) { + StringPtr = String; + } else { + StringPtr = "unknown name"; } - if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) { - DestMax = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); - StrLength = AsciiStrLen (StringPtr); - if (StrLength >= DestMax) { - StrLength = DestMax -1; - } - AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength); + 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, ModuleGuid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1)); + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2)); + } + 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 && AsciiStrLen (String) != 0) { + StringPtr = String; } else { - AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name"); + StringPtr = "unknown name"; + } + 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 (EFI_GUID)); + CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length); } break; default: - // - // Record is not supported in current PEI phase, return EFI_ABORTED - // - return EFI_UNSUPPORTED; + if (Attribute != PerfEntry) { + if (String != NULL && AsciiStrLen (String) != 0) { + StringPtr = String; + } else { + StringPtr = "unknown name"; + } + 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; + } + + // + // 5.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries. + // + 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; + if (Guid != NULL) { + // + // Cache the event guid in string event record. + // + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (EFI_GUID)); + } else { + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (EFI_GUID)); + } + CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length); } + // + // 6. Update the length of the used buffer after fill in the record. + // + PeiPerformanceLogHeader->SizeOfAllEntries += FpdtRecordPtr.RecordHeader->Length; + return EFI_SUCCESS; } @@ -454,7 +546,18 @@ StartPerformanceMeasurementEx ( IN UINT32 Identifier ) { - return InsertPeiFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, Identifier); + CONST CHAR8 *String; + + if (Token != NULL) { + String = Token; + } else if (Module != NULL) { + String = Module; + } else { + String = NULL; + } + + return (RETURN_STATUS)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, (UINT16)Identifier, PerfStartEntry); + } /** @@ -489,7 +592,17 @@ EndPerformanceMeasurementEx ( IN UINT32 Identifier ) { - return InsertPeiFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, Identifier); + CONST CHAR8 *String; + + if (Token != NULL) { + String = Token; + } else if (Module != NULL) { + String = Module; + } else { + String = NULL; + } + + return (RETURN_STATUS)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, (UINT16)Identifier, PerfEndEntry); } /** @@ -582,7 +695,7 @@ StartPerformanceMeasurement ( IN UINT64 TimeStamp ) { - return InsertPeiFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, 0); + return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0); } /** @@ -614,7 +727,7 @@ EndPerformanceMeasurement ( IN UINT64 TimeStamp ) { - return InsertPeiFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, 0); + return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0); } /** @@ -692,3 +805,58 @@ PerformanceMeasurementEnabled ( { 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)InsertFpdtRecord (CallerIdentifier, Guid, String, 0, Address, (UINT16)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 e630773562..0c00fb51e8 100644 --- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c +++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c @@ -47,11 +47,13 @@ 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. @@ -60,6 +62,64 @@ 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. @@ -125,113 +185,59 @@ IsKnownID ( } /** - Get the FPDT record info. + Get the FPDT record identifier. - @param IsStart TRUE if the performance log is start log. - @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 RecordInfo On return, pointer to the info of the record. - @param UseModuleName Only useful for FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use - Module name to fill the string field in the FPDT_DYNAMIC_STRING_EVENT_RECORD. + @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_UNSUPPORTED No matched FPDT record. + @retval EFI_SUCCESS Get record info successfully. + @retval EFI_INVALID_PARAMETER No matched FPDT record. **/ EFI_STATUS -GetFpdtRecordInfo ( - IN BOOLEAN IsStart, - IN CONST VOID *Handle, - IN CONST CHAR8 *Token, - IN CONST CHAR8 *Module, - OUT FPDT_BASIC_RECORD_INFO *RecordInfo, - IN OUT BOOLEAN *UseModuleName +GetFpdtRecordId ( + IN PERF_MEASUREMENT_ATTRIBUTE Attribute, + IN CONST VOID *Handle, + IN CONST CHAR8 *String, + OUT UINT16 *ProgressID ) { - UINT16 RecordType; - UINTN StringSize; - - RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE; - // - // Token to Type and Id. + // Token to Id. // - if (Token != NULL) { - if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) { // "StartImage:" - *UseModuleName = TRUE; - RecordType = FPDT_GUID_EVENT_TYPE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_START_ID; + if (String != NULL) { + if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_START_ID; } else { - RecordInfo->ProgressID = MODULE_END_ID; + *ProgressID = MODULE_END_ID; } - } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" - *UseModuleName = TRUE; - RecordType = FPDT_GUID_QWORD_EVENT_TYPE; - if (IsStart) { - RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID; + } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_LOADIMAGE_START_ID; } else { - RecordInfo->ProgressID = MODULE_LOADIMAGE_END_ID; + *ProgressID = MODULE_LOADIMAGE_END_ID; } } else { // Pref used in Modules - if (IsStart) { - RecordInfo->ProgressID = PERF_INMODULE_START_ID; + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_INMODULE_END_ID; + *ProgressID = PERF_INMODULE_END_ID; } } - } else if (Handle != NULL || Module != NULL) { // Pref used in Modules - if (IsStart) { - RecordInfo->ProgressID = PERF_INMODULE_START_ID; + } else if (Handle != NULL) { // Pref used in Modules + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; } else { - RecordInfo->ProgressID = PERF_INMODULE_END_ID; + *ProgressID = PERF_INMODULE_END_ID; } } else { return EFI_UNSUPPORTED; } - - if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { - RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE; - RecordInfo->RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE; - } else { - switch (RecordType) { - case FPDT_GUID_EVENT_TYPE: - RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD); - break; - - case FPDT_DYNAMIC_STRING_EVENT_TYPE: - if (*UseModuleName) { - StringSize = STRING_SIZE; - } else if (Token != NULL) { - StringSize = AsciiStrSize (Token); - } else if (Module != NULL) { - StringSize = AsciiStrSize (Module); - } else { - StringSize = STRING_SIZE; - } - if (StringSize > STRING_SIZE) { - StringSize = STRING_SIZE; - } - RecordInfo->RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize); - break; - - case FPDT_GUID_QWORD_EVENT_TYPE: - RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD); - break; - - default: - // - // Record type is unsupported in SMM phase. - // - return EFI_UNSUPPORTED; - } - } - - RecordInfo->Type = RecordType; return EFI_SUCCESS; } @@ -437,119 +443,140 @@ Done: } /** - Add performance log to FPDT boot record table. + Copies the string from Source into Destination and updates Length with the + size of the string. - @param IsStart TRUE if the performance log is start log. - @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 Ticker 64-bit time stamp. - @param Identifier 32-bit identifier. If the value is 0, the created record - is same as the one created by StartGauge of PERFORMANCE_PROTOCOL. + @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; + } - @retval EFI_SUCCESS Add FPDT boot record. - @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement. - @retval EFI_UNSUPPORTED No matched FPDT record. + 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 -InsertFpdtMeasurement ( - IN BOOLEAN IsStart, - IN CONST VOID *Handle, OPTIONAL - IN CONST CHAR8 *Token, OPTIONAL - IN CONST CHAR8 *Module, OPTIONAL - IN UINT64 Ticker, - IN UINT32 Identifier +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]; - EFI_STATUS Status; FPDT_RECORD_PTR FpdtRecordPtr; + FPDT_RECORD_PTR CachedFpdtRecordPtr; UINT64 TimeStamp; - FPDT_BASIC_RECORD_INFO RecordInfo; - UINTN DestMax; - UINTN StrLength; CONST CHAR8 *StringPtr; - BOOLEAN UseModuleName; + UINTN DestMax; + UINTN StringLen; + UINT16 ProgressId; StringPtr = NULL; - UseModuleName = FALSE; ZeroMem (ModuleName, sizeof (ModuleName)); // - // Get record info includes type, size, ProgressID. - // - Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, &UseModuleName); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // If PERF_START()/PERF_END() 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. + // 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 ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) { - return EFI_UNSUPPORTED; - } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) { - if (IsStart && ((Identifier & 0x000F) != 0)) { - Identifier &= 0xFFF0; - } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) { - Identifier += 1; - } - RecordInfo.ProgressID = (UINT16)Identifier; - } - - if (mFpdtDataIsReported) { + if (Attribute != PerfEntry) { // - // Append Boot records after Smm boot performance records have been reported. + // 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 (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) { - if (!mLackSpaceIsReport) { - DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n")); - mLackSpaceIsReport = TRUE; + 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; } - return EFI_OUT_OF_RESOURCES; - } else { + } + if (PerfId == 0) { // - // Covert buffer to FPDT Ptr Union type. + // Get ProgressID form the String Token. // - 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; + Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId); + if (EFI_ERROR (Status)) { + return Status; } - mSmmBootPerformanceTable->Header.Length = sizeof (SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength; - mMaxPerformanceLength = mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER; + PerfId = ProgressId; } - // - // 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; // - // Get the TimeStamp. + // 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 (); @@ -561,70 +588,186 @@ InsertFpdtMeasurement ( } // - // Get the ModuleName and ModuleGuid form the handle. + // 4. Fill in the FPDT record according to different Performance Identifier. // - GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof (ModuleName), &ModuleGuid); + 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; - // - // Fill in the record information. - // - switch (RecordInfo.Type) { - case FPDT_GUID_EVENT_TYPE: - FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE; - FpdtRecordPtr.GuidEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid)); + 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 FPDT_DYNAMIC_STRING_EVENT_TYPE: - FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE; - FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.DynamicStringEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + 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; + } + // + // 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 = 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; - if (UseModuleName) { - StringPtr = ModuleName; - } else if (Token != NULL) { - StringPtr = Token; - } else if (Module != NULL) { - StringPtr = Module; - } else if (ModuleName != NULL) { - StringPtr = ModuleName; + 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: + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + if (String != NULL) { + StringPtr = String; + } else { + StringPtr = ModuleName; + } + if (AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; } - if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) { - StrLength = AsciiStrLen (StringPtr); - DestMax = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8); - if (StrLength >= DestMax) { - StrLength = DestMax -1; + 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) { + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + if (String != NULL) { + StringPtr = String; + } else { + StringPtr = ModuleName; + } + if (AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; + } + 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); } - AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength); } else { - AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name"); + return EFI_INVALID_PARAMETER; } break; + } - case FPDT_GUID_QWORD_EVENT_TYPE: - FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE; - FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordInfo.RecordSize; - FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1; - FpdtRecordPtr.GuidQwordEvent->ProgressID = RecordInfo.ProgressID; - FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp; - CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid)); - 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; + 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); - default: - // - // Record is not supported in current SMM phase, return EFI_UNSUPPORTED - // - return EFI_UNSUPPORTED; + 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; + } } // - // Update the cached FPDT record buffer. + // 5. Update the length of the used buffer after fill in the record. // mPerformanceLength += FpdtRecordPtr.RecordHeader->Length; mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length; @@ -816,12 +959,10 @@ CreatePerformanceMeasurement( { 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); - } + Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute); ReleaseSpinLock (&mSmmFpdtLock); return Status; } @@ -1127,3 +1268,59 @@ PerformanceMeasurementEnabled ( { 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 fd820c0e49..830037befa 100644 --- a/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c +++ b/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c @@ -397,3 +397,71 @@ PerformanceMeasurementEnabled ( { 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.39.2