]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c
UefiCpuPkg CpuCommFeaturesLib: Disable TraceEn at the beginning
[mirror_edk2.git] / UefiCpuPkg / Library / CpuCommonFeaturesLib / ProcTrace.c
1 /** @file
2 Intel Processor Trace feature.
3
4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "CpuCommonFeatures.h"
10
11 ///
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.
19 ///
20 #define MAX_TOPA_ENTRY_COUNT 2
21
22
23 ///
24 /// Processor trace output scheme selection.
25 ///
26 typedef enum {
27 RtitOutputSchemeSingleRange = 0,
28 RtitOutputSchemeToPA
29 } RTIT_OUTPUT_SCHEME;
30
31 typedef struct {
32 BOOLEAN ProcTraceSupported;
33 BOOLEAN TopaSupported;
34 BOOLEAN SingleRangeSupported;
35 } PROC_TRACE_PROCESSOR_DATA;
36
37 typedef struct {
38 UINT32 NumberOfProcessors;
39
40 UINT8 ProcTraceOutputScheme;
41 UINT32 ProcTraceMemSize;
42
43 UINTN *ThreadMemRegionTable;
44 UINTN AllocatedThreads;
45
46 UINTN *TopaMemArray;
47 UINTN TopaMemArrayCount;
48
49 PROC_TRACE_PROCESSOR_DATA *ProcessorData;
50 } PROC_TRACE_DATA;
51
52 typedef struct {
53 RTIT_TOPA_TABLE_ENTRY TopaEntry[MAX_TOPA_ENTRY_COUNT];
54 } PROC_TRACE_TOPA_TABLE;
55
56 /**
57 Prepares for the data used by CPU feature detection and initialization.
58
59 @param[in] NumberOfProcessors The number of CPUs in the platform.
60
61 @return Pointer to a buffer of CPU related configuration data.
62
63 @note This service could be called by BSP only.
64 **/
65 VOID *
66 EFIAPI
67 ProcTraceGetConfigData (
68 IN UINTN NumberOfProcessors
69 )
70 {
71 PROC_TRACE_DATA *ConfigData;
72
73 ConfigData = AllocateZeroPool (sizeof (PROC_TRACE_DATA) + sizeof (PROC_TRACE_PROCESSOR_DATA) * NumberOfProcessors);
74 ASSERT (ConfigData != NULL);
75 ConfigData->ProcessorData = (PROC_TRACE_PROCESSOR_DATA *) ((UINT8*) ConfigData + sizeof (PROC_TRACE_DATA));
76
77 ConfigData->NumberOfProcessors = (UINT32) NumberOfProcessors;
78 ConfigData->ProcTraceMemSize = PcdGet32 (PcdCpuProcTraceMemSize);
79 ConfigData->ProcTraceOutputScheme = PcdGet8 (PcdCpuProcTraceOutputScheme);
80
81 return ConfigData;
82 }
83
84 /**
85 Detects if Intel Processor Trace feature supported on current
86 processor.
87
88 @param[in] ProcessorNumber The index of the CPU executing this function.
89 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
90 structure for the CPU executing this function.
91 @param[in] ConfigData A pointer to the configuration buffer returned
92 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
93 CPU_FEATURE_GET_CONFIG_DATA was not provided in
94 RegisterCpuFeature().
95
96 @retval TRUE Processor Trace feature is supported.
97 @retval FALSE Processor Trace feature is not supported.
98
99 @note This service could be called by BSP/APs.
100 **/
101 BOOLEAN
102 EFIAPI
103 ProcTraceSupport (
104 IN UINTN ProcessorNumber,
105 IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
106 IN VOID *ConfigData OPTIONAL
107 )
108 {
109 PROC_TRACE_DATA *ProcTraceData;
110 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx;
111 CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx;
112
113 //
114 // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)
115 //
116 ProcTraceData = (PROC_TRACE_DATA *) ConfigData;
117 ASSERT (ProcTraceData != NULL);
118 if ((ProcTraceData->ProcTraceMemSize > RtitTopaMemorySize128M) ||
119 (ProcTraceData->ProcTraceOutputScheme > RtitOutputSchemeToPA)) {
120 return FALSE;
121 }
122
123 //
124 // Check if Processor Trace is supported
125 //
126 AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, 0, NULL, &Ebx.Uint32, NULL, NULL);
127 ProcTraceData->ProcessorData[ProcessorNumber].ProcTraceSupported = (BOOLEAN) (Ebx.Bits.IntelProcessorTrace == 1);
128 if (!ProcTraceData->ProcessorData[ProcessorNumber].ProcTraceSupported) {
129 return FALSE;
130 }
131
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 return TRUE;
138 }
139
140 return FALSE;
141 }
142
143 /**
144 Initializes Intel Processor Trace feature to specific state.
145
146 @param[in] ProcessorNumber The index of the CPU executing this function.
147 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
148 structure for the CPU executing this function.
149 @param[in] ConfigData A pointer to the configuration buffer returned
150 by CPU_FEATURE_GET_CONFIG_DATA. NULL if
151 CPU_FEATURE_GET_CONFIG_DATA was not provided in
152 RegisterCpuFeature().
153 @param[in] State If TRUE, then the Processor Trace feature must be
154 enabled.
155 If FALSE, then the Processor Trace feature must be
156 disabled.
157
158 @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
159
160 **/
161 RETURN_STATUS
162 EFIAPI
163 ProcTraceInitialize (
164 IN UINTN ProcessorNumber,
165 IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
166 IN VOID *ConfigData, OPTIONAL
167 IN BOOLEAN State
168 )
169 {
170 UINT32 MemRegionSize;
171 UINTN Pages;
172 UINTN Alignment;
173 UINTN MemRegionBaseAddr;
174 UINTN *ThreadMemRegionTable;
175 UINTN Index;
176 UINTN TopaTableBaseAddr;
177 UINTN AlignedAddress;
178 UINTN *TopaMemArray;
179 PROC_TRACE_TOPA_TABLE *TopaTable;
180 PROC_TRACE_DATA *ProcTraceData;
181 BOOLEAN FirstIn;
182 MSR_IA32_RTIT_CTL_REGISTER CtrlReg;
183 MSR_IA32_RTIT_STATUS_REGISTER StatusReg;
184 MSR_IA32_RTIT_OUTPUT_BASE_REGISTER OutputBaseReg;
185 MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER OutputMaskPtrsReg;
186 RTIT_TOPA_TABLE_ENTRY *TopaEntryPtr;
187
188 //
189 // The scope of the MSR_IA32_RTIT_* is core for below processor type, only program
190 // MSR_IA32_RTIT_* for thread 0 in each core.
191 //
192 if (IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
193 IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
194 if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
195 return RETURN_SUCCESS;
196 }
197 }
198
199 ProcTraceData = (PROC_TRACE_DATA *) ConfigData;
200 ASSERT (ProcTraceData != NULL);
201
202 //
203 // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b
204 //
205 CtrlReg.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
206 if (CtrlReg.Bits.TraceEn != 0) {
207 ///
208 /// Clear bit 0 in MSR IA32_RTIT_CTL (570)
209 ///
210 CtrlReg.Bits.TraceEn = 0;
211 CPU_REGISTER_TABLE_WRITE64 (
212 ProcessorNumber,
213 Msr,
214 MSR_IA32_RTIT_CTL,
215 CtrlReg.Uint64
216 );
217
218 ///
219 /// Clear MSR IA32_RTIT_STS (571h) to all zeros
220 ///
221 StatusReg.Uint64 = 0x0;
222 CPU_REGISTER_TABLE_WRITE64 (
223 ProcessorNumber,
224 Msr,
225 MSR_IA32_RTIT_STATUS,
226 StatusReg.Uint64
227 );
228 }
229
230 if (!State) {
231 return RETURN_SUCCESS;
232 }
233
234 MemRegionBaseAddr = 0;
235 FirstIn = FALSE;
236
237 if (ProcTraceData->ThreadMemRegionTable == NULL) {
238 FirstIn = TRUE;
239 DEBUG ((DEBUG_INFO, "Initialize Processor Trace\n"));
240 }
241
242 ///
243 /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding
244 ///
245 MemRegionSize = (UINT32) (1 << (ProcTraceData->ProcTraceMemSize + 12));
246 if (FirstIn) {
247 DEBUG ((DEBUG_INFO, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize));
248 }
249
250 if (FirstIn) {
251 //
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.
257 //
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;
262 }
263 ProcTraceData->ThreadMemRegionTable = ThreadMemRegionTable;
264
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));
271 if (Index == 0) {
272 //
273 // Could not allocate for BSP even
274 //
275 FreePool ((VOID *) ThreadMemRegionTable);
276 ThreadMemRegionTable = NULL;
277 return RETURN_OUT_OF_RESOURCES;
278 }
279 break;
280 }
281
282 ThreadMemRegionTable[Index] = AlignedAddress;
283 DEBUG ((DEBUG_INFO, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index, (UINT64) ThreadMemRegionTable[Index]));
284 }
285
286 DEBUG ((DEBUG_INFO, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData->AllocatedThreads));
287 MemRegionBaseAddr = ThreadMemRegionTable[0];
288 } else {
289 if (ProcessorNumber < ProcTraceData->AllocatedThreads) {
290 MemRegionBaseAddr = ProcTraceData->ThreadMemRegionTable[ProcessorNumber];
291 } else {
292 return RETURN_SUCCESS;
293 }
294 }
295
296 ///
297 /// Check Processor Trace output scheme: Single Range output or ToPA table
298 ///
299
300 //
301 // Single Range output scheme
302 //
303 if (ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported &&
304 (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeSingleRange)) {
305 if (FirstIn) {
306 DEBUG ((DEBUG_INFO, "ProcTrace: Enabling Single Range Output scheme \n"));
307 }
308
309 //
310 // Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
311 //
312 CtrlReg.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
313 CtrlReg.Bits.ToPA = 0;
314 CPU_REGISTER_TABLE_WRITE64 (
315 ProcessorNumber,
316 Msr,
317 MSR_IA32_RTIT_CTL,
318 CtrlReg.Uint64
319 );
320
321 //
322 // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with the allocated Memory Region
323 //
324 OutputBaseReg.Bits.Base = (MemRegionBaseAddr >> 7) & 0x01FFFFFF;
325 OutputBaseReg.Bits.BaseHi = RShiftU64 ((UINT64) MemRegionBaseAddr, 32) & 0xFFFFFFFF;
326 CPU_REGISTER_TABLE_WRITE64 (
327 ProcessorNumber,
328 Msr,
329 MSR_IA32_RTIT_OUTPUT_BASE,
330 OutputBaseReg.Uint64
331 );
332
333 //
334 // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)
335 //
336 OutputMaskPtrsReg.Bits.MaskOrTableOffset = ((MemRegionSize - 1) >> 7) & 0x01FFFFFF;
337 OutputMaskPtrsReg.Bits.OutputOffset = RShiftU64 (MemRegionSize - 1, 32) & 0xFFFFFFFF;
338 CPU_REGISTER_TABLE_WRITE64 (
339 ProcessorNumber,
340 Msr,
341 MSR_IA32_RTIT_OUTPUT_MASK_PTRS,
342 OutputMaskPtrsReg.Uint64
343 );
344 }
345
346 //
347 // ToPA(Table of physical address) scheme
348 //
349 if (ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported &&
350 (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeToPA)) {
351 //
352 // Create ToPA structure aligned at 4KB for each logical thread
353 // with at least 2 entries by 8 bytes size each. The first entry
354 // should have the trace output base address in bits 47:12, 6:9
355 // for Size, bits 4,2 and 0 must be cleared. The second entry
356 // should have the base address of the table location in bits
357 // 47:12, bits 4 and 2 must be cleared and bit 0 must be set.
358 //
359 if (FirstIn) {
360 DEBUG ((DEBUG_INFO, "ProcTrace: Enabling ToPA scheme \n"));
361 //
362 // Let BSP allocate ToPA table mem for all threads
363 //
364 TopaMemArray = (UINTN *) AllocatePool (ProcTraceData->AllocatedThreads * sizeof (UINTN *));
365 if (TopaMemArray == NULL) {
366 DEBUG ((DEBUG_ERROR, "ProcTrace: Allocate mem for ToPA Failed\n"));
367 return RETURN_OUT_OF_RESOURCES;
368 }
369 ProcTraceData->TopaMemArray = TopaMemArray;
370
371 for (Index = 0; Index < ProcTraceData->AllocatedThreads; Index++) {
372 Pages = EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE));
373 Alignment = 0x1000;
374 AlignedAddress = (UINTN) AllocateAlignedReservedPages (Pages, Alignment);
375 if (AlignedAddress == 0) {
376 if (Index < ProcTraceData->AllocatedThreads) {
377 ProcTraceData->AllocatedThreads = Index;
378 }
379 DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocating ToPA mem only for %d threads\n", ProcTraceData->AllocatedThreads));
380 if (Index == 0) {
381 //
382 // Could not allocate for BSP
383 //
384 FreePool ((VOID *) TopaMemArray);
385 TopaMemArray = NULL;
386 return RETURN_OUT_OF_RESOURCES;
387 }
388 break;
389 }
390
391 TopaMemArray[Index] = AlignedAddress;
392 DEBUG ((DEBUG_INFO, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index, (UINT64) TopaMemArray[Index]));
393 }
394
395 DEBUG ((DEBUG_INFO, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData->AllocatedThreads));
396 //
397 // BSP gets the first block
398 //
399 TopaTableBaseAddr = TopaMemArray[0];
400 } else {
401 //
402 // Count for currently executing AP.
403 //
404 if (ProcessorNumber < ProcTraceData->AllocatedThreads) {
405 TopaTableBaseAddr = ProcTraceData->TopaMemArray[ProcessorNumber];
406 } else {
407 return RETURN_SUCCESS;
408 }
409 }
410
411 TopaTable = (PROC_TRACE_TOPA_TABLE *) TopaTableBaseAddr;
412 TopaEntryPtr = &TopaTable->TopaEntry[0];
413 TopaEntryPtr->Bits.Base = (MemRegionBaseAddr >> 12) & 0x000FFFFF;
414 TopaEntryPtr->Bits.BaseHi = RShiftU64 ((UINT64) MemRegionBaseAddr, 32) & 0xFFFFFFFF;
415 TopaEntryPtr->Bits.Size = ProcTraceData->ProcTraceMemSize;
416 TopaEntryPtr->Bits.END = 0;
417
418 TopaEntryPtr = &TopaTable->TopaEntry[1];
419 TopaEntryPtr->Bits.Base = (TopaTableBaseAddr >> 12) & 0x000FFFFF;
420 TopaEntryPtr->Bits.BaseHi = RShiftU64 ((UINT64) TopaTableBaseAddr, 32) & 0xFFFFFFFF;
421 TopaEntryPtr->Bits.END = 1;
422
423 //
424 // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with ToPA base
425 //
426 OutputBaseReg.Bits.Base = (TopaTableBaseAddr >> 7) & 0x01FFFFFF;
427 OutputBaseReg.Bits.BaseHi = RShiftU64 ((UINT64) TopaTableBaseAddr, 32) & 0xFFFFFFFF;
428 CPU_REGISTER_TABLE_WRITE64 (
429 ProcessorNumber,
430 Msr,
431 MSR_IA32_RTIT_OUTPUT_BASE,
432 OutputBaseReg.Uint64
433 );
434
435 //
436 // Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0
437 //
438 OutputMaskPtrsReg.Bits.MaskOrTableOffset = 0;
439 OutputMaskPtrsReg.Bits.OutputOffset = 0;
440 CPU_REGISTER_TABLE_WRITE64 (
441 ProcessorNumber,
442 Msr,
443 MSR_IA32_RTIT_OUTPUT_MASK_PTRS,
444 OutputMaskPtrsReg.Uint64
445 );
446 //
447 // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
448 //
449 CtrlReg.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
450 CtrlReg.Bits.ToPA = 1;
451 CPU_REGISTER_TABLE_WRITE64 (
452 ProcessorNumber,
453 Msr,
454 MSR_IA32_RTIT_CTL,
455 CtrlReg.Uint64
456 );
457 }
458
459 ///
460 /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)
461 ///
462 CtrlReg.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
463 CtrlReg.Bits.OS = 1;
464 CtrlReg.Bits.User = 1;
465 CtrlReg.Bits.BranchEn = 1;
466 CtrlReg.Bits.TraceEn = 1;
467 CPU_REGISTER_TABLE_WRITE64 (
468 ProcessorNumber,
469 Msr,
470 MSR_IA32_RTIT_CTL,
471 CtrlReg.Uint64
472 );
473
474 return RETURN_SUCCESS;
475 }