/** @file | |
Intel Processor Trace feature. | |
Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "CpuCommonFeatures.h" | |
/// | |
/// This macro define the max entries in the Topa table. | |
/// Each entry in the table contains some attribute bits, a pointer to an output region, and the size of the region. | |
/// The last entry in the table may hold a pointer to the next table. This pointer can either point to the top of the | |
/// current table (for circular array) or to the base of another table. | |
/// At least 2 entries are needed because the list of entries must | |
/// be terminated by an entry with the END bit set to 1, so 2 | |
/// entries are required to use a single valid entry. | |
/// | |
#define MAX_TOPA_ENTRY_COUNT 2 | |
/// | |
/// Processor trace output scheme selection. | |
/// | |
typedef enum { | |
RtitOutputSchemeSingleRange = 0, | |
RtitOutputSchemeToPA | |
} RTIT_OUTPUT_SCHEME; | |
typedef struct { | |
BOOLEAN TopaSupported; | |
BOOLEAN SingleRangeSupported; | |
MSR_IA32_RTIT_CTL_REGISTER RtitCtrl; | |
MSR_IA32_RTIT_OUTPUT_BASE_REGISTER RtitOutputBase; | |
MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER RtitOutputMaskPtrs; | |
BOOLEAN CycPacketSupported; | |
} PROC_TRACE_PROCESSOR_DATA; | |
typedef struct { | |
UINT32 NumberOfProcessors; | |
UINT8 ProcTraceOutputScheme; | |
UINT32 ProcTraceMemSize; | |
UINTN *ThreadMemRegionTable; | |
UINTN AllocatedThreads; | |
UINTN *TopaMemArray; | |
BOOLEAN EnableOnBspOnly; | |
BOOLEAN EnablePerformanceCollecting; | |
PROC_TRACE_PROCESSOR_DATA *ProcessorData; | |
} PROC_TRACE_DATA; | |
typedef struct { | |
RTIT_TOPA_TABLE_ENTRY TopaEntry[MAX_TOPA_ENTRY_COUNT]; | |
} PROC_TRACE_TOPA_TABLE; | |
/** | |
Prepares for the data used by CPU feature detection and initialization. | |
@param[in] NumberOfProcessors The number of CPUs in the platform. | |
@return Pointer to a buffer of CPU related configuration data. | |
@note This service could be called by BSP only. | |
**/ | |
VOID * | |
EFIAPI | |
ProcTraceGetConfigData ( | |
IN UINTN NumberOfProcessors | |
) | |
{ | |
PROC_TRACE_DATA *ConfigData; | |
ConfigData = AllocateZeroPool (sizeof (PROC_TRACE_DATA) + sizeof (PROC_TRACE_PROCESSOR_DATA) * NumberOfProcessors); | |
ASSERT (ConfigData != NULL); | |
ConfigData->ProcessorData = (PROC_TRACE_PROCESSOR_DATA *)((UINT8 *)ConfigData + sizeof (PROC_TRACE_DATA)); | |
ConfigData->NumberOfProcessors = (UINT32)NumberOfProcessors; | |
ConfigData->ProcTraceMemSize = PcdGet32 (PcdCpuProcTraceMemSize); | |
ConfigData->ProcTraceOutputScheme = PcdGet8 (PcdCpuProcTraceOutputScheme); | |
ConfigData->EnableOnBspOnly = PcdGetBool (PcdCpuProcTraceBspOnly); | |
ConfigData->EnablePerformanceCollecting = PcdGetBool (PcdCpuProcTracePerformanceCollecting); | |
return ConfigData; | |
} | |
/** | |
Detects if Intel Processor Trace feature supported on current | |
processor. | |
@param[in] ProcessorNumber The index of the CPU executing this function. | |
@param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION | |
structure for the CPU executing this function. | |
@param[in] ConfigData A pointer to the configuration buffer returned | |
by CPU_FEATURE_GET_CONFIG_DATA. NULL if | |
CPU_FEATURE_GET_CONFIG_DATA was not provided in | |
RegisterCpuFeature(). | |
@retval TRUE Processor Trace feature is supported. | |
@retval FALSE Processor Trace feature is not supported. | |
@note This service could be called by BSP/APs. | |
**/ | |
BOOLEAN | |
EFIAPI | |
ProcTraceSupport ( | |
IN UINTN ProcessorNumber, | |
IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo, | |
IN VOID *ConfigData OPTIONAL | |
) | |
{ | |
PROC_TRACE_DATA *ProcTraceData; | |
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx; | |
CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX ProcTraceEcx; | |
CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_EBX ProcTraceEbx; | |
// | |
// Check if ProcTraceMemorySize option is enabled (0xFF means disable by user) | |
// | |
ProcTraceData = (PROC_TRACE_DATA *)ConfigData; | |
ASSERT (ProcTraceData != NULL); | |
if ((ProcTraceData->ProcTraceMemSize > RtitTopaMemorySize128M) || | |
(ProcTraceData->ProcTraceOutputScheme > RtitOutputSchemeToPA)) | |
{ | |
return FALSE; | |
} | |
// | |
// Check if Processor Trace is supported | |
// | |
AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, 0, NULL, &Ebx.Uint32, NULL, NULL); | |
if (Ebx.Bits.IntelProcessorTrace == 0) { | |
return FALSE; | |
} | |
AsmCpuidEx (CPUID_INTEL_PROCESSOR_TRACE, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF, NULL, &ProcTraceEbx.Uint32, &ProcTraceEcx.Uint32, NULL); | |
ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported = (BOOLEAN)(ProcTraceEcx.Bits.RTIT == 1); | |
ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported = (BOOLEAN)(ProcTraceEcx.Bits.SingleRangeOutput == 1); | |
if ((ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported && (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeToPA)) || | |
(ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported && (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeSingleRange))) | |
{ | |
ProcTraceData->ProcessorData[ProcessorNumber].RtitCtrl.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_CTL); | |
ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputBase.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_OUTPUT_BASE); | |
ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputMaskPtrs.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_OUTPUT_MASK_PTRS); | |
ProcTraceData->ProcessorData[ProcessorNumber].CycPacketSupported = (BOOLEAN)(ProcTraceEbx.Bits.ConfigurablePsb == 1); | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
Initializes Intel Processor Trace feature to specific state. | |
@param[in] ProcessorNumber The index of the CPU executing this function. | |
@param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION | |
structure for the CPU executing this function. | |
@param[in] ConfigData A pointer to the configuration buffer returned | |
by CPU_FEATURE_GET_CONFIG_DATA. NULL if | |
CPU_FEATURE_GET_CONFIG_DATA was not provided in | |
RegisterCpuFeature(). | |
@param[in] State If TRUE, then the Processor Trace feature must be | |
enabled. | |
If FALSE, then the Processor Trace feature must be | |
disabled. | |
@retval RETURN_SUCCESS Intel Processor Trace feature is initialized. | |
**/ | |
RETURN_STATUS | |
EFIAPI | |
ProcTraceInitialize ( | |
IN UINTN ProcessorNumber, | |
IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo, | |
IN VOID *ConfigData OPTIONAL, | |
IN BOOLEAN State | |
) | |
{ | |
UINT32 MemRegionSize; | |
UINTN Pages; | |
UINTN Alignment; | |
UINTN MemRegionBaseAddr; | |
UINTN *ThreadMemRegionTable; | |
UINTN Index; | |
UINTN TopaTableBaseAddr; | |
UINTN AlignedAddress; | |
UINTN *TopaMemArray; | |
PROC_TRACE_TOPA_TABLE *TopaTable; | |
PROC_TRACE_DATA *ProcTraceData; | |
BOOLEAN FirstIn; | |
MSR_IA32_RTIT_CTL_REGISTER CtrlReg; | |
MSR_IA32_RTIT_STATUS_REGISTER StatusReg; | |
MSR_IA32_RTIT_OUTPUT_BASE_REGISTER OutputBaseReg; | |
MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER OutputMaskPtrsReg; | |
RTIT_TOPA_TABLE_ENTRY *TopaEntryPtr; | |
BOOLEAN IsBsp; | |
// | |
// The scope of the MSR_IA32_RTIT_* is core for below processor type, only program | |
// MSR_IA32_RTIT_* for thread 0 in each core. | |
// | |
if (IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) || | |
IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) | |
{ | |
if (CpuInfo->ProcessorInfo.Location.Thread != 0) { | |
return RETURN_SUCCESS; | |
} | |
} | |
ProcTraceData = (PROC_TRACE_DATA *)ConfigData; | |
ASSERT (ProcTraceData != NULL); | |
// | |
// Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b | |
// | |
CtrlReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitCtrl.Uint64; | |
if (CtrlReg.Bits.TraceEn != 0) { | |
/// | |
/// Clear bit 0 in MSR IA32_RTIT_CTL (570) | |
/// | |
CtrlReg.Bits.TraceEn = 0; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_CTL, | |
CtrlReg.Uint64 | |
); | |
/// | |
/// Clear MSR IA32_RTIT_STS (571h) to all zeros | |
/// | |
StatusReg.Uint64 = 0x0; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_STATUS, | |
StatusReg.Uint64 | |
); | |
} | |
if (!State) { | |
return RETURN_SUCCESS; | |
} | |
IsBsp = (CpuInfo->ProcessorInfo.StatusFlag & PROCESSOR_AS_BSP_BIT) ? TRUE : FALSE; | |
if (ProcTraceData->EnableOnBspOnly && !IsBsp) { | |
return RETURN_SUCCESS; | |
} | |
MemRegionBaseAddr = 0; | |
FirstIn = FALSE; | |
if (ProcTraceData->ThreadMemRegionTable == NULL) { | |
FirstIn = TRUE; | |
DEBUG ((DEBUG_INFO, "Initialize Processor Trace\n")); | |
} | |
/// | |
/// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding | |
/// | |
MemRegionSize = (UINT32)(1 << (ProcTraceData->ProcTraceMemSize + 12)); | |
if (FirstIn) { | |
DEBUG ((DEBUG_INFO, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize)); | |
} | |
if (FirstIn) { | |
// | |
// Let BSP allocate and create the necessary memory region (Aligned to the size of | |
// the memory region from setup option(ProcTraceMemSize) which is an integral multiple of 4kB) | |
// for all the enabled threads to store Processor Trace debug data. Then Configure the trace | |
// address base in MSR, IA32_RTIT_OUTPUT_BASE (560h) bits 47:12. Note that all regions must be | |
// aligned based on their size, not just 4K. Thus a 2M region must have bits 20:12 cleared. | |
// | |
Pages = EFI_SIZE_TO_PAGES (MemRegionSize); | |
Alignment = MemRegionSize; | |
if (ProcTraceData->EnableOnBspOnly) { | |
// | |
// When only enable ProcTrace on BSP, this is the first and only time ProcTraceInitialize() runs. | |
// | |
MemRegionBaseAddr = (UINTN)AllocateAlignedReservedPages (Pages, Alignment); | |
if (MemRegionBaseAddr == 0) { | |
// | |
// Could not allocate for BSP even | |
// | |
DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, failed to allocate buffer for BSP\n")); | |
return RETURN_OUT_OF_RESOURCES; | |
} | |
DEBUG ((DEBUG_INFO, "ProcTrace: Allocated PT MemRegionBaseAddr(aligned) for BSP only: 0x%llX.\n", (UINT64)MemRegionBaseAddr)); | |
} else { | |
ThreadMemRegionTable = (UINTN *)AllocatePool (ProcTraceData->NumberOfProcessors * sizeof (UINTN *)); | |
if (ThreadMemRegionTable == NULL) { | |
DEBUG ((DEBUG_ERROR, "Allocate ProcTrace ThreadMemRegionTable Failed\n")); | |
return RETURN_OUT_OF_RESOURCES; | |
} | |
ProcTraceData->ThreadMemRegionTable = ThreadMemRegionTable; | |
for (Index = 0; Index < ProcTraceData->NumberOfProcessors; Index++, ProcTraceData->AllocatedThreads++) { | |
AlignedAddress = (UINTN)AllocateAlignedReservedPages (Pages, Alignment); | |
if (AlignedAddress == 0) { | |
DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocated only for %d threads\n", ProcTraceData->AllocatedThreads)); | |
if (Index == 0) { | |
// | |
// Could not allocate for BSP even | |
// | |
FreePool ((VOID *)ThreadMemRegionTable); | |
ThreadMemRegionTable = NULL; | |
return RETURN_OUT_OF_RESOURCES; | |
} | |
break; | |
} | |
ThreadMemRegionTable[Index] = AlignedAddress; | |
DEBUG ((DEBUG_INFO, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index, (UINT64)ThreadMemRegionTable[Index])); | |
} | |
DEBUG ((DEBUG_INFO, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData->AllocatedThreads)); | |
} | |
} | |
if (!ProcTraceData->EnableOnBspOnly) { | |
if (ProcessorNumber < ProcTraceData->AllocatedThreads) { | |
MemRegionBaseAddr = ProcTraceData->ThreadMemRegionTable[ProcessorNumber]; | |
} else { | |
return RETURN_SUCCESS; | |
} | |
} | |
/// | |
/// Check Processor Trace output scheme: Single Range output or ToPA table | |
/// | |
// | |
// Single Range output scheme | |
// | |
if (ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported && | |
(ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeSingleRange)) | |
{ | |
if (FirstIn) { | |
DEBUG ((DEBUG_INFO, "ProcTrace: Enabling Single Range Output scheme \n")); | |
} | |
// | |
// Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8) | |
// | |
CtrlReg.Bits.ToPA = 0; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_CTL, | |
CtrlReg.Uint64 | |
); | |
// | |
// Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with the allocated Memory Region | |
// | |
OutputBaseReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputBase.Uint64; | |
OutputBaseReg.Bits.Base = (MemRegionBaseAddr >> 7) & 0x01FFFFFF; | |
OutputBaseReg.Bits.BaseHi = RShiftU64 ((UINT64)MemRegionBaseAddr, 32) & 0xFFFFFFFF; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_OUTPUT_BASE, | |
OutputBaseReg.Uint64 | |
); | |
// | |
// Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h) | |
// | |
OutputMaskPtrsReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputMaskPtrs.Uint64; | |
OutputMaskPtrsReg.Bits.MaskOrTableOffset = ((MemRegionSize - 1) >> 7) & 0x01FFFFFF; | |
OutputMaskPtrsReg.Bits.OutputOffset = RShiftU64 (MemRegionSize - 1, 32) & 0xFFFFFFFF; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_OUTPUT_MASK_PTRS, | |
OutputMaskPtrsReg.Uint64 | |
); | |
} | |
// | |
// ToPA(Table of physical address) scheme | |
// | |
if (ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported && | |
(ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeToPA)) | |
{ | |
// | |
// Create ToPA structure aligned at 4KB for each logical thread | |
// with at least 2 entries by 8 bytes size each. The first entry | |
// should have the trace output base address in bits 47:12, 6:9 | |
// for Size, bits 4,2 and 0 must be cleared. The second entry | |
// should have the base address of the table location in bits | |
// 47:12, bits 4 and 2 must be cleared and bit 0 must be set. | |
// | |
if (FirstIn) { | |
DEBUG ((DEBUG_INFO, "ProcTrace: Enabling ToPA scheme \n")); | |
Pages = EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE)); | |
Alignment = 0x1000; | |
if (ProcTraceData->EnableOnBspOnly) { | |
// | |
// When only enable ProcTrace on BSP, this is the first and only time ProcTraceInitialize() runs. | |
// | |
TopaTableBaseAddr = (UINTN)AllocateAlignedReservedPages (Pages, Alignment); | |
if (TopaTableBaseAddr == 0) { | |
DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, failed to allocate ToPA mem for BSP")); | |
return RETURN_OUT_OF_RESOURCES; | |
} | |
DEBUG ((DEBUG_INFO, "ProcTrace: Topa table address(aligned) for BSP only: 0x%llX \n", (UINT64)TopaTableBaseAddr)); | |
} else { | |
// | |
// Let BSP allocate ToPA table mem for all threads | |
// | |
TopaMemArray = (UINTN *)AllocatePool (ProcTraceData->AllocatedThreads * sizeof (UINTN *)); | |
if (TopaMemArray == NULL) { | |
DEBUG ((DEBUG_ERROR, "ProcTrace: Allocate mem for ToPA Failed\n")); | |
return RETURN_OUT_OF_RESOURCES; | |
} | |
ProcTraceData->TopaMemArray = TopaMemArray; | |
for (Index = 0; Index < ProcTraceData->AllocatedThreads; Index++) { | |
AlignedAddress = (UINTN)AllocateAlignedReservedPages (Pages, Alignment); | |
if (AlignedAddress == 0) { | |
if (Index < ProcTraceData->AllocatedThreads) { | |
ProcTraceData->AllocatedThreads = Index; | |
} | |
DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocated ToPA mem only for %d threads\n", ProcTraceData->AllocatedThreads)); | |
if (Index == 0) { | |
// | |
// Could not allocate for BSP even | |
// | |
FreePool ((VOID *)TopaMemArray); | |
TopaMemArray = NULL; | |
return RETURN_OUT_OF_RESOURCES; | |
} | |
break; | |
} | |
TopaMemArray[Index] = AlignedAddress; | |
DEBUG ((DEBUG_INFO, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index, (UINT64)TopaMemArray[Index])); | |
} | |
DEBUG ((DEBUG_INFO, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData->AllocatedThreads)); | |
} | |
} | |
if (!ProcTraceData->EnableOnBspOnly) { | |
if (ProcessorNumber < ProcTraceData->AllocatedThreads) { | |
TopaTableBaseAddr = ProcTraceData->TopaMemArray[ProcessorNumber]; | |
} else { | |
return RETURN_SUCCESS; | |
} | |
} | |
TopaTable = (PROC_TRACE_TOPA_TABLE *)TopaTableBaseAddr; | |
TopaEntryPtr = &TopaTable->TopaEntry[0]; | |
TopaEntryPtr->Uint64 = 0; | |
TopaEntryPtr->Bits.Base = (MemRegionBaseAddr >> 12) & 0x000FFFFF; | |
TopaEntryPtr->Bits.BaseHi = RShiftU64 ((UINT64)MemRegionBaseAddr, 32) & 0xFFFFFFFF; | |
TopaEntryPtr->Bits.Size = ProcTraceData->ProcTraceMemSize; | |
TopaEntryPtr->Bits.END = 0; | |
TopaEntryPtr = &TopaTable->TopaEntry[1]; | |
TopaEntryPtr->Uint64 = 0; | |
TopaEntryPtr->Bits.Base = (TopaTableBaseAddr >> 12) & 0x000FFFFF; | |
TopaEntryPtr->Bits.BaseHi = RShiftU64 ((UINT64)TopaTableBaseAddr, 32) & 0xFFFFFFFF; | |
TopaEntryPtr->Bits.END = 1; | |
// | |
// Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with ToPA base | |
// | |
OutputBaseReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputBase.Uint64; | |
OutputBaseReg.Bits.Base = (TopaTableBaseAddr >> 7) & 0x01FFFFFF; | |
OutputBaseReg.Bits.BaseHi = RShiftU64 ((UINT64)TopaTableBaseAddr, 32) & 0xFFFFFFFF; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_OUTPUT_BASE, | |
OutputBaseReg.Uint64 | |
); | |
// | |
// Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0 | |
// | |
OutputMaskPtrsReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputMaskPtrs.Uint64; | |
OutputMaskPtrsReg.Bits.MaskOrTableOffset = 0; | |
OutputMaskPtrsReg.Bits.OutputOffset = 0; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_OUTPUT_MASK_PTRS, | |
OutputMaskPtrsReg.Uint64 | |
); | |
// | |
// Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8) | |
// | |
CtrlReg.Bits.ToPA = 1; | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_CTL, | |
CtrlReg.Uint64 | |
); | |
} | |
/// | |
/// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h) | |
/// | |
CtrlReg.Bits.OS = 1; | |
CtrlReg.Bits.User = 1; | |
CtrlReg.Bits.BranchEn = 1; | |
CtrlReg.Bits.TraceEn = 1; | |
// | |
// Generate CYC/TSC timing packets to collect performance data. | |
// | |
if (ProcTraceData->EnablePerformanceCollecting) { | |
if (ProcTraceData->ProcessorData[ProcessorNumber].CycPacketSupported) { | |
CtrlReg.Bits.CYCEn = 1; | |
CtrlReg.Bits.CYCThresh = 5; | |
} | |
// | |
// Write to TSCEn is always supported | |
// | |
CtrlReg.Bits.TSCEn = 1; | |
} | |
CPU_REGISTER_TABLE_WRITE64 ( | |
ProcessorNumber, | |
Msr, | |
MSR_IA32_RTIT_CTL, | |
CtrlReg.Uint64 | |
); | |
return RETURN_SUCCESS; | |
} |