From nobody Mon Sep 16 18:51:39 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1529393190097414.79782512299766; Tue, 19 Jun 2018 00:26:30 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 3C7E2211299BD; Tue, 19 Jun 2018 00:26:29 -0700 (PDT) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D06AF210DC1B0 for ; Tue, 19 Jun 2018 00:26:27 -0700 (PDT) Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Jun 2018 00:26:27 -0700 Received: from shwdeopenpsi114.ccr.corp.intel.com ([10.239.157.135]) by orsmga006.jf.intel.com with ESMTP; 19 Jun 2018 00:26:26 -0700 X-Original-To: edk2-devel@lists.01.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.24; helo=mga09.intel.com; envelope-from=dandan.bi@intel.com; receiver=edk2-devel@lists.01.org X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.51,242,1526367600"; d="scan'208";a="51022272" From: Dandan Bi To: edk2-devel@lists.01.org Date: Tue, 19 Jun 2018 15:24:01 +0800 Message-Id: <20180619072405.142872-6-dandan.bi@intel.com> X-Mailer: git-send-email 2.14.3.windows.1 In-Reply-To: <20180619072405.142872-1-dandan.bi@intel.com> References: <20180619072405.142872-1-dandan.bi@intel.com> Subject: [edk2] [patch 5/9] MdeModulePkg: Update performance library instances X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Star Zeng , Liming Gao MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Update the performance library instances in MdeModulePkg to implement the APIs used for new added Perf macros. Cc: Liming Gao Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Dandan Bi --- .../DxeCorePerformanceLib/DxeCorePerformanceLib.c | 664 +++++++++++++++++= ++-- .../DxeCorePerformanceLib.inf | 1 + .../DxeCorePerformanceLibInternal.h | 1 + .../Library/DxePerformanceLib/DxePerformanceLib.c | 68 +++ .../Library/PeiPerformanceLib/PeiPerformanceLib.c | 442 ++++++++++++-- .../SmmCorePerformanceLib/SmmCorePerformanceLib.c | 440 ++++++++++++-- .../Library/SmmPerformanceLib/SmmPerformanceLib.c | 68 +++ 7 files changed, 1550 insertions(+), 134 deletions(-) diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceL= ib.c b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c index 79820605184..68724ce9e1c 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c @@ -69,17 +69,19 @@ UINTN mCachePairCount =3D 0; UINT32 mLoadImageCount =3D 0; UINT32 mPerformanceLength =3D 0; UINT32 mMaxPerformanceLength =3D 0; UINT32 mBootRecordSize =3D 0; UINT32 mBootRecordMaxSize =3D 0; +UINT32 mCachedLength =3D 0; =20 BOOLEAN mFpdtBufferIsReported =3D FALSE; BOOLEAN mLackSpaceIsReported =3D FALSE; CHAR8 *mPlatformLanguage =3D NULL; UINT8 *mPerformancePointer =3D NULL; UINT8 *mBootRecordBuffer =3D NULL; BOOLEAN mLockInsertRecord =3D FALSE; +CHAR8 *mDevicePathString =3D NULL; =20 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevicePathToText =3D NULL; =20 // // Interfaces for PerformanceMeasurement Protocol. @@ -88,10 +90,64 @@ EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeas= urementInterface =3D { CreatePerformanceMeasurement, }; =20 PERFORMANCE_PROPERTY mPerformanceProperty; =20 +/** + 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 sav= e boot records\n")); + mLackSpaceIsReported =3D TRUE; + } + return EFI_OUT_OF_RESOURCES; + } else { + // + // Save boot record into BootPerformance table + // + FpdtRecordPtr->RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECOR= D_HEADER *)(mBootRecordBuffer + mBootRecordSize); + } + } else { + // + // Check if pre-allocated buffer is full + // + if (mPerformanceLength + RecordSize > mMaxPerformanceLength) { + mPerformancePointer =3D ReallocatePool ( + mPerformanceLength, + mPerformanceLength + RecordSize + FIRMWARE_R= ECORD_BUFFER, + mPerformancePointer + ); + if (mPerformancePointer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + mMaxPerformanceLength =3D mPerformanceLength + RecordSize + FIRMWARE= _RECORD_BUFFER; + } + // + // Covert buffer to FPDT Ptr Union type. + // + FpdtRecordPtr->RecordHeader =3D (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. =20 @param Token Pointer to a Null-terminated ASCII string =20 @@ -814,49 +870,13 @@ InsertFpdtMeasurement ( Identifier +=3D 1; } RecordInfo.ProgressID =3D (UINT16)Identifier; } =20 - if (mFpdtBufferIsReported) { - // - // Append Boot records to the boot performance table. - // - if (mBootRecordSize + RecordInfo.RecordSize > mBootRecordMaxSize) { - if (!mLackSpaceIsReported) { - DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to sav= e boot records\n")); - mLackSpaceIsReported =3D TRUE; - } - return EFI_OUT_OF_RESOURCES; - } else { - // - // Save boot record into BootPerformance table - // - FpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD= _HEADER *)(mBootRecordBuffer + mBootRecordSize); - mBootRecordSize +=3D RecordInfo.RecordSize; - mAcpiBootPerformanceTable->Header.Length +=3D RecordInfo.RecordSize; - } - } else { - // - // Check if pre-allocated buffer is full - // - if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength= ) { - mPerformancePointer =3D ReallocatePool ( - mPerformanceLength, - mPerformanceLength + RecordInfo.RecordSize += FIRMWARE_RECORD_BUFFER, - mPerformancePointer - ); - - if (mPerformancePointer =3D=3D NULL) { - return EFI_OUT_OF_RESOURCES; - } - mMaxPerformanceLength =3D mPerformanceLength + RecordInfo.RecordSize= + FIRMWARE_RECORD_BUFFER; - } - // - // Covert buffer to FPDT Ptr Union type. - // - FpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_H= EADER *)(mPerformancePointer + mPerformanceLength); - mPerformanceLength +=3D RecordInfo.RecordSize; + Status =3D GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; } =20 // // Get the TimeStamp. // @@ -942,11 +962,16 @@ InsertFpdtMeasurement ( // // Record is not supported in current DXE phase, return EFI_ABORTED // return EFI_UNSUPPORTED; } - + if (mFpdtBufferIsReported) { + mBootRecordSize +=3D FpdtRecordPtr.RecordHeader->Length; + mAcpiBootPerformanceTable->Header.Length +=3D FpdtRecordPtr.RecordHead= er->Length; + } else { + mPerformanceLength +=3D FpdtRecordPtr.RecordHeader->Length; + } return EFI_SUCCESS; } =20 /** Dumps all the PEI performance. @@ -1038,10 +1063,512 @@ ReportFpdtRecordBuffer ( // mFpdtBufferIsReported =3D TRUE; } } =20 +/** + Get a string description for device for the given controller handle. + If ComponentName2 GetControllerName is supported, the value is + included in the string,followed by device path, otherwise just device pa= th. + + @param Handle - Image handle + @param ControllerHandle - Controller handle. + @param Length - Pointer to record length to be updated + + @retval EFI_SUCCESS - Successfully got string description for device + @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor Devi= cePath were found. + +**/ +EFI_STATUS +GetDeviceInfoFromHandleAndUpdateLength ( + IN CONST VOID *Handle, + IN EFI_HANDLE ControllerHandle, + IN OUT UINT8 *Length + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol; + EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; + EFI_STATUS Status; + CHAR16 *StringPtr; + CHAR8 *AsciiStringPtr; + UINTN ControllerNameStringSize; + UINTN DevicePathStringSize; + + ControllerNameStringSize =3D 0; + + Status =3D gBS->HandleProtocol ( + (EFI_HANDLE) Handle, + &gEfiComponentName2ProtocolGuid, + (VOID **) &ComponentName2 + ); + + if (!EFI_ERROR(Status)) { + // + // Get the current platform language setting + // + if (mPlatformLanguage =3D=3D NULL) { + GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&mPlatformLanguage,= NULL); + } + + Status =3D ComponentName2->GetControllerName ( + ComponentName2, + ControllerHandle, + NULL, + mPlatformLanguage !=3D NULL ? mPlatformLang= uage:"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 =3D StrSize(StringPtr) / 2; + + // + // The + 1 is because we want to add a space between the ControllerNam= e and the device path + // + if ((ControllerNameStringSize + (*Length) + 1) > FPDT_MAX_PERF_RECORD_= SIZE) { + // + // Only copy enough to fill MAX_PERF_RECORD_SIZE worth of the record + // + ControllerNameStringSize =3D FPDT_MAX_PERF_RECORD_SIZE - (*Length) -= 1; + } + + mDevicePathString =3D AllocateZeroPool (ControllerNameStringSize + 1); + if (mDevicePathString =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UnicodeStrToAsciiStrS(StringPtr, mDevicePathString, ControllerNameStri= ngSize); + + // + // Add a space in the end of the ControllerName + // + AsciiStringPtr =3D mDevicePathString + ControllerNameStringSize - 1; + *AsciiStringPtr =3D 0x20; + AsciiStringPtr++; + *AsciiStringPtr =3D 0; + ControllerNameStringSize++; + + *Length +=3D (UINT8)ControllerNameStringSize; + } + + // + // This function returns the device path protocol from the handle specif= ied by Handle. If Handle is + // NULL or Handle does not contain a device path protocol, then NULL is = returned. + // + DevicePathProtocol =3D DevicePathFromHandle(ControllerHandle); + + if (DevicePathProtocol !=3D NULL) { + StringPtr =3D ConvertDevicePathToText (DevicePathProtocol, TRUE, FALSE= ); + if (StringPtr !=3D 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 =3D StrSize(StringPtr) / 2; + + if ((DevicePathStringSize + (*Length)) > FPDT_MAX_PERF_RECORD_SIZE) { + // + // Only copy enough to fill MAX_PERF_RECORD_SIZE worth of the reco= rd + // + DevicePathStringSize =3D FPDT_MAX_PERF_RECORD_SIZE - (*Length); + } + if (ControllerNameStringSize !=3D 0) { + mDevicePathString =3D ReallocatePool( + ControllerNameStringSize + 1, + ControllerNameStringSize + DevicePathStringSize = + 1, + mDevicePathString + ); + } else { + mDevicePathString =3D AllocateZeroPool(DevicePathStringSize + 1); + } + if (mDevicePathString =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + if (ControllerNameStringSize !=3D 0) { + AsciiStringPtr =3D mDevicePathString + ControllerNameStringSize - = 1; + } else { + AsciiStringPtr =3D mDevicePathString; + } + + UnicodeStrToAsciiStrS(StringPtr, AsciiStringPtr, DevicePathStringSiz= e); + *Length +=3D (UINT8)DevicePathStringSize; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; +} + +/** + Get the FPDT record size. + + @param Handle Pointer to environment specific context= used + to identify the component being measure= d. + @param String Pointer to a Null-terminated ASCII stri= ng + that identifies the component being mea= sured. + @param Address Pointer to a location in memory relevan= t to the measurement. + For DriverBinding Perf, it's the Contro= ller handle. + For other Perf, it's NULL. + @param PerfId Performance identifier. + @param RecordSize On return, pointer to the size of recor= d. + + @retval EFI_SUCCESS Get record size successfully. + @retval EFI_INVALID_PARAMETER Invalid Performance identifier. + +**/ +EFI_STATUS +GetFpdtRecordSize ( + IN CONST VOID *Handle, + IN CONST CHAR8 *String, + IN UINT64 Address, + IN UINT16 PerfId, + OUT UINT8 *RecordSize + ) +{ + UINTN StringSize; + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + if (PerfId =3D=3D MODULE_DB_SUPPORT_START_ID || PerfId =3D=3D MODULE_= DB_SUPPORT_END_ID) { + return EFI_UNSUPPORTED; + } + *RecordSize =3D (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + ST= RING_SIZE); + } else { + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_EVENT_RECORD); + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case MODULE_DB_START_ID: + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case MODULE_DB_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD); + GetDeviceInfoFromHandleAndUpdateLength(Handle, (EFI_HANDLE)(UINTN)Ad= dress, RecordSize); + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize =3D AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize =3D STRING_SIZE; + } + *RecordSize =3D (UINT8)(sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) = + StringSize); + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + if (String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize =3D AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize =3D STRING_SIZE; + } + *RecordSize =3D (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + = StringSize); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + + return EFI_SUCCESS; +} + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID. + @param Guid - Pointer to a GUID + @param String - Pointer to a string describing the measurement + @param Address - Pointer to a location in memory relevant to t= he measurement + @param PerfId - Performance identifier describing the type of= measurement + + @retval EFI_SUCCESS - Successfully created performance record + @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records + @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - N= ULL + pointer or invalid PerfId + +**/ +EFI_STATUS +InsertFpdtRecord ( + IN CONST VOID *CallerIdentifier, OPTIONAL + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 Address, OPTIONAL + IN UINT16 PerfId + ) +{ + EFI_GUID ModuleGuid; + CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LE= NGTH]; + FPDT_RECORD_PTR FpdtRecordPtr; + FPDT_RECORD_PTR CachedFpdtRecordPtr; + UINT64 TimeStamp; + UINT64 TimeStampCounter; + CONST CHAR8 *StringPtr; + UINT8 RecordSize; + UINTN DestMax; + UINTN StringLen; + EFI_STATUS Status; + + StringPtr =3D NULL; + RecordSize =3D 0; + ZeroMem (ModuleName, sizeof (ModuleName)); + + Status =3D GetFpdtRecordSize(CallerIdentifier, String, Address, PerfId, = &RecordSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the TimeStamp. + // + TimeStampCounter =3D GetPerformanceCounter (); + TimeStamp =3D GetTimeInNanoSecond (TimeStampCounter); + + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + // + // Get the ModuleGuid and ModuleName from the handle. + // + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, s= izeof (ModuleName), &ModuleGuid); + StringPtr =3D ModuleName; + if (PerfId =3D=3D MODULE_START_ID) { + if (mFpdtBufferIsReported) { + mCachedLength =3D mBootRecordSize; + } else { + mCachedLength =3D mPerformanceLength; + } + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidEvent->Header.Type =3D FPDT_GUID_EV= ENT_TYPE; + FpdtRecordPtr.GuidEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.GuidEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.GuidEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRe= cordPtr.GuidEvent->Guid)); + if (PerfId =3D=3D MODULE_END_ID && mCachedLength !=3D 0) { + if (mFpdtBufferIsReported) { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMA= NCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength); + } else { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMA= NCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength); + } + CopyMem (&CachedFpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof= (CachedFpdtRecordPtr.GuidEvent->Guid)); + mCachedLength =3D 0; + } + } + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, s= izeof (ModuleName), &ModuleGuid); + StringPtr =3D ModuleName; + if (PerfId =3D=3D MODULE_LOADIMAGE_START_ID) { + mLoadImageCount ++; + if (mFpdtBufferIsReported) { + mCachedLength =3D mBootRecordSize; + } else { + mCachedLength =3D mPerformanceLength; + } + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type =3D FPDT_GUID_QW= ORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.GuidQwordEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.GuidQwordEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidQwordEvent->Timestamp =3D TimeStamp; + FpdtRecordPtr.GuidQwordEvent->Qword =3D mLoadImageCo= unt; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (F= pdtRecordPtr.GuidQwordEvent->Guid)); + if (PerfId =3D=3D MODULE_LOADIMAGE_END_ID && mCachedLength !=3D 0) { + if (mFpdtBufferIsReported) { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMA= NCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength); + } else { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMA= NCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength); + } + CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, s= izeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid)); + mCachedLength =3D 0; + } + } + break; + + case MODULE_DB_START_ID: + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + if (Address =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, s= izeof (ModuleName), &ModuleGuid); + StringPtr =3D ModuleName; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type =3D FPDT_GUID_QW= ORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.GuidQwordEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.GuidQwordEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidQwordEvent->Timestamp =3D TimeStamp; + FpdtRecordPtr.GuidQwordEvent->Qword =3D Address; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (F= pdtRecordPtr.GuidQwordEvent->Guid)); + } + break; + + case MODULE_DB_END_ID: + if (Address =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, s= izeof (ModuleName), &ModuleGuid); + StringPtr =3D ModuleName; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordStringEvent->Header.Type =3D FPDT_GUID_QW= ORD_STRING_EVENT_TYPE; + FpdtRecordPtr.GuidQwordStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.GuidQwordStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.GuidQwordStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidQwordStringEvent->Timestamp =3D TimeStamp; + FpdtRecordPtr.GuidQwordStringEvent->Qword =3D Address; + CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, siz= eof (FpdtRecordPtr.GuidQwordStringEvent->Guid)); + DestMax =3D (RecordSize - sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECOR= D)) / sizeof (CHAR8); + if (mDevicePathString !=3D NULL) { + AsciiStrCpyS (FpdtRecordPtr.GuidQwordStringEvent->String, DestMax,= mDevicePathString); + FreePool (mDevicePathString); + mDevicePathString =3D NULL; + } + } + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (CallerIdentifier =3D=3D NULL || Guid =3D=3DNULL || String =3D=3D N= ULL) { + return EFI_INVALID_PARAMETER; + } + // + // Cache the event guid in string event record when PcdEdkiiFpdtString= RecordEnableOnly =3D=3D TRUE + // + CopyGuid (&ModuleGuid, Guid); + StringPtr =3D String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type =3D FPDT_DUAL_GU= ID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DualGuidStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.DualGuidStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DualGuidStringEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier= , sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1)); + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (Fp= dtRecordPtr.DualGuidStringEvent->Guid2)); + DestMax =3D (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD= )) / sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, S= tringPtr, StringLen); + } + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + if (CallerIdentifier =3D=3D NULL || String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + CopyGuid (&ModuleGuid, (EFI_GUID *) CallerIdentifier); + StringPtr =3D String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type =3D FPDT_DYNAMIC= _STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, = sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + DestMax =3D (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD))= / sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, St= ringPtr, StringLen); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type =3D FPDT_DYNAMIC_S= TRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision =3D FPDT_RECORD_RE= VISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp =3D TimeStamp; + DestMax =3D (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) /= sizeof (CHAR8); + if (StringPtr !=3D NULL && AsciiStrLen (StringPtr) =3D=3D 0) { + StringPtr =3D "unknown name"; + } + if (StringPtr !=3D NULL) { + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + } + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof = (FpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, Stri= ngPtr, StringLen); + + if ((PerfId =3D=3D MODULE_LOADIMAGE_END_ID) || (PerfId =3D=3D MODULE_E= ND_ID)) { + if (mCachedLength !=3D 0) { + if (mFpdtBufferIsReported) { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMA= NCE_RECORD_HEADER *)(mBootRecordBuffer + mCachedLength); + } else { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMA= NCE_RECORD_HEADER *)(mPerformancePointer + mCachedLength); + } + CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGui= d, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, Des= tMax, StringPtr, StringLen); + mCachedLength =3D 0; + } + } + } + if (mFpdtBufferIsReported) { + mBootRecordSize +=3D FpdtRecordPtr.RecordHeader->Length; + mAcpiBootPerformanceTable->Header.Length +=3D FpdtRecordPtr.RecordHead= er->Length; + } else { + mPerformanceLength +=3D FpdtRecordPtr.RecordHeader->Length; + } + return EFI_SUCCESS; +} + /** The constructor function initializes Performance infrastructure for DXE = phase. =20 The constructor function publishes Performance and PerformanceEx protoco= l, allocates memory to log DXE performance and merges PEI performance data to DXE performance log. @@ -1162,10 +1689,12 @@ CreatePerformanceMeasurement ( =20 if (Attribute =3D=3D PerfStartEntry) { Status =3D InsertFpdtMeasurement (TRUE, CallerIdentifier, String, Stri= ng, TimeStamp, Identifier); } else if (Attribute =3D=3D PerfEndEntry) { Status =3D InsertFpdtMeasurement (FALSE, CallerIdentifier, String, Str= ing, TimeStamp, Identifier); + } else if ( Attribute =3D=3D PerfEntry) { + Status =3D InsertFpdtRecord (CallerIdentifier, Guid, String, Address, = (UINT16) Identifier); } mLockInsertRecord =3D FALSE; =20 return Status; } @@ -1470,5 +1999,60 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMA= NCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) !=3D 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 t= he measurement + @param Identifier - Performance identifier describing the type of= measurement + + @retval RETURN_SUCCESS - Successfully created performance reco= rd + @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, Gu= id, String, 0, Address, Identifier, PerfEntry); +} + +/** + Check whether the specified performance measurement can be logged. + + This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASURE= MENT_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(PcdPerformanceLibraryPr= opertyMask) & Type) =3D=3D 0) { + return TRUE; + } + return FALSE; +} diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceL= ib.inf b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.i= nf index 68cd76da5b3..3e77f9cd57a 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf @@ -59,10 +59,11 @@ DebugLib UefiLib ReportStatusCodeLib DxeServicesLib PeCoffGetEntryPointLib + DevicePathLib =20 [Protocols] gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES =20 =20 diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceL= ibInternal.h b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanc= eLibInternal.h index f9800e34941..a96f4081503 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInter= nal.h +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInter= nal.h @@ -40,10 +40,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITH= ER EXPRESS OR IMPLIED. #include #include #include #include #include +#include #include #include #include #include #include diff --git a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c b/M= deModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c index 9ed50d22b8d..664e8261af9 100644 --- a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c +++ b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c @@ -376,5 +376,73 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMA= NCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) !=3D 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 t= he measurement + @param Identifier - Performance identifier describing the type of= measurement + + @retval RETURN_SUCCESS - Successfully created performance reco= rd + @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 =3D GetPerformanceMeasurementProtocol (); + if (EFI_ERROR (Status)) { + return RETURN_OUT_OF_RESOURCES; + } + + if (mPerformanceMeasurement !=3D NULL) { + Status =3D mPerformanceMeasurement->CreatePerformanceMeasurement (Call= erIdentifier, 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_MEASURE= MENT_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(PcdPerformanceLibraryPr= opertyMask) & Type) =3D=3D 0) { + return TRUE; + } + return FALSE; +} diff --git a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c b/M= deModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c index f770a35a995..d7b652c5771 100644 --- a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c +++ b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c @@ -31,11 +31,88 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITH= ER EXPRESS OR IMPLIED. #include #include #include =20 #define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * si= zeof (CHAR8)) -#define MAX_RECORD_SIZE (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)= + STRING_SIZE) +#define PEI_MAX_RECORD_SIZE (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECOR= D) + 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 allocat= ed memory. + @param PeiPerformanceLogHeader Pointer to the header of the PEI Perfo= rmance records in the GUID Hob. + + @retval EFI_SUCCESS Successfully get the pointer to the FP= DT 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 =3D (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLog= Entries16) !=3D 0 ? + PcdGet16 (PcdMaxPeiPerformanceLogEn= tries16) : + PcdGet8 (PcdMaxPeiPerformanceLogEnt= ries)); + + // + // Create GUID HOB Data. + // + GuidHob =3D GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid); + PeiFirmwarePerformance =3D NULL; + while (GuidHob !=3D NULL) { + // + // PEI Performance HOB was found, then return the existing one. + // + PeiFirmwarePerformance =3D (UINT8*)GET_GUID_HOB_DATA (GuidHob); + *PeiPerformanceLogHeader =3D (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePe= rformance; + if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeade= r)->SizeOfAllEntries + RecordSize > PeiPerformanceLogEntries * PEI_MAX_RECO= RD_SIZE) { + (*PeiPerformanceLogHeader)->HobIsFull =3D TRUE; + } + if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeade= r)->SizeOfAllEntries + RecordSize <=3D PeiPerformanceLogEntries * PEI_MAX_R= ECORD_SIZE) { + FpdtRecordPtr->RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECOR= D_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + (*= PeiPerformanceLogHeader)->SizeOfAllEntries); + break; + } + // + // Previous HOB is used, then find next one. + // + GuidHob =3D GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid= , GET_NEXT_HOB (GuidHob)); + } + + if (GuidHob =3D=3D NULL) { + // + // PEI Performance HOB was not found, then build one. + // + PeiPerformanceSize =3D sizeof (FPDT_PEI_EXT_PERF_HEADER) + + PEI_MAX_RECORD_SIZE * PeiPerformanceLogEntri= es; + PeiFirmwarePerformance =3D (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedF= irmwarePerformanceGuid, PeiPerformanceSize); + if (PeiFirmwarePerformance !=3D NULL) { + ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize); + (*PeiPerformanceLogHeader) =3D (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwa= rePerformance; + FpdtRecordPtr->RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECOR= D_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER)); + } + } + + if (PeiFirmwarePerformance =3D=3D NULL) { + // + // there is no enough resource to store performance data + // + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} =20 /** Check whether the Token is a known one which is uesed by core. =20 @param Token Pointer to a Null-terminated ASCII string @@ -240,23 +317,19 @@ InsertPeiFpdtMeasurement ( IN CONST CHAR8 *Module, OPTIONAL IN UINT64 Ticker, IN UINT32 Identifier ) { - EFI_HOB_GUID_TYPE *GuidHob; - UINTN PeiPerformanceSize; - UINT8 *PeiFirmwarePerformance; - FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; FPDT_RECORD_PTR FpdtRecordPtr; FPDT_BASIC_RECORD_INFO RecordInfo; CONST VOID *ModuleGuid; UINTN DestMax; UINTN StrLength; CONST CHAR8 *StringPtr; EFI_STATUS Status; - UINT16 PeiPerformanceLogEntries; UINT64 TimeStamp; + FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; =20 StringPtr =3D NULL; FpdtRecordPtr.RecordHeader =3D NULL; PeiPerformanceLogHeader =3D NULL; =20 @@ -286,60 +359,13 @@ InsertPeiFpdtMeasurement ( Identifier +=3D 1; } RecordInfo.ProgressID =3D (UINT16)Identifier; } =20 - // - // Get the number of PeiPerformanceLogEntries form PCD. - // - PeiPerformanceLogEntries =3D (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLog= Entries16) !=3D 0 ? - PcdGet16 (PcdMaxPeiPerformanceLogEn= tries16) : - PcdGet8 (PcdMaxPeiPerformanceLogEnt= ries)); - - // - // Create GUID HOB Data. - // - GuidHob =3D GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid); - PeiFirmwarePerformance =3D NULL; - while (GuidHob !=3D NULL) { - // - // PEI Performance HOB was found, then return the existing one. - // - PeiFirmwarePerformance =3D (UINT8*)GET_GUID_HOB_DATA (GuidHob); - PeiPerformanceLogHeader =3D (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePer= formance; - if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->Si= zeOfAllEntries + RecordInfo.RecordSize > PeiPerformanceLogEntries * MAX_REC= ORD_SIZE) { - PeiPerformanceLogHeader->HobIsFull =3D TRUE; - } - if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->Si= zeOfAllEntries + RecordInfo.RecordSize <=3D PeiPerformanceLogEntries * MAX_= RECORD_SIZE) { - FpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD= _HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + Pei= PerformanceLogHeader->SizeOfAllEntries); - break; - } - // - // Previous HOB is used, then find next one. - // - GuidHob =3D GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid= , GET_NEXT_HOB (GuidHob)); - } - - if (GuidHob =3D=3D NULL) { - // - // PEI Performance HOB was not found, then build one. - // - PeiPerformanceSize =3D sizeof (FPDT_PEI_EXT_PERF_HEADER) + - MAX_RECORD_SIZE * PeiPerformanceLogEntries; - PeiFirmwarePerformance =3D (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedF= irmwarePerformanceGuid, PeiPerformanceSize); - if (PeiFirmwarePerformance !=3D NULL) { - ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize); - } - PeiPerformanceLogHeader =3D (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePer= formance; - FpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_H= EADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER)); - } - - if (PeiFirmwarePerformance =3D=3D NULL) { - // - // there is no enough resource to store performance data - // - return EFI_OUT_OF_RESOURCES; + Status =3D GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr, &Pei= PerformanceLogHeader); + if (EFI_ERROR (Status)) { + return Status; } =20 // // Get the TimeStamp. // @@ -690,5 +716,309 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMA= NCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) !=3D 0); } + +/** + Get the FPDT record size. + + @param String Pointer to a Null-terminated ASCII stri= ng + that identifies the component being mea= sured. + @param PerfId Performance identifier. + @param RecordSize On return, pointer to the size of recor= d. + + @retval EFI_SUCCESS Get record size successfully. + @retval EFI_INVALID_PARAMETER Invalid Performance identifier. + +**/ +EFI_STATUS +GetFpdtRecordSize ( + IN CONST CHAR8 *String, + IN UINT16 PerfId, + OUT UINT8 *RecordSize + ) +{ + UINTN StringSize; + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + *RecordSize =3D sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZ= E; + } else { + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_EVENT_RECORD); + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize =3D AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize =3D STRING_SIZE; + } + *RecordSize =3D (UINT8) (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)= + StringSize); + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + if (String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize =3D AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize =3D STRING_SIZE; + } + *RecordSize =3D (UINT8) (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) += StringSize); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + return EFI_SUCCESS; +} + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID + @param Guid - Pointer to a GUID + @param String - Pointer to a string describing the measurement + @param Address - Pointer to a location in memory relevant to t= he measurement + @param PerfId - Performance identifier describing the type of= measurement + + @retval EFI_SUCCESS - Successfully created performance record + @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records + @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - N= ULL + pointer or invalid PerfId + +**/ +EFI_STATUS +CreateFpdtRecord ( + IN CONST VOID *CallerIdentifier, OPTIONAL + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 Address, OPTIONAL + IN UINT16 PerfId + ) +{ + FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; + FPDT_RECORD_PTR FpdtRecordPtr; + CONST CHAR8 *StringPtr; + EFI_STATUS Status; + UINT64 TimeStamp; + UINT64 TimeStampCounter; + UINT8 RecordSize; + UINTN DestMax; + UINTN StringLen; + + StringPtr =3D NULL; + RecordSize =3D 0; + + Status =3D GetFpdtRecordSize(String, PerfId, &RecordSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr, &PeiPerformance= LogHeader); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the TimeStamp. + // + TimeStampCounter =3D GetPerformanceCounter (); + TimeStamp =3D GetTimeInNanoSecond (TimeStampCounter); + + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + if (CallerIdentifier =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr =3D PEIM_TOK; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidEvent->Header.Type =3D FPDT_GUID_EVENT_TYPE; + FpdtRecordPtr.GuidEvent->Header.Length =3D RecordSize;; + FpdtRecordPtr.GuidEvent->Header.Revision =3D FPDT_RECORD_REVISION_= 1; + FpdtRecordPtr.GuidEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.GuidEvent->Guid, CallerIdentifier, sizeof (E= FI_GUID)); + PeiPerformanceLogHeader->SizeOfAllEntries +=3D RecordSize; + } + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + if (CallerIdentifier =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr =3D LOAD_IMAGE_TOK; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type =3D FPDT_GUID_QWORD_EV= ENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length =3D RecordSize;; + FpdtRecordPtr.GuidQwordEvent->Header.Revision =3D FPDT_RECORD_REVISI= ON_1; + FpdtRecordPtr.GuidQwordEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidQwordEvent->Timestamp =3D TimeStamp; + if (PerfId =3D=3D MODULE_LOADIMAGE_START_ID) { + PeiPerformanceLogHeader->LoadImageCount++; + } + FpdtRecordPtr.GuidQwordEvent->Qword =3D PeiPerformanceLogH= eader->LoadImageCount; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, CallerIdentifier, size= of (EFI_GUID)); + PeiPerformanceLogHeader->SizeOfAllEntries +=3D RecordSize; + } + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (CallerIdentifier =3D=3D NULL || Guid =3D=3DNULL || String =3D=3D N= ULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr =3D String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type =3D FPDT_DUAL_GU= ID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DualGuidStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.DualGuidStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DualGuidStringEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier= , sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1)); + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (Fp= dtRecordPtr.DualGuidStringEvent->Guid2)); + DestMax =3D (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD= )) / sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, S= tringPtr, StringLen); + PeiPerformanceLogHeader->SizeOfAllEntries +=3D RecordSize; + } + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + if (CallerIdentifier =3D=3D NULL || String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr =3D String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type =3D FPDT_DYNAMIC= _STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, = sizeof (EFI_GUID)); + DestMax =3D (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD))= / sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, St= ringPtr, StringLen); + PeiPerformanceLogHeader->SizeOfAllEntries +=3D RecordSize; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type =3D FPDT_DYNAMIC_S= TRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision =3D FPDT_RECORD_RE= VISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp =3D TimeStamp; + if (Guid !=3D NULL) { + // + // Cache the event guid in string event record. + // + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (EFI_= GUID)); + } else { + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, = sizeof (EFI_GUID)); + } + DestMax =3D (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) /= sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, Stri= ngPtr, StringLen); + PeiPerformanceLogHeader->SizeOfAllEntries +=3D RecordSize; + } + + return EFI_SUCCESS; +} + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID + @param Guid - Pointer to a GUID + @param String - Pointer to a string describing the measurement + @param Address - Pointer to a location in memory relevant to t= he measurement + @param Identifier - Performance identifier describing the type of= measurement + + @retval RETURN_SUCCESS - Successfully created performance reco= rd + @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records + @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function = - NULL + pointer or invalid PerfId + +**/ +RETURN_STATUS +EFIAPI +LogPerformanceMeasurement ( + IN CONST VOID *CallerIdentifier, + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 Address, OPTIONAL + IN UINT32 Identifier + ) +{ + return (RETURN_STATUS)CreateFpdtRecord (CallerIdentifier, Guid, String, = Address, (UINT16)Identifier); +} + +/** + Check whether the specified performance measurement can be logged. + + This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASURE= MENT_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(PcdPerformanceLibraryPr= opertyMask) & Type) =3D=3D 0) { + return TRUE; + } + return FALSE; +} diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceL= ib.c b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c index e630773562f..efbde88220b 100644 --- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c +++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c @@ -45,23 +45,83 @@ typedef struct { HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT]; UINTN mCachePairCount =3D 0; =20 UINT32 mPerformanceLength =3D 0; UINT32 mMaxPerformanceLength =3D 0; +UINT32 mLoadImageCount =3D 0; BOOLEAN mFpdtDataIsReported =3D FALSE; BOOLEAN mLackSpaceIsReport =3D FALSE; CHAR8 *mPlatformLanguage =3D NULL; SPIN_LOCK mSmmFpdtLock; PERFORMANCE_PROPERTY mPerformanceProperty; +UINT32 mCachedLength =3D 0; =20 // // Interfaces for SMM PerformanceMeasurement Protocol. // EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = =3D { CreatePerformanceMeasurement, }; =20 +/** + 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 re= ported. + // + if (mPerformanceLength + RecordSize > mMaxPerformanceLength) { + if (!mLackSpaceIsReport) { + DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to sav= e boot records\n")); + mLackSpaceIsReport =3D TRUE; + } + return EFI_OUT_OF_RESOURCES; + } else { + // + // Covert buffer to FPDT Ptr Union type. + // + FpdtRecordPtr->RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECOR= D_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->He= ader.Length); + } + } else { + // + // Check if pre-allocated buffer is full + // + if (mPerformanceLength + RecordSize > mMaxPerformanceLength) { + mSmmBootPerformanceTable =3D ReallocatePool ( + mPerformanceLength, + mPerformanceLength + sizeof (SMM_BOOT_P= ERFORMANCE_TABLE) + RecordSize + FIRMWARE_RECORD_BUFFER, + mSmmBootPerformanceTable + ); + + if (mSmmBootPerformanceTable =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + mSmmBootPerformanceTable->Header.Length =3D sizeof (SMM_BOOT_PERFORM= ANCE_TABLE) + mPerformanceLength; + mMaxPerformanceLength =3D mPerformanceLength + sizeof (SMM_BOOT_PERF= ORMANCE_TABLE) + RecordSize + FIRMWARE_RECORD_BUFFER; + } + // + // Covert buffer to FPDT Ptr Union type. + // + FpdtRecordPtr->RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_= HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Head= er.Length); + } + FpdtRecordPtr->RecordHeader->Length =3D 0; + return EFI_SUCCESS; +} + + /** Check whether the Token is a known one which is uesed by core. =20 @param Token Pointer to a Null-terminated ASCII string =20 @@ -506,49 +566,14 @@ InsertFpdtMeasurement ( Identifier +=3D 1; } RecordInfo.ProgressID =3D (UINT16)Identifier; } =20 - if (mFpdtDataIsReported) { - // - // Append Boot records after Smm boot performance records have been re= ported. - // - if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength= ) { - if (!mLackSpaceIsReport) { - DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to sav= e boot records\n")); - mLackSpaceIsReport =3D TRUE; - } - return EFI_OUT_OF_RESOURCES; - } else { - // - // Covert buffer to FPDT Ptr Union type. - // - FpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD= _HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Hea= der.Length); - } - } else { - // - // Check if pre-allocated buffer is full - // - if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength= ) { - mSmmBootPerformanceTable =3D ReallocatePool ( - mPerformanceLength, - mPerformanceLength + sizeof (SMM_BOOT_P= ERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER, - mSmmBootPerformanceTable - ); - - if (mSmmBootPerformanceTable =3D=3D NULL) { - return EFI_OUT_OF_RESOURCES; - } - mSmmBootPerformanceTable->Header.Length =3D sizeof (SMM_BOOT_PERFORM= ANCE_TABLE) + mPerformanceLength; - mMaxPerformanceLength =3D mPerformanceLength + sizeof (SMM_BOOT_PERF= ORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER; - } - // - // Covert buffer to FPDT Ptr Union type. - // - FpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_H= EADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Heade= r.Length); + Status =3D GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; } - FpdtRecordPtr.RecordHeader->Length =3D 0; =20 // // Get the TimeStamp. // if (Ticker =3D=3D 0) { @@ -630,10 +655,289 @@ InsertFpdtMeasurement ( mSmmBootPerformanceTable->Header.Length +=3D FpdtRecordPtr.RecordHeader-= >Length; =20 return EFI_SUCCESS; } =20 +/** + Get the FPDT record size. + + @param String Pointer to a Null-terminated ASCII stri= ng + that identifies the component being mea= sured. + @param PerfId Performance identifier. + @param RecordSize On return, pointer to the size of recor= d. + + @retval EFI_SUCCESS Get record size successfully. + @retval EFI_INVALID_PARAMETER Invalid Performance identifier. + +**/ +EFI_STATUS +GetFpdtRecordSize ( + IN CONST CHAR8 *String, + IN UINT16 PerfId, + OUT UINT8 *RecordSize + ) +{ + UINTN StringSize; + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + *RecordSize =3D (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + ST= RING_SIZE); + } else { + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_EVENT_RECORD); + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + *RecordSize =3D sizeof (FPDT_GUID_QWORD_EVENT_RECORD); + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize =3D AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize =3D STRING_SIZE; + } + *RecordSize =3D (UINT8) (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)= + StringSize); + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + if (String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + StringSize =3D AsciiStrSize (String); + if (StringSize > STRING_SIZE) { + StringSize =3D STRING_SIZE; + } + *RecordSize =3D (UINT8) (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) += StringSize); + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + return EFI_SUCCESS; +} + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID + @param Guid - Pointer to a GUID + @param String - Pointer to a string describing the measurement + @param Address - Pointer to a location in memory relevant to t= he measurement + @param PerfId - Performance identifier describing the type of= measurement + + @retval EFI_SUCCESS - Successfully created performance record + @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records + @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - N= ULL + pointer or invalid PerfId + +**/ +EFI_STATUS +InsertFpdtRecord ( + IN CONST VOID *CallerIdentifier, OPTIONAL + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 Address, OPTIONAL + IN UINT16 PerfId + ) +{ + EFI_STATUS Status; + EFI_GUID ModuleGuid; + CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LE= NGTH]; + FPDT_RECORD_PTR FpdtRecordPtr; + FPDT_RECORD_PTR CachedFpdtRecordPtr; + UINT64 TimeStamp; + UINT64 TimeStampCounter; + CONST CHAR8 *StringPtr; + UINT8 RecordSize; + UINTN DestMax; + UINTN StringLen; + + StringPtr =3D NULL; + RecordSize =3D 0; + ZeroMem (ModuleName, sizeof (ModuleName)); + + Status =3D GetFpdtRecordSize(String, PerfId, &RecordSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the TimeStamp. + // + TimeStampCounter =3D GetPerformanceCounter (); + TimeStamp =3D GetTimeInNanoSecond (TimeStampCounter); + + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + // + // Get the ModuleGuid from the handle. + // + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, s= izeof (ModuleName), &ModuleGuid); + StringPtr =3D ModuleName; + if (PerfId =3D=3D MODULE_START_ID) { + mCachedLength =3D mSmmBootPerformanceTable->Header.Length; + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidEvent->Header.Type =3D FPDT_GUID_EV= ENT_TYPE; + FpdtRecordPtr.GuidEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.GuidEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.GuidEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRe= cordPtr.GuidEvent->Guid)); + if (PerfId =3D=3D MODULE_END_ID && mCachedLength !=3D 0) { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANC= E_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength); + CopyMem (&CachedFpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof= (CachedFpdtRecordPtr.GuidEvent->Guid)); + mCachedLength =3D 0; + } + } + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, s= izeof (ModuleName), &ModuleGuid); + StringPtr =3D ModuleName; + if (PerfId =3D=3D MODULE_LOADIMAGE_START_ID) { + mLoadImageCount++; + mCachedLength =3D mSmmBootPerformanceTable->Header.Length; + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.GuidQwordEvent->Header.Type =3D FPDT_GUID_QW= ORD_EVENT_TYPE; + FpdtRecordPtr.GuidQwordEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.GuidQwordEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.GuidQwordEvent->ProgressID =3D PerfId; + FpdtRecordPtr.GuidQwordEvent->Timestamp =3D TimeStamp; + FpdtRecordPtr.GuidQwordEvent->Qword =3D mLoadImageCo= unt; + CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (F= pdtRecordPtr.GuidQwordEvent->Guid)); + if (PerfId =3D=3D MODULE_LOADIMAGE_END_ID && mCachedLength !=3D 0) { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANC= E_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength); + CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, s= izeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid)); + mCachedLength =3D 0; + } + } + break; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (CallerIdentifier =3D=3D NULL || Guid =3D=3DNULL || String =3D=3D N= ULL) { + return EFI_INVALID_PARAMETER; + } + // + // Cache the event guid in string event record when PcdEdkiiFpdtString= RecordEnableOnly =3D=3D TRUE + // + CopyGuid (&ModuleGuid, Guid); + StringPtr =3D String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type =3D FPDT_DUAL_GU= ID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DualGuidStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.DualGuidStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DualGuidStringEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier= , sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1)); + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (Fp= dtRecordPtr.DualGuidStringEvent->Guid2)); + DestMax =3D (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD= )) / sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, S= tringPtr, StringLen); + } + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + if (CallerIdentifier =3D=3D NULL || String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + CopyGuid (&ModuleGuid, (EFI_GUID *) CallerIdentifier); + StringPtr =3D String; + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type =3D FPDT_DYNAMIC= _STRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision =3D FPDT_RECORD_= REVISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp =3D TimeStamp; + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, = sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + DestMax =3D (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD))= / sizeof (CHAR8); + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, St= ringPtr, StringLen); + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DynamicStringEvent->Header.Type =3D FPDT_DYNAMIC_S= TRING_EVENT_TYPE; + FpdtRecordPtr.DynamicStringEvent->Header.Length =3D RecordSize; + FpdtRecordPtr.DynamicStringEvent->Header.Revision =3D FPDT_RECORD_RE= VISION_1; + FpdtRecordPtr.DynamicStringEvent->ProgressID =3D PerfId; + FpdtRecordPtr.DynamicStringEvent->Timestamp =3D TimeStamp; + DestMax =3D (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) /= sizeof (CHAR8); + if (StringPtr !=3D NULL && AsciiStrLen (StringPtr) =3D=3D 0) { + StringPtr =3D "unknown name"; + } + if (StringPtr !=3D NULL) { + StringLen =3D AsciiStrLen (StringPtr); + if (StringLen >=3D DestMax) { + StringLen =3D DestMax -1; + } + } + + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof = (FpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, Stri= ngPtr, StringLen); + + if ((PerfId =3D=3D MODULE_LOADIMAGE_END_ID) || (PerfId =3D=3D MODULE_E= ND_ID)) { + if (mCachedLength !=3D 0) { + CachedFpdtRecordPtr.RecordHeader =3D (EFI_ACPI_5_0_FPDT_PERFORMANC= E_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength); + CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGui= d, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid)); + AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, Des= tMax, StringPtr, StringLen); + mCachedLength =3D 0; + } + } + } + + // + // Update the cached FPDT record buffer. + // + mPerformanceLength +=3D FpdtRecordPtr.RecordHeader->Length; + mSmmBootPerformanceTable->Header.Length +=3D FpdtRecordPtr.RecordHeader-= >Length; + + return EFI_SUCCESS; +} + /** SmmReadyToBoot protocol notification event handler. =20 @param Protocol Points to the protocol's unique identifier @param Interface Points to the interface instance @@ -814,15 +1118,19 @@ CreatePerformanceMeasurement( IN PERF_MEASUREMENT_ATTRIBUTE Attribute ) { EFI_STATUS Status; =20 + Status =3D EFI_SUCCESS; + AcquireSpinLock (&mSmmFpdtLock); if (Attribute =3D=3D PerfStartEntry) { Status =3D InsertFpdtMeasurement (TRUE, CallerIdentifier, String, Stri= ng, TimeStamp, Identifier); } else if (Attribute =3D=3D PerfEndEntry) { Status =3D InsertFpdtMeasurement (FALSE, CallerIdentifier, String, Str= ing, TimeStamp, Identifier); + } else if (Attribute =3D=3D PerfEntry) { + Status =3D InsertFpdtRecord (CallerIdentifier, Guid, String, Address, = (UINT16) Identifier); } ReleaseSpinLock (&mSmmFpdtLock); return Status; } =20 @@ -1125,5 +1433,61 @@ PerformanceMeasurementEnabled ( VOID ) { return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMA= NCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) !=3D 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 t= he measurement + @param Identifier - Performance identifier describing the type of= measurement + + @retval RETURN_SUCCESS - Successfully created performance reco= rd + @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, Gu= id, String, 0, Address, Identifier, PerfEntry); +} + +/** + Check whether the specified performance measurement can be logged. + + This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASURE= MENT_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(PcdPerformanceLibraryPr= opertyMask) & Type) =3D=3D 0) { + return TRUE; + } + return FALSE; +} + diff --git a/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c b/M= deModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c index fd820c0e49c..830037befa6 100644 --- a/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c +++ b/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c @@ -395,5 +395,73 @@ PerformanceMeasurementEnabled ( VOID ) { return mPerformanceMeasurementEnabled; } + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID + @param Guid - Pointer to a GUID + @param String - Pointer to a string describing the measurement + @param Address - Pointer to a location in memory relevant to t= he measurement + @param Identifier - Performance identifier describing the type of= measurement + + @retval RETURN_SUCCESS - Successfully created performance reco= rd + @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 =3D GetPerformanceMeasurementProtocol (); + if (EFI_ERROR (Status)) { + return RETURN_OUT_OF_RESOURCES; + } + + if (mPerformanceMeasurement !=3D NULL) { + Status =3D mPerformanceMeasurement->CreatePerformanceMeasurement (Call= erIdentifier, 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_MEASURE= MENT_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(PcdPerformanceLibraryPr= opertyMask) & Type) =3D=3D 0) { + return TRUE; + } + return FALSE; +} --=20 2.14.3.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel