diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c | 1822 |
1 files changed, 1822 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c new file mode 100644 index 00000000..3ae5420a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c @@ -0,0 +1,1822 @@ +/** @file + Performance library instance mainly used by DxeCore. + + This library provides the performance measurement interfaces and initializes performance + logging for DXE phase. It first initializes its private global data structure for + performance logging and saves the performance GUIDed HOB passed from PEI phase. + It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol, + which are consumed by DxePerformanceLib to logging performance data in DXE phase. + + This library is mainly used by DxeCore to start performance logging to ensure that + Performance Protocol is installed at the very beginning of DXE phase. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "DxeCorePerformanceLibInternal.h" + +// +// Data for FPDT performance records. +// +#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE)) +#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8)) +#define FIRMWARE_RECORD_BUFFER 0x10000 +#define CACHE_HANDLE_GUID_COUNT 0x800 + +BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL; +BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = { + { + EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE, + sizeof (BOOT_PERFORMANCE_TABLE) + }, + { + { + EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type + sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length + EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision + }, + 0, // Reserved + // + // These values will be updated at runtime. + // + 0, // ResetEnd + 0, // OsLoaderLoadImageStart + 0, // OsLoaderStartImageStart + 0, // ExitBootServicesEntry + 0 // ExitBootServicesExit + } +}; + +typedef struct { + EFI_HANDLE Handle; + CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH]; + EFI_GUID ModuleGuid; +} HANDLE_GUID_MAP; + +HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT]; +UINTN mCachePairCount = 0; + +UINT32 mLoadImageCount = 0; +UINT32 mPerformanceLength = 0; +UINT32 mMaxPerformanceLength = 0; +UINT32 mBootRecordSize = 0; +UINT32 mBootRecordMaxSize = 0; +UINT32 mCachedLength = 0; + +BOOLEAN mFpdtBufferIsReported = FALSE; +BOOLEAN mLackSpaceIsReported = FALSE; +CHAR8 *mPlatformLanguage = NULL; +UINT8 *mPerformancePointer = NULL; +UINT8 *mBootRecordBuffer = NULL; +BOOLEAN mLockInsertRecord = FALSE; +CHAR8 *mDevicePathString = NULL; + +EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevicePathToText = NULL; + +// +// Interfaces for PerformanceMeasurement Protocol. +// +EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = { + CreatePerformanceMeasurement, + }; + +PERFORMANCE_PROPERTY mPerformanceProperty; + +/** + Return the pointer to the FPDT record in the allocated memory. + + @param RecordSize The size of FPDT record. + @param FpdtRecordPtr Pointer the FPDT record in the allocated memory. + + @retval EFI_SUCCESS Successfully get the pointer to the FPDT record. + @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records. +**/ +EFI_STATUS +GetFpdtRecordPtr ( + IN UINT8 RecordSize, + IN OUT FPDT_RECORD_PTR *FpdtRecordPtr +) +{ + if (mFpdtBufferIsReported) { + // + // Append Boot records to the boot performance table. + // + if (mBootRecordSize + RecordSize > mBootRecordMaxSize) { + if (!mLackSpaceIsReported) { + DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n")); + mLackSpaceIsReported = TRUE; + } + return EFI_OUT_OF_RESOURCES; + } else { + // + // Save boot record into BootPerformance table + // + FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mBootRecordSize); + } + } else { + // + // Check if pre-allocated buffer is full + // + if (mPerformanceLength + RecordSize > mMaxPerformanceLength) { + mPerformancePointer = ReallocatePool ( + mPerformanceLength, + mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER, + mPerformancePointer + ); + if (mPerformancePointer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER; + } + // + // Covert buffer to FPDT Ptr Union type. + // + FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength); + } + return EFI_SUCCESS; +} + +/** +Check whether the Token is a known one which is uesed by core. + +@param Token Pointer to a Null-terminated ASCII string + +@retval TRUE Is a known one used by core. +@retval FALSE Not a known one. + +**/ +BOOLEAN +IsKnownTokens ( + IN CONST CHAR8 *Token + ) +{ + if (Token == NULL) { + return FALSE; + } + + if (AsciiStrCmp (Token, SEC_TOK) == 0 || + AsciiStrCmp (Token, PEI_TOK) == 0 || + AsciiStrCmp (Token, DXE_TOK) == 0 || + AsciiStrCmp (Token, BDS_TOK) == 0 || + AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 || + AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 || + AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 || + AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 || + AsciiStrCmp (Token, START_IMAGE_TOK) == 0 || + AsciiStrCmp (Token, PEIM_TOK) == 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** +Check whether the ID is a known one which map to the known Token. + +@param Identifier 32-bit identifier. + +@retval TRUE Is a known one used by core. +@retval FALSE Not a known one. + +**/ +BOOLEAN +IsKnownID ( + IN UINT32 Identifier + ) +{ + if (Identifier == MODULE_START_ID || + Identifier == MODULE_END_ID || + Identifier == MODULE_LOADIMAGE_START_ID || + Identifier == MODULE_LOADIMAGE_END_ID || + Identifier == MODULE_DB_START_ID || + Identifier == MODULE_DB_END_ID || + Identifier == MODULE_DB_SUPPORT_START_ID || + Identifier == MODULE_DB_SUPPORT_END_ID || + Identifier == MODULE_DB_STOP_START_ID || + Identifier == MODULE_DB_STOP_END_ID) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Allocate buffer for Boot Performance table. + + @return Status code. + +**/ +EFI_STATUS +AllocateBootPerformanceTable ( + ) +{ + EFI_STATUS Status; + UINTN Size; + UINT8 *SmmBootRecordCommBuffer; + EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader; + SMM_BOOT_RECORD_COMMUNICATE *SmmCommData; + UINTN CommSize; + UINTN BootPerformanceDataSize; + UINT8 *BootPerformanceData; + EFI_SMM_COMMUNICATION_PROTOCOL *Communication; + FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable; + EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable; + EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion; + UINTN Index; + VOID *SmmBootRecordData; + UINTN SmmBootRecordDataSize; + UINTN ReservedMemSize; + + // + // Collect boot records from SMM drivers. + // + SmmBootRecordCommBuffer = NULL; + SmmCommData = NULL; + SmmBootRecordData = NULL; + SmmBootRecordDataSize = 0; + ReservedMemSize = 0; + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication); + if (!EFI_ERROR (Status)) { + // + // Initialize communicate buffer + // Get the prepared Reserved Memory Range + // + Status = EfiGetSystemConfigurationTable ( + &gEdkiiPiSmmCommunicationRegionTableGuid, + (VOID **) &SmmCommRegionTable + ); + if (!EFI_ERROR (Status)) { + ASSERT (SmmCommRegionTable != NULL); + SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1); + for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index ++) { + if (SmmCommMemRegion->Type == EfiConventionalMemory) { + break; + } + SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize); + } + ASSERT (Index < SmmCommRegionTable->NumberOfEntries); + ASSERT (SmmCommMemRegion->PhysicalStart > 0); + ASSERT (SmmCommMemRegion->NumberOfPages > 0); + ReservedMemSize = (UINTN) SmmCommMemRegion->NumberOfPages * EFI_PAGE_SIZE; + + // + // Check enough reserved memory space + // + if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) { + SmmBootRecordCommBuffer = (VOID *) (UINTN) SmmCommMemRegion->PhysicalStart; + SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer; + SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data; + ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE)); + + CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid); + SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE); + CommSize = SMM_BOOT_RECORD_COMM_SIZE; + + // + // Get the size of boot records. + // + SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE; + SmmCommData->BootRecordData = NULL; + Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize); + + if (!EFI_ERROR (Status) && !EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) { + // + // Get all boot records + // + SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET; + SmmBootRecordDataSize = SmmCommData->BootRecordSize; + SmmBootRecordData = AllocateZeroPool(SmmBootRecordDataSize); + ASSERT (SmmBootRecordData != NULL); + SmmCommData->BootRecordOffset = 0; + SmmCommData->BootRecordData = (VOID *) ((UINTN) SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE); + SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE; + while (SmmCommData->BootRecordOffset < SmmBootRecordDataSize) { + Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + ASSERT_EFI_ERROR(SmmCommData->ReturnStatus); + if (SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize > SmmBootRecordDataSize) { + CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmCommData->BootRecordOffset); + } else { + CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmCommData->BootRecordSize); + } + SmmCommData->BootRecordOffset = SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize; + } + } + } + } + } + + // + // Prepare memory for Boot Performance table. + // Boot Performance table includes BasicBoot record, and one or more appended Boot Records. + // + BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mPerformanceLength + PcdGet32 (PcdExtFpdtBootRecordPadSize); + if (SmmCommData != NULL && SmmBootRecordData != NULL) { + BootPerformanceDataSize += SmmBootRecordDataSize; + } + + // + // Try to allocate the same runtime buffer as last time boot. + // + ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable)); + Size = sizeof (PerformanceVariable); + Status = gRT->GetVariable ( + EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME, + &gEfiFirmwarePerformanceGuid, + NULL, + &Size, + &PerformanceVariable + ); + if (!EFI_ERROR (Status)) { + Status = gBS->AllocatePages ( + AllocateAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (BootPerformanceDataSize), + &PerformanceVariable.BootPerformanceTablePointer + ); + if (!EFI_ERROR (Status)) { + mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer; + } + } + + if (mAcpiBootPerformanceTable == NULL) { + // + // Fail to allocate at specified address, continue to allocate at any address. + // + mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) AllocatePeiAccessiblePages ( + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (BootPerformanceDataSize) + ); + if (mAcpiBootPerformanceTable != NULL) { + ZeroMem (mAcpiBootPerformanceTable, BootPerformanceDataSize); + } + } + DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable)); + + if (mAcpiBootPerformanceTable == NULL) { + if (SmmCommData != NULL && SmmBootRecordData != NULL) { + FreePool (SmmBootRecordData); + } + return EFI_OUT_OF_RESOURCES; + } + + // + // Prepare Boot Performance Table. + // + BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable; + // + // Fill Basic Boot record to Boot Performance Table. + // + CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate)); + BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length; + // + // Fill Boot records from boot drivers. + // + if (mPerformancePointer != NULL) { + CopyMem (BootPerformanceData, mPerformancePointer, mPerformanceLength); + mAcpiBootPerformanceTable->Header.Length += mPerformanceLength; + BootPerformanceData = BootPerformanceData + mPerformanceLength; + FreePool (mPerformancePointer); + mPerformancePointer = NULL; + mPerformanceLength = 0; + mMaxPerformanceLength = 0; + } + if (SmmCommData != NULL && SmmBootRecordData != NULL) { + // + // Fill Boot records from SMM drivers. + // + CopyMem (BootPerformanceData, SmmBootRecordData, SmmBootRecordDataSize); + FreePool (SmmBootRecordData); + mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize); + BootPerformanceData = BootPerformanceData + SmmBootRecordDataSize; + } + + mBootRecordBuffer = (UINT8 *) mAcpiBootPerformanceTable; + mBootRecordSize = mAcpiBootPerformanceTable->Header.Length; + mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize); + + return EFI_SUCCESS; +} + +/** + Get a human readable module name and module guid for the given image handle. + If module name can't be found, "" string will return. + If module guid can't be found, Zero Guid will return. + + @param Handle Image handle or Controller handle. + @param NameString The ascii string will be filled into it. If not found, null string will return. + @param BufferSize Size of the input NameString buffer. + @param ModuleGuid Point to the guid buffer to store the got module guid value. + + @retval EFI_SUCCESS Successfully get module name and guid. + @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL. + @retval other value Module Name can't be got. +**/ +EFI_STATUS +GetModuleInfoFromHandle ( + IN EFI_HANDLE Handle, + OUT CHAR8 *NameString, + IN UINTN BufferSize, + OUT EFI_GUID *ModuleGuid OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + CHAR8 *PdbFileName; + EFI_GUID *TempGuid; + UINTN StartIndex; + UINTN Index; + INTN Count; + BOOLEAN ModuleGuidIsGet; + UINTN StringSize; + CHAR16 *StringPtr; + EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + if (NameString == NULL || BufferSize == 0) { + return EFI_INVALID_PARAMETER; + } + // + // Try to get the ModuleGuid and name string form the caached array. + // + if (mCachePairCount > 0) { + for (Count = mCachePairCount -1; Count >= 0; Count--) { + if (Handle == mCacheHandleGuidTable[Count].Handle) { + CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid); + AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString); + return EFI_SUCCESS; + } + } + } + + Status = EFI_INVALID_PARAMETER; + LoadedImage = NULL; + ModuleGuidIsGet = FALSE; + + // + // Initialize GUID as zero value. + // + TempGuid = &gZeroGuid; + // + // Initialize it as "" string. + // + NameString[0] = 0; + + if (Handle != NULL) { + // + // Try Handle as ImageHandle. + // + Status = gBS->HandleProtocol ( + Handle, + &gEfiLoadedImageProtocolGuid, + (VOID**) &LoadedImage + ); + + if (EFI_ERROR (Status)) { + // + // Try Handle as Controller Handle + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Get Image protocol from ImageHandle + // + Status = gBS->HandleProtocol ( + DriverBinding->ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**) &LoadedImage + ); + } + } + } + + if (!EFI_ERROR (Status) && LoadedImage != NULL) { + // + // Get Module Guid from DevicePath. + // + if (LoadedImage->FilePath != NULL && + LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH && + LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP + ) { + // + // Determine GUID associated with module logging performance + // + ModuleGuidIsGet = TRUE; + FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath; + TempGuid = &FvFilePath->FvFileName; + } + + // + // Method 1 Get Module Name from PDB string. + // + PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + if (PdbFileName != NULL && BufferSize > 0) { + StartIndex = 0; + for (Index = 0; PdbFileName[Index] != 0; Index++) { + if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) { + StartIndex = Index + 1; + } + } + // + // Copy the PDB file name to our temporary string. + // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary. + // + for (Index = 0; Index < BufferSize - 1; Index++) { + NameString[Index] = PdbFileName[Index + StartIndex]; + if (NameString[Index] == 0 || NameString[Index] == '.') { + NameString[Index] = 0; + break; + } + } + + if (Index == BufferSize - 1) { + NameString[Index] = 0; + } + // + // Module Name is got. + // + goto Done; + } + } + + // + // Method 2: Get the name string from ComponentName2 protocol + // + Status = gBS->HandleProtocol ( + Handle, + &gEfiComponentName2ProtocolGuid, + (VOID **) &ComponentName2 + ); + if (!EFI_ERROR (Status)) { + // + // Get the current platform language setting + // + if (mPlatformLanguage == NULL) { + GetEfiGlobalVariable2 (L"PlatformLang", (VOID **) &mPlatformLanguage, NULL); + } + if (mPlatformLanguage != NULL) { + Status = ComponentName2->GetDriverName ( + ComponentName2, + mPlatformLanguage != NULL ? mPlatformLanguage : "en-US", + &StringPtr + ); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) { + NameString[Index] = (CHAR8) StringPtr[Index]; + } + NameString[Index] = 0; + // + // Module Name is got. + // + goto Done; + } + } + } + + if (ModuleGuidIsGet) { + // + // Method 3 Try to get the image's FFS UI section by image GUID + // + StringPtr = NULL; + StringSize = 0; + Status = GetSectionFromAnyFv ( + TempGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **) &StringPtr, + &StringSize + ); + + if (!EFI_ERROR (Status)) { + // + // Method 3. Get the name string from FFS UI section + // + for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) { + NameString[Index] = (CHAR8) StringPtr[Index]; + } + NameString[Index] = 0; + FreePool (StringPtr); + } + } + +Done: + // + // Copy Module Guid + // + if (ModuleGuid != NULL) { + CopyGuid (ModuleGuid, TempGuid); + if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) { + // Handle is GUID + CopyGuid (ModuleGuid, (EFI_GUID *) Handle); + } + } + + // + // Cache the Handle and Guid pairs. + // + if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) { + mCacheHandleGuidTable[mCachePairCount].Handle = Handle; + CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid); + AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString); + mCachePairCount ++; + } + + return Status; +} + +/** + Get the FPDT record identifier. + + @param Attribute The attribute of the Record. + PerfStartEntry: Start Record. + PerfEndEntry: End Record. + @param Handle Pointer to environment specific context used to identify the component being measured. + @param String Pointer to a Null-terminated ASCII string that identifies the component being measured. + @param ProgressID On return, pointer to the ProgressID. + + @retval EFI_SUCCESS Get record info successfully. + @retval EFI_INVALID_PARAMETER No matched FPDT record. + +**/ +EFI_STATUS +GetFpdtRecordId ( + IN PERF_MEASUREMENT_ATTRIBUTE Attribute, + IN CONST VOID *Handle, + IN CONST CHAR8 *String, + OUT UINT16 *ProgressID + ) +{ + // + // Token to PerfId. + // + if (String != NULL) { + if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_START_ID; + } else { + *ProgressID = MODULE_END_ID; + } + } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_LOADIMAGE_START_ID; + } else { + *ProgressID = MODULE_LOADIMAGE_END_ID; + } + } else if (AsciiStrCmp (String, DRIVERBINDING_START_TOK) == 0) { // "DB:Start:" + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_DB_START_ID; + } else { + *ProgressID = MODULE_DB_END_ID; + } + } else if (AsciiStrCmp (String, DRIVERBINDING_SUPPORT_TOK) == 0) { // "DB:Support:" + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + return RETURN_UNSUPPORTED; + } + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_DB_SUPPORT_START_ID; + } else { + *ProgressID = MODULE_DB_SUPPORT_END_ID; + } + } else if (AsciiStrCmp (String, DRIVERBINDING_STOP_TOK) == 0) { // "DB:Stop:" + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + return RETURN_UNSUPPORTED; + } + if (Attribute == PerfStartEntry) { + *ProgressID = MODULE_DB_STOP_START_ID; + } else { + *ProgressID = MODULE_DB_STOP_END_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 { + *ProgressID = PERF_CROSSMODULE_END_ID; + } + } else { // Pref used in Modules. + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; + } else { + *ProgressID = PERF_INMODULE_END_ID; + } + } + } else if (Handle!= NULL) { // Pref used in Modules. + if (Attribute == PerfStartEntry) { + *ProgressID = PERF_INMODULE_START_ID; + } else { + *ProgressID = PERF_INMODULE_END_ID; + } + } else { + return EFI_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); + + if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + DestMax = STRING_SIZE; + } else { + DestMax = AsciiStrSize (Source); + if (DestMax > STRING_SIZE) { + DestMax = STRING_SIZE; + } + } + StringLen = AsciiStrLen (Source); + if (StringLen >= DestMax) { + StringLen = DestMax -1; + } + + AsciiStrnCpyS(Destination, DestMax, Source, StringLen); + *Length += (UINT8)DestMax; + + return; +} + +/** + 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. + + @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 + + @retval EFI_SUCCESS - Successfully got string description for device + @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor DevicePath were found + +**/ +EFI_STATUS +GetDeviceInfoFromHandleAndUpdateLength ( + IN CONST VOID *Handle, + IN EFI_HANDLE ControllerHandle, + 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) { + // + // Only copy enough to fill FPDT_MAX_PERF_RECORD_SIZE worth of the record + // + ControllerNameStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length) - 1; + } + + UnicodeStrnToAsciiStrS(StringPtr, ControllerNameStringSize - 1, ComponentNameString, ControllerNameStringSize, &ControllerNameStringSize); + + // + // Add a space in the end of the ControllerName + // + AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1; + *AsciiStringPtr = 0x20; + AsciiStringPtr++; + *AsciiStringPtr = 0; + ControllerNameStringSize++; + + *Length += (UINT8)ControllerNameStringSize; + } + + // + // This function returns the device path protocol from the handle specified by Handle. If Handle is + // NULL or Handle does not contain a device path protocol, then NULL is returned. + // + DevicePathProtocol = DevicePathFromHandle(ControllerHandle); + + if (DevicePathProtocol != NULL) { + StringPtr = ConvertDevicePathToText (DevicePathProtocol, TRUE, FALSE); + if (StringPtr != NULL) { + // + // This will produce the size of the unicode string, which is twice as large as the ASCII one + // This must be an even number, so ok to divide by 2 + // + DevicePathStringSize = StrSize(StringPtr) / 2; + + if ((DevicePathStringSize + (*Length)) > FPDT_MAX_PERF_RECORD_SIZE) { + // + // Only copy enough to fill 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; + } + + UnicodeStrnToAsciiStrS(StringPtr, DevicePathStringSize - 1, AsciiStringPtr, DevicePathStringSize, &DevicePathStringSize); + *Length += (UINT8)DevicePathStringSize; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; +} + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID. + @param Guid - Pointer to a GUID. + @param String - Pointer to a string describing the measurement. + @param Ticker - 64-bit time stamp. + @param Address - Pointer to a location in memory relevant to the measurement. + @param PerfId - Performance identifier describing the type of measurement. + @param Attribute - The attribute of the measurement. According to attribute can create a start + record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX, + or a general record for other Perf macros. + + @retval EFI_SUCCESS - Successfully created performance record. + @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records. + @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL + pointer or invalid PerfId. + + @retval EFI_SUCCESS - Successfully created performance record + @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records + @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL + pointer or invalid PerfId + +**/ +EFI_STATUS +InsertFpdtRecord ( + IN CONST VOID *CallerIdentifier, OPTIONAL + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 Ticker, + IN UINT64 Address, OPTIONAL + IN UINT16 PerfId, + IN PERF_MEASUREMENT_ATTRIBUTE Attribute + ) +{ + EFI_GUID ModuleGuid; + CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH]; + FPDT_RECORD_PTR FpdtRecordPtr; + FPDT_RECORD_PTR CachedFpdtRecordPtr; + UINT64 TimeStamp; + CONST CHAR8 *StringPtr; + UINTN DestMax; + UINTN StringLen; + EFI_STATUS Status; + UINT16 ProgressId; + + StringPtr = NULL; + ProgressId = 0; + ZeroMem (ModuleName, sizeof (ModuleName)); + + // + // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX. + // notes: For other Perf macros (Attribute == PerfEntry), their Id is known. + // + if (Attribute != PerfEntry) { + // + // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority. + // !!! Note: If the Perf is not the known Token used in the core but have same + // ID with the core Token, this case will not be supported. + // And in currtnt usage mode, for the unkown ID, there is a general rule: + // If it is start pref: the lower 4 bits of the ID should be 0. + // If it is end pref: the lower 4 bits of the ID should not be 0. + // If input ID doesn't follow the rule, we will adjust it. + // + if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) { + return EFI_INVALID_PARAMETER; + } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) { + if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) { + PerfId &= 0xFFF0; + } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) { + PerfId += 1; + } + } else if (PerfId == 0) { + // + // Get ProgressID form the String Token. + // + Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId); + if (EFI_ERROR (Status)) { + return Status; + } + PerfId = ProgressId; + } + } + + // + // 2. Get the buffer to store the FPDT record. + // + Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr); + if (EFI_ERROR (Status)) { + return Status; + } + + // + //3. Get the TimeStamp. + // + if (Ticker == 0) { + Ticker = GetPerformanceCounter (); + TimeStamp = GetTimeInNanoSecond (Ticker); + } else if (Ticker == 1) { + TimeStamp = 0; + } else { + TimeStamp = GetTimeInNanoSecond (Ticker); + } + + // + // 4. Fill in the FPDT record according to different Performance Identifier. + // + switch (PerfId) { + case MODULE_START_ID: + case MODULE_END_ID: + GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid); + StringPtr = ModuleName; + // + // Cache the offset of start image start record and use to update the start image end record if needed. + // + if (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 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 (!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; + } + } + 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: + 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 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; + + case PERF_EVENTSIGNAL_START_ID: + case PERF_EVENTSIGNAL_END_ID: + case PERF_CALLBACK_START_ID: + case PERF_CALLBACK_END_ID: + if (String == NULL || Guid == NULL) { + return EFI_INVALID_PARAMETER; + } + StringPtr = String; + if (AsciiStrLen (String) == 0) { + StringPtr = "unknown name"; + } + if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) { + FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE; + FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD); + FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1; + FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId; + FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp; + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1)); + CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2)); + CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length); + } + break; + + case PERF_EVENT_ID: + case PERF_FUNCTION_START_ID: + case PERF_FUNCTION_END_ID: + case PERF_INMODULE_START_ID: + case PERF_INMODULE_END_ID: + case PERF_CROSSMODULE_START_ID: + case PERF_CROSSMODULE_END_ID: + 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; + if (Guid != NULL) { + // + // Cache the event guid in string event record. + // + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + } else { + CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid)); + } + if (AsciiStrLen (StringPtr) == 0) { + StringPtr = "unknown name"; + } + CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length); + + if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) { + FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE); + } + if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) { + 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; +} + +/** + Dumps all the PEI performance. + + @param HobStart A pointer to a Guid. + + This internal function dumps all the PEI performance log to the DXE performance gauge array. + It retrieves the optional GUID HOB for PEI performance and then saves the performance data + to DXE performance data structures. + +**/ +VOID +InternalGetPeiPerformance ( + VOID *HobStart + ) +{ + UINT8 *FirmwarePerformanceHob; + FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader; + UINT8 *EventRec; + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, HobStart); + while (GuidHob != NULL) { + FirmwarePerformanceHob = GET_GUID_HOB_DATA (GuidHob); + PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)FirmwarePerformanceHob; + + if (mPerformanceLength + PeiPerformanceLogHeader->SizeOfAllEntries > mMaxPerformanceLength) { + mPerformancePointer = ReallocatePool ( + mPerformanceLength, + mPerformanceLength + + (UINTN)PeiPerformanceLogHeader->SizeOfAllEntries + + FIRMWARE_RECORD_BUFFER, + mPerformancePointer + ); + ASSERT (mPerformancePointer != NULL); + mMaxPerformanceLength = mPerformanceLength + + (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries) + + FIRMWARE_RECORD_BUFFER; + } + + EventRec = mPerformancePointer + mPerformanceLength; + CopyMem (EventRec, FirmwarePerformanceHob + sizeof (FPDT_PEI_EXT_PERF_HEADER), (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries)); + // + // Update the used buffer size. + // + mPerformanceLength += (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries); + mLoadImageCount += PeiPerformanceLogHeader->LoadImageCount; + + // + // Get next performance guid hob + // + GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob)); + } +} + +/** + Report Boot Perforamnce table address as report status code. + + @param Event The event of notify protocol. + @param Context Notify event context. + +**/ +VOID +EFIAPI +ReportFpdtRecordBuffer ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINT64 BPDTAddr; + + if (!mFpdtBufferIsReported) { + Status = AllocateBootPerformanceTable (); + if (!EFI_ERROR(Status)) { + BPDTAddr = (UINT64)(UINTN)mAcpiBootPerformanceTable; + REPORT_STATUS_CODE_EX ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_DXE_BS_DRIVER, + 0, + NULL, + &gEdkiiFpdtExtendedFirmwarePerformanceGuid, + &BPDTAddr, + sizeof (UINT64) + ); + } + // + // Set FPDT report state to TRUE. + // + mFpdtBufferIsReported = TRUE; + } +} + +/** + The constructor function initializes Performance infrastructure for DXE phase. + + The constructor function publishes Performance and PerformanceEx protocol, allocates memory to log DXE performance + and merges PEI performance data to DXE performance log. + It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +DxeCorePerformanceLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_EVENT ReadyToBootEvent; + PERFORMANCE_PROPERTY *PerformanceProperty; + + if (!PerformanceMeasurementEnabled ()) { + // + // Do not initialize performance infrastructure if not required. + // + return EFI_SUCCESS; + } + + // + // Dump normal PEI performance records + // + InternalGetPeiPerformance (GetHobList()); + + // + // Install the protocol interfaces for DXE performance library instance. + // + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEdkiiPerformanceMeasurementProtocolGuid, + &mPerformanceMeasurementInterface, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Register ReadyToBoot event to report StatusCode data + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ReportFpdtRecordBuffer, + NULL, + &gEfiEventReadyToBootGuid, + &ReadyToBootEvent + ); + + ASSERT_EFI_ERROR (Status); + + Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty); + if (EFI_ERROR (Status)) { + // + // Install configuration table for performance property. + // + mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION; + mPerformanceProperty.Reserved = 0; + mPerformanceProperty.Frequency = GetPerformanceCounterProperties ( + &mPerformanceProperty.TimerStartValue, + &mPerformanceProperty.TimerEndValue + ); + Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} + +/** + Create performance record with event description and a timestamp. + + @param CallerIdentifier - Image handle or pointer to caller ID GUID. + @param Guid - Pointer to a GUID. + @param String - Pointer to a string describing the measurement. + @param TimeStamp - 64-bit time stamp. + @param Address - Pointer to a location in memory relevant to the measurement. + @param Identifier - Performance identifier describing the type of measurement. + @param Attribute - The attribute of the measurement. According to attribute can create a start + record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX, + or a general record for other Perf macros. + + @retval EFI_SUCCESS - Successfully created performance record. + @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records. + @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL + pointer or invalid PerfId. +**/ +EFI_STATUS +EFIAPI +CreatePerformanceMeasurement ( + IN CONST VOID *CallerIdentifier, + IN CONST VOID *Guid, OPTIONAL + IN CONST CHAR8 *String, OPTIONAL + IN UINT64 TimeStamp, + IN UINT64 Address, OPTIONAL + IN UINT32 Identifier, + IN PERF_MEASUREMENT_ATTRIBUTE Attribute + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + if (mLockInsertRecord) { + return EFI_INVALID_PARAMETER; + } + mLockInsertRecord = TRUE; + + Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute); + + mLockInsertRecord = FALSE; + + return Status; +} + +/** + Adds a record at the end of the performance measurement log + that records the start time of a performance measurement. + + Adds a record to the end of the performance measurement log + that contains the Handle, Token, Module and Identifier. + The end time of the new record must be set to zero. + If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record. + If TimeStamp is zero, the start time in the record is filled in with the value + read from the current time stamp. + + @param Handle Pointer to environment specific context used + to identify the component being measured. + @param Token Pointer to a Null-terminated ASCII string + that identifies the component being measured. + @param Module Pointer to a Null-terminated ASCII string + that identifies the module being measured. + @param TimeStamp 64-bit time stamp. + @param Identifier 32-bit identifier. If the value is 0, the created record + is same as the one created by StartPerformanceMeasurement. + + @retval RETURN_SUCCESS The start of the measurement was recorded. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement. + +**/ +RETURN_STATUS +EFIAPI +StartPerformanceMeasurementEx ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp, + IN UINT32 Identifier + ) +{ + CONST CHAR8 *String; + + if (Token != NULL) { + String = Token; + } else if (Module != NULL) { + String = Module; + } else { + String = NULL; + } + + return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry); +} + +/** + Searches the performance measurement log from the beginning of the log + for the first matching record that contains a zero end time and fills in a valid end time. + + Searches the performance measurement log from the beginning of the log + for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero. + If the record can not be found then return RETURN_NOT_FOUND. + If the record is found and TimeStamp is not zero, + then the end time in the record is filled in with the value specified by TimeStamp. + If the record is found and TimeStamp is zero, then the end time in the matching record + is filled in with the current time stamp value. + + @param Handle Pointer to environment specific context used + to identify the component being measured. + @param Token Pointer to a Null-terminated ASCII string + that identifies the component being measured. + @param Module Pointer to a Null-terminated ASCII string + that identifies the module being measured. + @param TimeStamp 64-bit time stamp. + @param Identifier 32-bit identifier. If the value is 0, the found record + is same as the one found by EndPerformanceMeasurement. + + @retval RETURN_SUCCESS The end of the measurement was recorded. + @retval RETURN_NOT_FOUND The specified measurement record could not be found. + +**/ +RETURN_STATUS +EFIAPI +EndPerformanceMeasurementEx ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp, + IN UINT32 Identifier + ) +{ + CONST CHAR8 *String; + + if (Token != NULL) { + String = Token; + } else if (Module != NULL) { + String = Module; + } else { + String = NULL; + } + + return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry); +} + +/** + Attempts to retrieve a performance measurement log entry from the performance measurement log. + It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement, + and then assign the Identifier with 0. + + !!! Not support!!! + + Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is + zero on entry, then an attempt is made to retrieve the first entry from the performance log, + and the key for the second entry in the log is returned. If the performance log is empty, + then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance + log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is + returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is + retrieved and an implementation specific non-zero key value that specifies the end of the performance + log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry + is retrieved and zero is returned. In the cases where a performance log entry can be returned, + the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier. + If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT(). + If Handle is NULL, then ASSERT(). + If Token is NULL, then ASSERT(). + If Module is NULL, then ASSERT(). + If StartTimeStamp is NULL, then ASSERT(). + If EndTimeStamp is NULL, then ASSERT(). + If Identifier is NULL, then ASSERT(). + + @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve. + 0, then the first performance measurement log entry is retrieved. + On exit, the key of the next performance log entry. + @param Handle Pointer to environment specific context used to identify the component + being measured. + @param Token Pointer to a Null-terminated ASCII string that identifies the component + being measured. + @param Module Pointer to a Null-terminated ASCII string that identifies the module + being measured. + @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement + was started. + @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement + was ended. + @param Identifier Pointer to the 32-bit identifier that was recorded when the measurement + was ended. + + @return The key for the next performance log entry (in general case). + +**/ +UINTN +EFIAPI +GetPerformanceMeasurementEx ( + IN UINTN LogEntryKey, + OUT CONST VOID **Handle, + OUT CONST CHAR8 **Token, + OUT CONST CHAR8 **Module, + OUT UINT64 *StartTimeStamp, + OUT UINT64 *EndTimeStamp, + OUT UINT32 *Identifier + ) +{ + return 0; +} + +/** + Adds a record at the end of the performance measurement log + that records the start time of a performance measurement. + + Adds a record to the end of the performance measurement log + that contains the Handle, Token, and Module. + The end time of the new record must be set to zero. + If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record. + If TimeStamp is zero, the start time in the record is filled in with the value + read from the current time stamp. + + @param Handle Pointer to environment specific context used + to identify the component being measured. + @param Token Pointer to a Null-terminated ASCII string + that identifies the component being measured. + @param Module Pointer to a Null-terminated ASCII string + that identifies the module being measured. + @param TimeStamp 64-bit time stamp. + + @retval RETURN_SUCCESS The start of the measurement was recorded. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement. + +**/ +RETURN_STATUS +EFIAPI +StartPerformanceMeasurement ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp + ) +{ + return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0); +} + +/** + Searches the performance measurement log from the beginning of the log + for the first matching record that contains a zero end time and fills in a valid end time. + + Searches the performance measurement log from the beginning of the log + for the first record that matches Handle, Token, and Module and has an end time value of zero. + If the record can not be found then return RETURN_NOT_FOUND. + If the record is found and TimeStamp is not zero, + then the end time in the record is filled in with the value specified by TimeStamp. + If the record is found and TimeStamp is zero, then the end time in the matching record + is filled in with the current time stamp value. + + @param Handle Pointer to environment specific context used + to identify the component being measured. + @param Token Pointer to a Null-terminated ASCII string + that identifies the component being measured. + @param Module Pointer to a Null-terminated ASCII string + that identifies the module being measured. + @param TimeStamp 64-bit time stamp. + + @retval RETURN_SUCCESS The end of the measurement was recorded. + @retval RETURN_NOT_FOUND The specified measurement record could not be found. + +**/ +RETURN_STATUS +EFIAPI +EndPerformanceMeasurement ( + IN CONST VOID *Handle, OPTIONAL + IN CONST CHAR8 *Token, OPTIONAL + IN CONST CHAR8 *Module, OPTIONAL + IN UINT64 TimeStamp + ) +{ + return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0); +} + +/** + Attempts to retrieve a performance measurement log entry from the performance measurement log. + It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx, + and then eliminate the Identifier. + + !!! Not support!!! + + Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is + zero on entry, then an attempt is made to retrieve the first entry from the performance log, + and the key for the second entry in the log is returned. If the performance log is empty, + then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance + log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is + returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is + retrieved and an implementation specific non-zero key value that specifies the end of the performance + log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry + is retrieved and zero is returned. In the cases where a performance log entry can be returned, + the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp. + If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT(). + If Handle is NULL, then ASSERT(). + If Token is NULL, then ASSERT(). + If Module is NULL, then ASSERT(). + If StartTimeStamp is NULL, then ASSERT(). + If EndTimeStamp is NULL, then ASSERT(). + + @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve. + 0, then the first performance measurement log entry is retrieved. + On exit, the key of the next performance log entry. + @param Handle Pointer to environment specific context used to identify the component + being measured. + @param Token Pointer to a Null-terminated ASCII string that identifies the component + being measured. + @param Module Pointer to a Null-terminated ASCII string that identifies the module + being measured. + @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement + was started. + @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement + was ended. + + @return The key for the next performance log entry (in general case). + +**/ +UINTN +EFIAPI +GetPerformanceMeasurement ( + IN UINTN LogEntryKey, + OUT CONST VOID **Handle, + OUT CONST CHAR8 **Token, + OUT CONST CHAR8 **Module, + OUT UINT64 *StartTimeStamp, + OUT UINT64 *EndTimeStamp + ) +{ + return 0; +} + +/** + Returns TRUE if the performance measurement macros are enabled. + + This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of + PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of + PcdPerformanceLibraryPropertyMask is set. + @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of + PcdPerformanceLibraryPropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +PerformanceMeasurementEnabled ( + VOID + ) +{ + return (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; +} |