2 Intel Processor Trace feature.
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "CpuCommonFeatures.h"
18 /// This macro define the max entries in the Topa table.
19 /// Each entry in the table contains some attribute bits, a pointer to an output region, and the size of the region.
20 /// The last entry in the table may hold a pointer to the next table. This pointer can either point to the top of the
21 /// current table (for circular array) or to the base of another table.
22 /// At least 2 entries are needed because the list of entries must
23 /// be terminated by an entry with the END bit set to 1, so 2
24 /// entries are required to use a single valid entry.
26 #define MAX_TOPA_ENTRY_COUNT 2
30 /// Processor trace output scheme selection.
33 OutputSchemeSingleRange
= 0,
36 } PROC_TRACE_OUTPUT_SCHEME
;
39 BOOLEAN ProcTraceSupported
;
40 BOOLEAN TopaSupported
;
41 BOOLEAN SingleRangeSupported
;
42 } PROC_TRACE_PROCESSOR_DATA
;
45 UINT32 NumberOfProcessors
;
47 UINT8 ProcTraceOutputScheme
;
48 UINT32 ProcTraceMemSize
;
50 UINTN
*ThreadMemRegionTable
;
51 UINTN AllocatedThreads
;
54 UINTN TopaMemArrayCount
;
56 PROC_TRACE_PROCESSOR_DATA
*ProcessorData
;
60 RTIT_TOPA_TABLE_ENTRY TopaEntry
[MAX_TOPA_ENTRY_COUNT
];
61 } PROC_TRACE_TOPA_TABLE
;
64 Prepares for the data used by CPU feature detection and initialization.
66 @param[in] NumberOfProcessors The number of CPUs in the platform.
68 @return Pointer to a buffer of CPU related configuration data.
70 @note This service could be called by BSP only.
74 ProcTraceGetConfigData (
75 IN UINTN NumberOfProcessors
78 PROC_TRACE_DATA
*ConfigData
;
80 ConfigData
= AllocateZeroPool (sizeof (PROC_TRACE_DATA
) + sizeof (PROC_TRACE_PROCESSOR_DATA
) * NumberOfProcessors
);
81 ASSERT (ConfigData
!= NULL
);
82 ConfigData
->ProcessorData
= (PROC_TRACE_PROCESSOR_DATA
*) ((UINT8
*) ConfigData
+ sizeof (PROC_TRACE_DATA
));
84 ConfigData
->NumberOfProcessors
= (UINT32
) NumberOfProcessors
;
85 ConfigData
->ProcTraceMemSize
= PcdGet32 (PcdCpuProcTraceMemSize
);
86 ConfigData
->ProcTraceOutputScheme
= PcdGet8 (PcdCpuProcTraceOutputScheme
);
92 Detects if Intel Processor Trace feature supported on current
95 @param[in] ProcessorNumber The index of the CPU executing this function.
96 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
97 structure for the CPU executing this function.
98 @param[in] ConfigData A pointer to the configuration buffer returned
99 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
100 CPU_FEATURE_GET_CONFIG_DATA was not provided in
101 RegisterCpuFeature().
103 @retval TRUE Processor Trace feature is supported.
104 @retval FALSE Processor Trace feature is not supported.
106 @note This service could be called by BSP/APs.
111 IN UINTN ProcessorNumber
,
112 IN REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
,
113 IN VOID
*ConfigData OPTIONAL
116 PROC_TRACE_DATA
*ProcTraceData
;
117 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx
;
118 CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx
;
121 // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)
123 ProcTraceData
= (PROC_TRACE_DATA
*) ConfigData
;
124 if ((ProcTraceData
->ProcTraceMemSize
> RtitTopaMemorySize128M
) ||
125 (ProcTraceData
->ProcTraceOutputScheme
> ProcTraceOutputSchemeToPA
)) {
130 // Check if Processor Trace is supported
132 AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS
, 0, NULL
, &Ebx
.Uint32
, NULL
, NULL
);
133 ProcTraceData
->ProcessorData
[ProcessorNumber
].ProcTraceSupported
= (BOOLEAN
) (Ebx
.Bits
.IntelProcessorTrace
== 1);
134 if (!ProcTraceData
->ProcessorData
[ProcessorNumber
].ProcTraceSupported
) {
138 AsmCpuidEx (CPUID_INTEL_PROCESSOR_TRACE
, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF
, NULL
, NULL
, &Ecx
.Uint32
, NULL
);
139 ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
= (BOOLEAN
) (Ecx
.Bits
.RTIT
== 1);
140 ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
= (BOOLEAN
) (Ecx
.Bits
.SingleRangeOutput
== 1);
141 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
||
142 ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
) {
150 Initializes Intel Processor Trace feature to specific state.
152 @param[in] ProcessorNumber The index of the CPU executing this function.
153 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
154 structure for the CPU executing this function.
155 @param[in] ConfigData A pointer to the configuration buffer returned
156 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
157 CPU_FEATURE_GET_CONFIG_DATA was not provided in
158 RegisterCpuFeature().
159 @param[in] State If TRUE, then the Processor Trace feature must be
161 If FALSE, then the Processor Trace feature must be
164 @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
169 ProcTraceInitialize (
170 IN UINTN ProcessorNumber
,
171 IN REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
,
172 IN VOID
*ConfigData
, OPTIONAL
176 UINT32 MemRegionSize
;
179 UINTN MemRegionBaseAddr
;
180 UINTN
*ThreadMemRegionTable
;
182 UINTN TopaTableBaseAddr
;
183 UINTN AlignedAddress
;
185 PROC_TRACE_TOPA_TABLE
*TopaTable
;
186 PROC_TRACE_DATA
*ProcTraceData
;
188 MSR_IA32_RTIT_CTL_REGISTER CtrlReg
;
189 MSR_IA32_RTIT_STATUS_REGISTER StatusReg
;
190 MSR_IA32_RTIT_OUTPUT_BASE_REGISTER OutputBaseReg
;
191 MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER OutputMaskPtrsReg
;
192 RTIT_TOPA_TABLE_ENTRY
*TopaEntryPtr
;
194 ProcTraceData
= (PROC_TRACE_DATA
*) ConfigData
;
196 MemRegionBaseAddr
= 0;
199 if (ProcTraceData
->ThreadMemRegionTable
== NULL
) {
201 DEBUG ((DEBUG_INFO
, "Initialize Processor Trace\n"));
205 /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding
207 MemRegionSize
= (UINT32
) (1 << (ProcTraceData
->ProcTraceMemSize
+ 12));
209 DEBUG ((DEBUG_INFO
, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize
));
213 // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b
215 CtrlReg
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
216 if (CtrlReg
.Bits
.TraceEn
!= 0) {
218 /// Clear bit 0 in MSR IA32_RTIT_CTL (570)
220 CtrlReg
.Bits
.TraceEn
= 0;
221 CPU_REGISTER_TABLE_WRITE64 (
229 /// Clear MSR IA32_RTIT_STS (571h) to all zeros
231 StatusReg
.Uint64
= 0x0;
232 CPU_REGISTER_TABLE_WRITE64 (
235 MSR_IA32_RTIT_STATUS
,
242 // Let BSP allocate and create the necessary memory region (Aligned to the size of
243 // the memory region from setup option(ProcTraceMemSize) which is an integral multiple of 4kB)
244 // for the all the enabled threads for storing Processor Trace debug data. Then Configure the trace
245 // address base in MSR, IA32_RTIT_OUTPUT_BASE (560h) bits 47:12. Note that all regions must be
246 // aligned based on their size, not just 4K. Thus a 2M region must have bits 20:12 clear.
248 ThreadMemRegionTable
= (UINTN
*) AllocatePool (ProcTraceData
->NumberOfProcessors
* sizeof (UINTN
*));
249 if (ThreadMemRegionTable
== NULL
) {
250 DEBUG ((DEBUG_ERROR
, "Allocate ProcTrace ThreadMemRegionTable Failed\n"));
251 return RETURN_OUT_OF_RESOURCES
;
253 ProcTraceData
->ThreadMemRegionTable
= ThreadMemRegionTable
;
255 for (Index
= 0; Index
< ProcTraceData
->NumberOfProcessors
; Index
++, ProcTraceData
->AllocatedThreads
++) {
256 Pages
= EFI_SIZE_TO_PAGES (MemRegionSize
);
257 Alignment
= MemRegionSize
;
258 AlignedAddress
= (UINTN
) AllocateAlignedReservedPages (Pages
, Alignment
);
259 if (AlignedAddress
== 0) {
260 DEBUG ((DEBUG_ERROR
, "ProcTrace: Out of mem, allocated only for %d threads\n", ProcTraceData
->AllocatedThreads
));
263 // Could not allocate for BSP even
265 FreePool ((VOID
*) ThreadMemRegionTable
);
266 ThreadMemRegionTable
= NULL
;
267 return RETURN_OUT_OF_RESOURCES
;
272 ThreadMemRegionTable
[Index
] = AlignedAddress
;
273 DEBUG ((DEBUG_INFO
, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index
, (UINT64
) ThreadMemRegionTable
[Index
]));
276 DEBUG ((DEBUG_INFO
, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData
->AllocatedThreads
));
277 MemRegionBaseAddr
= ThreadMemRegionTable
[0];
279 if (ProcessorNumber
< ProcTraceData
->AllocatedThreads
) {
280 MemRegionBaseAddr
= ProcTraceData
->ThreadMemRegionTable
[ProcessorNumber
];
282 return RETURN_SUCCESS
;
287 /// Check Processor Trace output scheme: Single Range output or ToPA table
291 // Single Range output scheme
293 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
&&
294 (ProcTraceData
->ProcTraceOutputScheme
== OutputSchemeSingleRange
)) {
296 DEBUG ((DEBUG_INFO
, "ProcTrace: Enabling Single Range Output scheme \n"));
300 // Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
302 CtrlReg
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
303 CtrlReg
.Bits
.ToPA
= 0;
304 CPU_REGISTER_TABLE_WRITE64 (
312 // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with the allocated Memory Region
314 OutputBaseReg
.Bits
.Base
= (MemRegionBaseAddr
>> 7) & 0x01FFFFFF;
315 OutputBaseReg
.Bits
.BaseHi
= RShiftU64 ((UINT64
) MemRegionBaseAddr
, 32) & 0xFFFFFFFF;
316 CPU_REGISTER_TABLE_WRITE64 (
319 MSR_IA32_RTIT_OUTPUT_BASE
,
324 // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)
326 OutputMaskPtrsReg
.Bits
.MaskOrTableOffset
= ((MemRegionSize
- 1) >> 7) & 0x01FFFFFF;
327 OutputMaskPtrsReg
.Bits
.OutputOffset
= RShiftU64 ((UINT64
) (MemRegionSize
- 1), 32) & 0xFFFFFFFF;
328 CPU_REGISTER_TABLE_WRITE64 (
331 MSR_IA32_RTIT_OUTPUT_MASK_PTRS
,
332 OutputMaskPtrsReg
.Uint64
337 // ToPA(Table of physical address) scheme
339 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
&&
340 (ProcTraceData
->ProcTraceOutputScheme
== OutputSchemeToPA
)) {
342 // Create ToPA structure aligned at 4KB for each logical thread
343 // with at least 2 entries by 8 bytes size each. The first entry
344 // should have the trace output base address in bits 47:12, 6:9
345 // for Size, bits 4,2 and 0 must be cleared. The second entry
346 // should have the base address of the table location in bits
347 // 47:12, bits 4 and 2 must be cleared and bit 0 must be set.
350 DEBUG ((DEBUG_INFO
, "ProcTrace: Enabling ToPA scheme \n"));
352 // Let BSP allocate ToPA table mem for all threads
354 TopaMemArray
= (UINTN
*) AllocatePool (ProcTraceData
->AllocatedThreads
* sizeof (UINTN
*));
355 if (TopaMemArray
== NULL
) {
356 DEBUG ((DEBUG_ERROR
, "ProcTrace: Allocate mem for ToPA Failed\n"));
357 return RETURN_OUT_OF_RESOURCES
;
359 ProcTraceData
->TopaMemArray
= TopaMemArray
;
361 for (Index
= 0; Index
< ProcTraceData
->AllocatedThreads
; Index
++) {
362 Pages
= EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE
));
364 AlignedAddress
= (UINTN
) AllocateAlignedReservedPages (Pages
, Alignment
);
365 if (AlignedAddress
== 0) {
366 if (Index
< ProcTraceData
->AllocatedThreads
) {
367 ProcTraceData
->AllocatedThreads
= Index
;
369 DEBUG ((DEBUG_ERROR
, "ProcTrace: Out of mem, allocating ToPA mem only for %d threads\n", ProcTraceData
->AllocatedThreads
));
372 // Could not allocate for BSP
374 FreePool ((VOID
*) TopaMemArray
);
376 return RETURN_OUT_OF_RESOURCES
;
381 TopaMemArray
[Index
] = AlignedAddress
;
382 DEBUG ((DEBUG_INFO
, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index
, (UINT64
) TopaMemArray
[Index
]));
385 DEBUG ((DEBUG_INFO
, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData
->AllocatedThreads
));
387 // BSP gets the first block
389 TopaTableBaseAddr
= TopaMemArray
[0];
392 // Count for currently executing AP.
394 if (ProcessorNumber
< ProcTraceData
->AllocatedThreads
) {
395 TopaTableBaseAddr
= ProcTraceData
->TopaMemArray
[ProcessorNumber
];
397 return RETURN_SUCCESS
;
401 TopaTable
= (PROC_TRACE_TOPA_TABLE
*) TopaTableBaseAddr
;
402 TopaEntryPtr
= &TopaTable
->TopaEntry
[0];
403 TopaEntryPtr
->Bits
.Base
= (MemRegionBaseAddr
>> 12) & 0x000FFFFF;
404 TopaEntryPtr
->Bits
.BaseHi
= RShiftU64 ((UINT64
) MemRegionBaseAddr
, 32) & 0xFFFFFFFF;
405 TopaEntryPtr
->Bits
.Size
= ProcTraceData
->ProcTraceMemSize
;
406 TopaEntryPtr
->Bits
.END
= 0;
408 TopaEntryPtr
= &TopaTable
->TopaEntry
[1];
409 TopaEntryPtr
->Bits
.Base
= (TopaTableBaseAddr
>> 12) & 0x000FFFFF;
410 TopaEntryPtr
->Bits
.BaseHi
= RShiftU64 ((UINT64
) TopaTableBaseAddr
, 32) & 0xFFFFFFFF;
411 TopaEntryPtr
->Bits
.END
= 1;
414 // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with ToPA base
416 OutputBaseReg
.Bits
.Base
= (TopaTableBaseAddr
>> 7) & 0x01FFFFFF;
417 OutputBaseReg
.Bits
.BaseHi
= RShiftU64 ((UINT64
) TopaTableBaseAddr
, 32) & 0xFFFFFFFF;
418 CPU_REGISTER_TABLE_WRITE64 (
421 MSR_IA32_RTIT_OUTPUT_BASE
,
426 // Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0
428 OutputMaskPtrsReg
.Bits
.MaskOrTableOffset
= 0;
429 OutputMaskPtrsReg
.Bits
.OutputOffset
= 0;
430 CPU_REGISTER_TABLE_WRITE64 (
433 MSR_IA32_RTIT_OUTPUT_MASK_PTRS
,
434 OutputMaskPtrsReg
.Uint64
437 // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
439 CtrlReg
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
440 CtrlReg
.Bits
.ToPA
= 1;
441 CPU_REGISTER_TABLE_WRITE64 (
450 /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)
452 CtrlReg
.Uint64
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
454 CtrlReg
.Bits
.User
= 1;
455 CtrlReg
.Bits
.BranchEn
= 1;
457 CtrlReg
.Bits
.TraceEn
= 0;
459 CtrlReg
.Bits
.TraceEn
= 1;
461 CPU_REGISTER_TABLE_WRITE64 (
468 return RETURN_SUCCESS
;