/** @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 - 2023, 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; | |
UINTN 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; | |
UINTN mSmmBootRecordOffset = 0; | |
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; | |
} | |
} | |
/** | |
This internal function dumps all the SMM performance data and size. | |
@param SmmPerfData Smm Performance data. The buffer contain the SMM perf data is allocated by this function and caller needs to free it. | |
@param SmmPerfDataSize Smm Performance data size. | |
@param SkipGetPerfData Skip to get performance data, just get the size. | |
**/ | |
VOID | |
InternalGetSmmPerfData ( | |
OUT VOID **SmmPerfData, | |
OUT UINTN *SmmPerfDataSize, | |
IN BOOLEAN SkipGetPerfData | |
) | |
{ | |
EFI_STATUS Status; | |
UINT8 *SmmBootRecordCommBuffer; | |
EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader; | |
SMM_BOOT_RECORD_COMMUNICATE *SmmCommData; | |
UINTN CommSize; | |
EFI_SMM_COMMUNICATION_PROTOCOL *Communication; | |
EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable; | |
EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion; | |
UINTN Index; | |
VOID *SmmBootRecordData; | |
UINTN SmmBootRecordDataSize; | |
UINTN ReservedMemSize; | |
UINTN SmmBootRecordDataRetrieved; | |
// | |
// Collect boot records from SMM drivers. | |
// | |
SmmBootRecordCommBuffer = NULL; | |
SmmCommData = NULL; | |
SmmBootRecordData = NULL; | |
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)) { | |
if (SkipGetPerfData) { | |
*SmmPerfDataSize = SmmCommData->BootRecordSize; | |
return; | |
} | |
// | |
// Get boot records starting from mSmmBootRecordOffset | |
// | |
SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET; | |
SmmCommData->BootRecordOffset = mSmmBootRecordOffset; | |
SmmBootRecordDataSize = SmmCommData->BootRecordSize - mSmmBootRecordOffset; | |
SmmBootRecordData = AllocateZeroPool (SmmBootRecordDataSize); | |
SmmBootRecordDataRetrieved = 0; | |
ASSERT (SmmBootRecordData != NULL); | |
SmmCommData->BootRecordData = (VOID *)((UINTN)SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE); | |
SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE; | |
while (SmmBootRecordDataRetrieved < SmmBootRecordDataSize) { | |
Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize); | |
ASSERT_EFI_ERROR (Status); | |
ASSERT_EFI_ERROR (SmmCommData->ReturnStatus); | |
if (SmmBootRecordDataRetrieved + SmmCommData->BootRecordSize > SmmBootRecordDataSize) { | |
CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmBootRecordDataRetrieved); | |
} else { | |
CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, SmmCommData->BootRecordData, SmmCommData->BootRecordSize); | |
} | |
SmmBootRecordDataRetrieved += SmmCommData->BootRecordSize; | |
SmmCommData->BootRecordOffset += SmmCommData->BootRecordSize; | |
} | |
mSmmBootRecordOffset = SmmCommData->BootRecordOffset; | |
*SmmPerfData = SmmBootRecordData; | |
*SmmPerfDataSize = SmmBootRecordDataSize; | |
} | |
} | |
} | |
} | |
} | |
/** | |
Allocate buffer for Boot Performance table. | |
@return Status code. | |
**/ | |
EFI_STATUS | |
AllocateBootPerformanceTable ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Size; | |
UINTN BootPerformanceDataSize; | |
UINT8 *BootPerformanceData; | |
FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable; | |
UINTN SmmBootRecordDataSize; | |
SmmBootRecordDataSize = 0; | |
// | |
// Get SMM performance data size at the point of EndOfDxe in order to allocate the boot performance table. | |
// Will Get all the data at ReadyToBoot. | |
// | |
InternalGetSmmPerfData (NULL, &SmmBootRecordDataSize, TRUE); | |
// | |
// 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 + SmmBootRecordDataSize + PcdGet32 (PcdExtFpdtBootRecordPadSize); | |
// | |
// 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) { | |
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; | |
} | |
mBootRecordBuffer = (UINT8 *)mAcpiBootPerformanceTable; | |
mBootRecordSize = mAcpiBootPerformanceTable->Header.Length; | |
mBootRecordMaxSize = BootPerformanceDataSize; | |
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) | |
); | |
Status = gBS->InstallConfigurationTable (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, (VOID *)(UINTN)BPDTAddr); | |
ASSERT_EFI_ERROR (Status); | |
} | |
// | |
// Set FPDT report state to TRUE. | |
// | |
mFpdtBufferIsReported = TRUE; | |
} | |
} | |
/** | |
Update Boot Performance table. | |
@param Event The event of notify protocol. | |
@param Context Notify event context. | |
**/ | |
VOID | |
EFIAPI | |
UpdateBootPerformanceTable ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
VOID *SmmBootRecordData; | |
UINTN SmmBootRecordDataSize; | |
UINTN AppendSize; | |
UINT8 *FirmwarePerformanceTablePtr; | |
SmmBootRecordDataSize = 0; | |
// | |
// Get SMM performance data. | |
// | |
SmmBootRecordData = NULL; | |
InternalGetSmmPerfData (&SmmBootRecordData, &SmmBootRecordDataSize, FALSE); | |
FirmwarePerformanceTablePtr = (UINT8 *)mAcpiBootPerformanceTable + mAcpiBootPerformanceTable->Header.Length; | |
if (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize > mBootRecordMaxSize) { | |
DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save all SMM boot performance data\n")); | |
AppendSize = mBootRecordMaxSize - mAcpiBootPerformanceTable->Header.Length; | |
} else { | |
AppendSize = SmmBootRecordDataSize; | |
} | |
if (SmmBootRecordData != NULL) { | |
CopyMem (FirmwarePerformanceTablePtr, SmmBootRecordData, AppendSize); | |
mAcpiBootPerformanceTable->Header.Length += (UINT32)AppendSize; | |
mBootRecordSize += (UINT32)AppendSize; | |
FreePool (SmmBootRecordData); | |
} | |
} | |
/** | |
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 EndOfDxeEvent; | |
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 EndOfDxe event to allocate the boot performance table and report the table address through status code. | |
// | |
Status = gBS->CreateEventEx ( | |
EVT_NOTIFY_SIGNAL, | |
TPL_NOTIFY, | |
ReportFpdtRecordBuffer, | |
NULL, | |
&gEfiEndOfDxeEventGroupGuid, | |
&EndOfDxeEvent | |
); | |
// | |
// Register ReadyToBoot event to update the boot performance table for SMM performance data. | |
// | |
Status = gBS->CreateEventEx ( | |
EVT_NOTIFY_SIGNAL, | |
TPL_CALLBACK, | |
UpdateBootPerformanceTable, | |
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; | |
} |