summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
diff options
context:
space:
mode:
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.c1822
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;
+}