2 Intel Processor Trace feature.
4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "CpuCommonFeatures.h"
12 /// This macro define the max entries in the Topa table.
13 /// Each entry in the table contains some attribute bits, a pointer to an output region, and the size of the region.
14 /// The last entry in the table may hold a pointer to the next table. This pointer can either point to the top of the
15 /// current table (for circular array) or to the base of another table.
16 /// At least 2 entries are needed because the list of entries must
17 /// be terminated by an entry with the END bit set to 1, so 2
18 /// entries are required to use a single valid entry.
20 #define MAX_TOPA_ENTRY_COUNT 2
24 /// Processor trace output scheme selection.
27 RtitOutputSchemeSingleRange
= 0,
32 BOOLEAN TopaSupported
;
33 BOOLEAN SingleRangeSupported
;
34 MSR_IA32_RTIT_CTL_REGISTER RtitCtrl
;
35 MSR_IA32_RTIT_OUTPUT_BASE_REGISTER RtitOutputBase
;
36 MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER RtitOutputMaskPtrs
;
37 } PROC_TRACE_PROCESSOR_DATA
;
40 UINT32 NumberOfProcessors
;
42 UINT8 ProcTraceOutputScheme
;
43 UINT32 ProcTraceMemSize
;
45 UINTN
*ThreadMemRegionTable
;
46 UINTN AllocatedThreads
;
50 PROC_TRACE_PROCESSOR_DATA
*ProcessorData
;
54 RTIT_TOPA_TABLE_ENTRY TopaEntry
[MAX_TOPA_ENTRY_COUNT
];
55 } PROC_TRACE_TOPA_TABLE
;
58 Prepares for the data used by CPU feature detection and initialization.
60 @param[in] NumberOfProcessors The number of CPUs in the platform.
62 @return Pointer to a buffer of CPU related configuration data.
64 @note This service could be called by BSP only.
68 ProcTraceGetConfigData (
69 IN UINTN NumberOfProcessors
72 PROC_TRACE_DATA
*ConfigData
;
74 ConfigData
= AllocateZeroPool (sizeof (PROC_TRACE_DATA
) + sizeof (PROC_TRACE_PROCESSOR_DATA
) * NumberOfProcessors
);
75 ASSERT (ConfigData
!= NULL
);
76 ConfigData
->ProcessorData
= (PROC_TRACE_PROCESSOR_DATA
*) ((UINT8
*) ConfigData
+ sizeof (PROC_TRACE_DATA
));
78 ConfigData
->NumberOfProcessors
= (UINT32
) NumberOfProcessors
;
79 ConfigData
->ProcTraceMemSize
= PcdGet32 (PcdCpuProcTraceMemSize
);
80 ConfigData
->ProcTraceOutputScheme
= PcdGet8 (PcdCpuProcTraceOutputScheme
);
86 Detects if Intel Processor Trace feature supported on current
89 @param[in] ProcessorNumber The index of the CPU executing this function.
90 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
91 structure for the CPU executing this function.
92 @param[in] ConfigData A pointer to the configuration buffer returned
93 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
94 CPU_FEATURE_GET_CONFIG_DATA was not provided in
97 @retval TRUE Processor Trace feature is supported.
98 @retval FALSE Processor Trace feature is not supported.
100 @note This service could be called by BSP/APs.
105 IN UINTN ProcessorNumber
,
106 IN REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
,
107 IN VOID
*ConfigData OPTIONAL
110 PROC_TRACE_DATA
*ProcTraceData
;
111 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx
;
112 CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx
;
115 // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)
117 ProcTraceData
= (PROC_TRACE_DATA
*) ConfigData
;
118 ASSERT (ProcTraceData
!= NULL
);
119 if ((ProcTraceData
->ProcTraceMemSize
> RtitTopaMemorySize128M
) ||
120 (ProcTraceData
->ProcTraceOutputScheme
> RtitOutputSchemeToPA
)) {
125 // Check if Processor Trace is supported
127 AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS
, 0, NULL
, &Ebx
.Uint32
, NULL
, NULL
);
128 if (Ebx
.Bits
.IntelProcessorTrace
== 0) {
132 AsmCpuidEx (CPUID_INTEL_PROCESSOR_TRACE
, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF
, NULL
, NULL
, &Ecx
.Uint32
, NULL
);
133 ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
= (BOOLEAN
) (Ecx
.Bits
.RTIT
== 1);
134 ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
= (BOOLEAN
) (Ecx
.Bits
.SingleRangeOutput
== 1);
135 if ((ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
&& (ProcTraceData
->ProcTraceOutputScheme
== RtitOutputSchemeToPA
)) ||
136 (ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
&& (ProcTraceData
->ProcTraceOutputScheme
== RtitOutputSchemeSingleRange
))) {
137 ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitCtrl
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
138 ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitOutputBase
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_OUTPUT_BASE
);
139 ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitOutputMaskPtrs
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_OUTPUT_MASK_PTRS
);
147 Initializes Intel Processor Trace feature to specific state.
149 @param[in] ProcessorNumber The index of the CPU executing this function.
150 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
151 structure for the CPU executing this function.
152 @param[in] ConfigData A pointer to the configuration buffer returned
153 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
154 CPU_FEATURE_GET_CONFIG_DATA was not provided in
155 RegisterCpuFeature().
156 @param[in] State If TRUE, then the Processor Trace feature must be
158 If FALSE, then the Processor Trace feature must be
161 @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
166 ProcTraceInitialize (
167 IN UINTN ProcessorNumber
,
168 IN REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
,
169 IN VOID
*ConfigData
, OPTIONAL
173 UINT32 MemRegionSize
;
176 UINTN MemRegionBaseAddr
;
177 UINTN
*ThreadMemRegionTable
;
179 UINTN TopaTableBaseAddr
;
180 UINTN AlignedAddress
;
182 PROC_TRACE_TOPA_TABLE
*TopaTable
;
183 PROC_TRACE_DATA
*ProcTraceData
;
185 MSR_IA32_RTIT_CTL_REGISTER CtrlReg
;
186 MSR_IA32_RTIT_STATUS_REGISTER StatusReg
;
187 MSR_IA32_RTIT_OUTPUT_BASE_REGISTER OutputBaseReg
;
188 MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER OutputMaskPtrsReg
;
189 RTIT_TOPA_TABLE_ENTRY
*TopaEntryPtr
;
192 // The scope of the MSR_IA32_RTIT_* is core for below processor type, only program
193 // MSR_IA32_RTIT_* for thread 0 in each core.
195 if (IS_GOLDMONT_PROCESSOR (CpuInfo
->DisplayFamily
, CpuInfo
->DisplayModel
) ||
196 IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo
->DisplayFamily
, CpuInfo
->DisplayModel
)) {
197 if (CpuInfo
->ProcessorInfo
.Location
.Thread
!= 0) {
198 return RETURN_SUCCESS
;
202 ProcTraceData
= (PROC_TRACE_DATA
*) ConfigData
;
203 ASSERT (ProcTraceData
!= NULL
);
206 // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b
208 CtrlReg
.Uint64
= ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitCtrl
.Uint64
;
209 if (CtrlReg
.Bits
.TraceEn
!= 0) {
211 /// Clear bit 0 in MSR IA32_RTIT_CTL (570)
213 CtrlReg
.Bits
.TraceEn
= 0;
214 CPU_REGISTER_TABLE_WRITE64 (
222 /// Clear MSR IA32_RTIT_STS (571h) to all zeros
224 StatusReg
.Uint64
= 0x0;
225 CPU_REGISTER_TABLE_WRITE64 (
228 MSR_IA32_RTIT_STATUS
,
234 return RETURN_SUCCESS
;
237 MemRegionBaseAddr
= 0;
240 if (ProcTraceData
->ThreadMemRegionTable
== NULL
) {
242 DEBUG ((DEBUG_INFO
, "Initialize Processor Trace\n"));
246 /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding
248 MemRegionSize
= (UINT32
) (1 << (ProcTraceData
->ProcTraceMemSize
+ 12));
250 DEBUG ((DEBUG_INFO
, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize
));
255 // Let BSP allocate and create the necessary memory region (Aligned to the size of
256 // the memory region from setup option(ProcTraceMemSize) which is an integral multiple of 4kB)
257 // for all the enabled threads to store Processor Trace debug data. Then Configure the trace
258 // address base in MSR, IA32_RTIT_OUTPUT_BASE (560h) bits 47:12. Note that all regions must be
259 // aligned based on their size, not just 4K. Thus a 2M region must have bits 20:12 cleared.
261 ThreadMemRegionTable
= (UINTN
*) AllocatePool (ProcTraceData
->NumberOfProcessors
* sizeof (UINTN
*));
262 if (ThreadMemRegionTable
== NULL
) {
263 DEBUG ((DEBUG_ERROR
, "Allocate ProcTrace ThreadMemRegionTable Failed\n"));
264 return RETURN_OUT_OF_RESOURCES
;
266 ProcTraceData
->ThreadMemRegionTable
= ThreadMemRegionTable
;
268 for (Index
= 0; Index
< ProcTraceData
->NumberOfProcessors
; Index
++, ProcTraceData
->AllocatedThreads
++) {
269 Pages
= EFI_SIZE_TO_PAGES (MemRegionSize
);
270 Alignment
= MemRegionSize
;
271 AlignedAddress
= (UINTN
) AllocateAlignedReservedPages (Pages
, Alignment
);
272 if (AlignedAddress
== 0) {
273 DEBUG ((DEBUG_ERROR
, "ProcTrace: Out of mem, allocated only for %d threads\n", ProcTraceData
->AllocatedThreads
));
276 // Could not allocate for BSP even
278 FreePool ((VOID
*) ThreadMemRegionTable
);
279 ThreadMemRegionTable
= NULL
;
280 return RETURN_OUT_OF_RESOURCES
;
285 ThreadMemRegionTable
[Index
] = AlignedAddress
;
286 DEBUG ((DEBUG_INFO
, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index
, (UINT64
) ThreadMemRegionTable
[Index
]));
289 DEBUG ((DEBUG_INFO
, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData
->AllocatedThreads
));
292 if (ProcessorNumber
< ProcTraceData
->AllocatedThreads
) {
293 MemRegionBaseAddr
= ProcTraceData
->ThreadMemRegionTable
[ProcessorNumber
];
295 return RETURN_SUCCESS
;
299 /// Check Processor Trace output scheme: Single Range output or ToPA table
303 // Single Range output scheme
305 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
&&
306 (ProcTraceData
->ProcTraceOutputScheme
== RtitOutputSchemeSingleRange
)) {
308 DEBUG ((DEBUG_INFO
, "ProcTrace: Enabling Single Range Output scheme \n"));
312 // Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
314 CtrlReg
.Bits
.ToPA
= 0;
315 CPU_REGISTER_TABLE_WRITE64 (
323 // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with the allocated Memory Region
325 OutputBaseReg
.Uint64
= ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitOutputBase
.Uint64
;
326 OutputBaseReg
.Bits
.Base
= (MemRegionBaseAddr
>> 7) & 0x01FFFFFF;
327 OutputBaseReg
.Bits
.BaseHi
= RShiftU64 ((UINT64
) MemRegionBaseAddr
, 32) & 0xFFFFFFFF;
328 CPU_REGISTER_TABLE_WRITE64 (
331 MSR_IA32_RTIT_OUTPUT_BASE
,
336 // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)
338 OutputMaskPtrsReg
.Uint64
= ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitOutputMaskPtrs
.Uint64
;
339 OutputMaskPtrsReg
.Bits
.MaskOrTableOffset
= ((MemRegionSize
- 1) >> 7) & 0x01FFFFFF;
340 OutputMaskPtrsReg
.Bits
.OutputOffset
= RShiftU64 (MemRegionSize
- 1, 32) & 0xFFFFFFFF;
341 CPU_REGISTER_TABLE_WRITE64 (
344 MSR_IA32_RTIT_OUTPUT_MASK_PTRS
,
345 OutputMaskPtrsReg
.Uint64
350 // ToPA(Table of physical address) scheme
352 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
&&
353 (ProcTraceData
->ProcTraceOutputScheme
== RtitOutputSchemeToPA
)) {
355 // Create ToPA structure aligned at 4KB for each logical thread
356 // with at least 2 entries by 8 bytes size each. The first entry
357 // should have the trace output base address in bits 47:12, 6:9
358 // for Size, bits 4,2 and 0 must be cleared. The second entry
359 // should have the base address of the table location in bits
360 // 47:12, bits 4 and 2 must be cleared and bit 0 must be set.
363 DEBUG ((DEBUG_INFO
, "ProcTrace: Enabling ToPA scheme \n"));
365 // Let BSP allocate ToPA table mem for all threads
367 TopaMemArray
= (UINTN
*) AllocatePool (ProcTraceData
->AllocatedThreads
* sizeof (UINTN
*));
368 if (TopaMemArray
== NULL
) {
369 DEBUG ((DEBUG_ERROR
, "ProcTrace: Allocate mem for ToPA Failed\n"));
370 return RETURN_OUT_OF_RESOURCES
;
372 ProcTraceData
->TopaMemArray
= TopaMemArray
;
374 for (Index
= 0; Index
< ProcTraceData
->AllocatedThreads
; Index
++) {
375 Pages
= EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE
));
377 AlignedAddress
= (UINTN
) AllocateAlignedReservedPages (Pages
, Alignment
);
378 if (AlignedAddress
== 0) {
379 if (Index
< ProcTraceData
->AllocatedThreads
) {
380 ProcTraceData
->AllocatedThreads
= Index
;
382 DEBUG ((DEBUG_ERROR
, "ProcTrace: Out of mem, allocated ToPA mem only for %d threads\n", ProcTraceData
->AllocatedThreads
));
385 // Could not allocate for BSP even
387 FreePool ((VOID
*) TopaMemArray
);
389 return RETURN_OUT_OF_RESOURCES
;
394 TopaMemArray
[Index
] = AlignedAddress
;
395 DEBUG ((DEBUG_INFO
, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index
, (UINT64
) TopaMemArray
[Index
]));
398 DEBUG ((DEBUG_INFO
, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData
->AllocatedThreads
));
401 if (ProcessorNumber
< ProcTraceData
->AllocatedThreads
) {
402 TopaTableBaseAddr
= ProcTraceData
->TopaMemArray
[ProcessorNumber
];
404 return RETURN_SUCCESS
;
407 TopaTable
= (PROC_TRACE_TOPA_TABLE
*) TopaTableBaseAddr
;
408 TopaEntryPtr
= &TopaTable
->TopaEntry
[0];
409 TopaEntryPtr
->Uint64
= 0;
410 TopaEntryPtr
->Bits
.Base
= (MemRegionBaseAddr
>> 12) & 0x000FFFFF;
411 TopaEntryPtr
->Bits
.BaseHi
= RShiftU64 ((UINT64
) MemRegionBaseAddr
, 32) & 0xFFFFFFFF;
412 TopaEntryPtr
->Bits
.Size
= ProcTraceData
->ProcTraceMemSize
;
413 TopaEntryPtr
->Bits
.END
= 0;
415 TopaEntryPtr
= &TopaTable
->TopaEntry
[1];
416 TopaEntryPtr
->Uint64
= 0;
417 TopaEntryPtr
->Bits
.Base
= (TopaTableBaseAddr
>> 12) & 0x000FFFFF;
418 TopaEntryPtr
->Bits
.BaseHi
= RShiftU64 ((UINT64
) TopaTableBaseAddr
, 32) & 0xFFFFFFFF;
419 TopaEntryPtr
->Bits
.END
= 1;
422 // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with ToPA base
424 OutputBaseReg
.Uint64
= ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitOutputBase
.Uint64
;
425 OutputBaseReg
.Bits
.Base
= (TopaTableBaseAddr
>> 7) & 0x01FFFFFF;
426 OutputBaseReg
.Bits
.BaseHi
= RShiftU64 ((UINT64
) TopaTableBaseAddr
, 32) & 0xFFFFFFFF;
427 CPU_REGISTER_TABLE_WRITE64 (
430 MSR_IA32_RTIT_OUTPUT_BASE
,
435 // Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0
437 OutputMaskPtrsReg
.Uint64
= ProcTraceData
->ProcessorData
[ProcessorNumber
].RtitOutputMaskPtrs
.Uint64
;
438 OutputMaskPtrsReg
.Bits
.MaskOrTableOffset
= 0;
439 OutputMaskPtrsReg
.Bits
.OutputOffset
= 0;
440 CPU_REGISTER_TABLE_WRITE64 (
443 MSR_IA32_RTIT_OUTPUT_MASK_PTRS
,
444 OutputMaskPtrsReg
.Uint64
447 // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
449 CtrlReg
.Bits
.ToPA
= 1;
450 CPU_REGISTER_TABLE_WRITE64 (
459 /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)
462 CtrlReg
.Bits
.User
= 1;
463 CtrlReg
.Bits
.BranchEn
= 1;
464 CtrlReg
.Bits
.TraceEn
= 1;
465 CPU_REGISTER_TABLE_WRITE64 (
472 return RETURN_SUCCESS
;