123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- /** @file
- Intel Processor Trace feature.
- Copyright (c) 2017 - 2018, 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;
- } PROC_TRACE_PROCESSOR_DATA;
- typedef struct {
- UINT32 NumberOfProcessors;
- UINT8 ProcTraceOutputScheme;
- UINT32 ProcTraceMemSize;
- UINTN *ThreadMemRegionTable;
- UINTN AllocatedThreads;
- UINTN *TopaMemArray;
- 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);
- 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 Ecx;
- //
- // 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, NULL, &Ecx.Uint32, NULL);
- ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported = (BOOLEAN)(Ecx.Bits.RTIT == 1);
- ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported = (BOOLEAN)(Ecx.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);
- 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;
- //
- // 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;
- }
- 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.
- //
- 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++) {
- Pages = EFI_SIZE_TO_PAGES (MemRegionSize);
- Alignment = MemRegionSize;
- 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 (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"));
- //
- // 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++) {
- Pages = EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE));
- Alignment = 0x1000;
- 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 (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;
- CPU_REGISTER_TABLE_WRITE64 (
- ProcessorNumber,
- Msr,
- MSR_IA32_RTIT_CTL,
- CtrlReg.Uint64
- );
- return RETURN_SUCCESS;
- }
|