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"
17 #define MAX_TOPA_ENTRY_COUNT 2
20 /// Processor trace buffer size selection.
39 EnumProcTraceMemDisable
40 } PROC_TRACE_MEM_SIZE
;
43 /// Processor trace output scheme selection.
46 OutputSchemeSingleRange
= 0,
49 } PROC_TRACE_OUTPUT_SCHEME
;
52 BOOLEAN ProcTraceSupported
;
53 BOOLEAN TopaSupported
;
54 BOOLEAN SingleRangeSupported
;
55 } PROC_TRACE_PROCESSOR_DATA
;
58 UINT32 NumberOfProcessors
;
60 UINT8 ProcTraceOutputScheme
;
61 UINT32 ProcTraceMemSize
;
63 UINTN
*ThreadMemRegionTable
;
64 UINTN AllocatedThreads
;
67 UINTN TopaMemArrayCount
;
69 PROC_TRACE_PROCESSOR_DATA
*ProcessorData
;
73 UINT64 TopaEntry
[MAX_TOPA_ENTRY_COUNT
];
74 } PROC_TRACE_TOPA_TABLE
;
77 Prepares for the data used by CPU feature detection and initialization.
79 @param[in] NumberOfProcessors The number of CPUs in the platform.
81 @return Pointer to a buffer of CPU related configuration data.
83 @note This service could be called by BSP only.
87 ProcTraceGetConfigData (
88 IN UINTN NumberOfProcessors
91 PROC_TRACE_DATA
*ConfigData
;
93 ConfigData
= AllocateZeroPool (sizeof (PROC_TRACE_DATA
) + sizeof (PROC_TRACE_PROCESSOR_DATA
) * NumberOfProcessors
);
94 ASSERT (ConfigData
!= NULL
);
95 ConfigData
->ProcessorData
= (PROC_TRACE_PROCESSOR_DATA
*) ((UINT8
*) ConfigData
+ sizeof (PROC_TRACE_DATA
));
97 ConfigData
->NumberOfProcessors
= (UINT32
) NumberOfProcessors
;
98 ConfigData
->ProcTraceMemSize
= PcdGet32 (PcdCpuProcTraceMemSize
);
99 ConfigData
->ProcTraceOutputScheme
= PcdGet8 (PcdCpuProcTraceOutputScheme
);
105 Detects if Intel Processor Trace feature supported on current
108 @param[in] ProcessorNumber The index of the CPU executing this function.
109 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
110 structure for the CPU executing this function.
111 @param[in] ConfigData A pointer to the configuration buffer returned
112 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
113 CPU_FEATURE_GET_CONFIG_DATA was not provided in
114 RegisterCpuFeature().
116 @retval TRUE Processor Trace feature is supported.
117 @retval FALSE Processor Trace feature is not supported.
119 @note This service could be called by BSP/APs.
124 IN UINTN ProcessorNumber
,
125 IN REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
,
126 IN VOID
*ConfigData OPTIONAL
129 PROC_TRACE_DATA
*ProcTraceData
;
130 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx
;
131 CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx
;
134 // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)
136 ProcTraceData
= (PROC_TRACE_DATA
*) ConfigData
;
137 if ((ProcTraceData
->ProcTraceMemSize
>= EnumProcTraceMemDisable
) ||
138 (ProcTraceData
->ProcTraceOutputScheme
>= OutputSchemeInvalid
)) {
143 // Check if Processor Trace is supported
145 AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS
, 0, NULL
, &Ebx
.Uint32
, NULL
, NULL
);
146 ProcTraceData
->ProcessorData
[ProcessorNumber
].ProcTraceSupported
= (BOOLEAN
) (Ebx
.Bits
.IntelProcessorTrace
== 1);
147 if (!ProcTraceData
->ProcessorData
[ProcessorNumber
].ProcTraceSupported
) {
151 AsmCpuidEx (CPUID_INTEL_PROCESSOR_TRACE
, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF
, NULL
, NULL
, &Ecx
.Uint32
, NULL
);
152 ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
= (BOOLEAN
) (Ecx
.Bits
.RTIT
== 1);
153 ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
= (BOOLEAN
) (Ecx
.Bits
.SingleRangeOutput
== 1);
154 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
||
155 ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
) {
163 Initializes Intel Processor Trace feature to specific state.
165 @param[in] ProcessorNumber The index of the CPU executing this function.
166 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
167 structure for the CPU executing this function.
168 @param[in] ConfigData A pointer to the configuration buffer returned
169 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
170 CPU_FEATURE_GET_CONFIG_DATA was not provided in
171 RegisterCpuFeature().
172 @param[in] State If TRUE, then the Processor Trace feature must be
174 If FALSE, then the Processor Trace feature must be
177 @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
182 ProcTraceInitialize (
183 IN UINTN ProcessorNumber
,
184 IN REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
,
185 IN VOID
*ConfigData
, OPTIONAL
190 UINT32 MemRegionSize
;
193 UINTN MemRegionBaseAddr
;
194 UINTN
*ThreadMemRegionTable
;
196 UINTN TopaTableBaseAddr
;
197 UINTN AlignedAddress
;
199 PROC_TRACE_TOPA_TABLE
*TopaTable
;
200 PROC_TRACE_DATA
*ProcTraceData
;
203 ProcTraceData
= (PROC_TRACE_DATA
*) ConfigData
;
205 MemRegionBaseAddr
= 0;
208 if (ProcTraceData
->ThreadMemRegionTable
== NULL
) {
210 DEBUG ((DEBUG_INFO
, "Initialize Processor Trace\n"));
214 /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding
216 MemRegionSize
= (UINT32
) (1 << (ProcTraceData
->ProcTraceMemSize
+ 12));
218 DEBUG ((DEBUG_INFO
, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize
));
222 // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b
224 MsrValue
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
225 if ((MsrValue
& BIT0
) != 0) {
227 /// Clear bit 0 in MSR IA32_RTIT_CTL (570)
229 MsrValue
&= (UINT64
) ~BIT0
;
230 CPU_REGISTER_TABLE_WRITE64 (
238 /// Clear MSR IA32_RTIT_STS (571h) to all zeros
240 MsrValue
= AsmReadMsr64 (MSR_IA32_RTIT_STATUS
);
242 CPU_REGISTER_TABLE_WRITE64 (
245 MSR_IA32_RTIT_STATUS
,
252 // Let BSP allocate and create the necessary memory region (Aligned to the size of
253 // the memory region from setup option(ProcTraceMemSize) which is an integral multiple of 4kB)
254 // for the all the enabled threads for storing Processor Trace debug data. Then Configure the trace
255 // address base in MSR, IA32_RTIT_OUTPUT_BASE (560h) bits 47:12. Note that all regions must be
256 // aligned based on their size, not just 4K. Thus a 2M region must have bits 20:12 clear.
258 ThreadMemRegionTable
= (UINTN
*) AllocatePool (ProcTraceData
->NumberOfProcessors
* sizeof (UINTN
*));
259 if (ThreadMemRegionTable
== NULL
) {
260 DEBUG ((DEBUG_ERROR
, "Allocate ProcTrace ThreadMemRegionTable Failed\n"));
261 return RETURN_OUT_OF_RESOURCES
;
263 ProcTraceData
->ThreadMemRegionTable
= ThreadMemRegionTable
;
265 for (Index
= 0; Index
< ProcTraceData
->NumberOfProcessors
; Index
++, ProcTraceData
->AllocatedThreads
++) {
266 Pages
= EFI_SIZE_TO_PAGES (MemRegionSize
);
267 Alignment
= MemRegionSize
;
268 AlignedAddress
= (UINTN
) AllocateAlignedReservedPages (Pages
, Alignment
);
269 if (AlignedAddress
== 0) {
270 DEBUG ((DEBUG_ERROR
, "ProcTrace: Out of mem, allocated only for %d threads\n", ProcTraceData
->AllocatedThreads
));
273 // Could not allocate for BSP even
275 FreePool ((VOID
*) ThreadMemRegionTable
);
276 ThreadMemRegionTable
= NULL
;
277 return RETURN_OUT_OF_RESOURCES
;
282 ThreadMemRegionTable
[Index
] = AlignedAddress
;
283 DEBUG ((DEBUG_INFO
, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index
, (UINT64
) ThreadMemRegionTable
[Index
]));
286 DEBUG ((DEBUG_INFO
, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData
->AllocatedThreads
));
287 MemRegionBaseAddr
= ThreadMemRegionTable
[0];
289 if (ProcessorNumber
< ProcTraceData
->AllocatedThreads
) {
290 MemRegionBaseAddr
= ProcTraceData
->ThreadMemRegionTable
[ProcessorNumber
];
292 return RETURN_SUCCESS
;
297 /// Check Processor Trace output scheme: Single Range output or ToPA table
301 // Single Range output scheme
303 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].SingleRangeSupported
&&
304 (ProcTraceData
->ProcTraceOutputScheme
== OutputSchemeSingleRange
)) {
306 DEBUG ((DEBUG_INFO
, "ProcTrace: Enabling Single Range Output scheme \n"));
310 // Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
312 MsrValue
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
313 MsrValue
&= (UINT64
) ~BIT8
;
314 CPU_REGISTER_TABLE_WRITE64 (
322 // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[47:12] with the allocated Memory Region
324 MsrValue
= (UINT64
) MemRegionBaseAddr
;
325 CPU_REGISTER_TABLE_WRITE64 (
328 MSR_IA32_RTIT_OUTPUT_BASE
,
333 // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)
335 MsrValue
= (UINT64
) MemRegionSize
- 1;
336 CPU_REGISTER_TABLE_WRITE64 (
339 MSR_IA32_RTIT_OUTPUT_MASK_PTRS
,
346 // ToPA(Table of physical address) scheme
348 if (ProcTraceData
->ProcessorData
[ProcessorNumber
].TopaSupported
&&
349 (ProcTraceData
->ProcTraceOutputScheme
== OutputSchemeToPA
)) {
351 // Create ToPA structure aligned at 4KB for each logical thread
352 // with at least 2 entries by 8 bytes size each. The first entry
353 // should have the trace output base address in bits 47:12, 6:9
354 // for Size, bits 4,2 and 0 must be cleared. The second entry
355 // should have the base address of the table location in bits
356 // 47:12, bits 4 and 2 must be cleared and bit 0 must be set.
359 DEBUG ((DEBUG_INFO
, "ProcTrace: Enabling ToPA scheme \n"));
361 // Let BSP allocate ToPA table mem for all threads
363 TopaMemArray
= (UINTN
*) AllocatePool (ProcTraceData
->AllocatedThreads
* sizeof (UINTN
*));
364 if (TopaMemArray
== NULL
) {
365 DEBUG ((DEBUG_ERROR
, "ProcTrace: Allocate mem for ToPA Failed\n"));
366 return RETURN_OUT_OF_RESOURCES
;
368 ProcTraceData
->TopaMemArray
= TopaMemArray
;
370 for (Index
= 0; Index
< ProcTraceData
->AllocatedThreads
; Index
++) {
371 Pages
= EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE
));
373 AlignedAddress
= (UINTN
) AllocateAlignedReservedPages (Pages
, Alignment
);
374 if (AlignedAddress
== 0) {
375 if (Index
< ProcTraceData
->AllocatedThreads
) {
376 ProcTraceData
->AllocatedThreads
= Index
;
378 DEBUG ((DEBUG_ERROR
, "ProcTrace: Out of mem, allocating ToPA mem only for %d threads\n", ProcTraceData
->AllocatedThreads
));
381 // Could not allocate for BSP
383 FreePool ((VOID
*) TopaMemArray
);
385 return RETURN_OUT_OF_RESOURCES
;
390 TopaMemArray
[Index
] = AlignedAddress
;
391 DEBUG ((DEBUG_INFO
, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index
, (UINT64
) TopaMemArray
[Index
]));
394 DEBUG ((DEBUG_INFO
, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData
->AllocatedThreads
));
396 // BSP gets the first block
398 TopaTableBaseAddr
= TopaMemArray
[0];
401 // Count for currently executing AP.
403 if (ProcessorNumber
< ProcTraceData
->AllocatedThreads
) {
404 TopaTableBaseAddr
= ProcTraceData
->TopaMemArray
[ProcessorNumber
];
406 return RETURN_SUCCESS
;
410 TopaTable
= (PROC_TRACE_TOPA_TABLE
*) TopaTableBaseAddr
;
411 TopaTable
->TopaEntry
[0] = (UINT64
) (MemRegionBaseAddr
| ((ProcTraceData
->ProcTraceMemSize
) << 6)) & ~BIT0
;
412 TopaTable
->TopaEntry
[1] = (UINT64
) TopaTableBaseAddr
| BIT0
;
415 // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[47:12] with ToPA base
417 MsrValue
= (UINT64
) TopaTableBaseAddr
;
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 CPU_REGISTER_TABLE_WRITE64 (
431 MSR_IA32_RTIT_OUTPUT_MASK_PTRS
,
435 // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
437 MsrValue
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
439 CPU_REGISTER_TABLE_WRITE64 (
448 /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)
450 MsrValue
= AsmReadMsr64 (MSR_IA32_RTIT_CTL
);
451 MsrValue
|= (UINT64
) BIT0
+ BIT2
+ BIT3
+ BIT13
;
453 MsrValue
&= (UINT64
) ~BIT0
;
455 CPU_REGISTER_TABLE_WRITE64 (
462 return RETURN_SUCCESS
;