]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c
UefiCpuPkg: Enable Processor Trace feature.
[mirror_edk2.git] / UefiCpuPkg / Library / CpuCommonFeaturesLib / ProcTrace.c
1 /** @file
2 Intel Processor Trace feature.
3
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
9
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.
12
13 **/
14
15 #include "CpuCommonFeatures.h"
16
17 #define MAX_TOPA_ENTRY_COUNT 2
18
19 ///
20 /// Processor trace buffer size selection.
21 ///
22 typedef enum {
23 Enum4K = 0,
24 Enum8K,
25 Enum16K,
26 Enum32K,
27 Enum64K,
28 Enum128K,
29 Enum256K,
30 Enum512K,
31 Enum1M,
32 Enum2M,
33 Enum4M,
34 Enum8M,
35 Enum16M,
36 Enum32M,
37 Enum64M,
38 Enum128M,
39 EnumProcTraceMemDisable
40 } PROC_TRACE_MEM_SIZE;
41
42 ///
43 /// Processor trace output scheme selection.
44 ///
45 typedef enum {
46 OutputSchemeSingleRange = 0,
47 OutputSchemeToPA,
48 OutputSchemeInvalid
49 } PROC_TRACE_OUTPUT_SCHEME;
50
51 typedef struct {
52 BOOLEAN ProcTraceSupported;
53 BOOLEAN TopaSupported;
54 BOOLEAN SingleRangeSupported;
55 } PROC_TRACE_PROCESSOR_DATA;
56
57 typedef struct {
58 UINT32 NumberOfProcessors;
59
60 UINT8 ProcTraceOutputScheme;
61 UINT32 ProcTraceMemSize;
62
63 UINTN *ThreadMemRegionTable;
64 UINTN AllocatedThreads;
65
66 UINTN *TopaMemArray;
67 UINTN TopaMemArrayCount;
68
69 PROC_TRACE_PROCESSOR_DATA *ProcessorData;
70 } PROC_TRACE_DATA;
71
72 typedef struct {
73 UINT64 TopaEntry[MAX_TOPA_ENTRY_COUNT];
74 } PROC_TRACE_TOPA_TABLE;
75
76 /**
77 Prepares for the data used by CPU feature detection and initialization.
78
79 @param[in] NumberOfProcessors The number of CPUs in the platform.
80
81 @return Pointer to a buffer of CPU related configuration data.
82
83 @note This service could be called by BSP only.
84 **/
85 VOID *
86 EFIAPI
87 ProcTraceGetConfigData (
88 IN UINTN NumberOfProcessors
89 )
90 {
91 PROC_TRACE_DATA *ConfigData;
92
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));
96
97 ConfigData->NumberOfProcessors = (UINT32) NumberOfProcessors;
98 ConfigData->ProcTraceMemSize = PcdGet32 (PcdCpuProcTraceMemSize);
99 ConfigData->ProcTraceOutputScheme = PcdGet8 (PcdCpuProcTraceOutputScheme);
100
101 return ConfigData;
102 }
103
104 /**
105 Detects if Intel Processor Trace feature supported on current
106 processor.
107
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().
115
116 @retval TRUE Processor Trace feature is supported.
117 @retval FALSE Processor Trace feature is not supported.
118
119 @note This service could be called by BSP/APs.
120 **/
121 BOOLEAN
122 EFIAPI
123 ProcTraceSupport (
124 IN UINTN ProcessorNumber,
125 IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
126 IN VOID *ConfigData OPTIONAL
127 )
128 {
129 PROC_TRACE_DATA *ProcTraceData;
130 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx;
131 CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx;
132
133 //
134 // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)
135 //
136 ProcTraceData = (PROC_TRACE_DATA *) ConfigData;
137 if ((ProcTraceData->ProcTraceMemSize >= EnumProcTraceMemDisable) ||
138 (ProcTraceData->ProcTraceOutputScheme >= OutputSchemeInvalid)) {
139 return FALSE;
140 }
141
142 //
143 // Check if Processor Trace is supported
144 //
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) {
148 return FALSE;
149 }
150
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) {
156 return TRUE;
157 }
158
159 return FALSE;
160 }
161
162 /**
163 Initializes Intel Processor Trace feature to specific state.
164
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
173 enabled.
174 If FALSE, then the Processor Trace feature must be
175 disabled.
176
177 @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
178
179 **/
180 RETURN_STATUS
181 EFIAPI
182 ProcTraceInitialize (
183 IN UINTN ProcessorNumber,
184 IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
185 IN VOID *ConfigData, OPTIONAL
186 IN BOOLEAN State
187 )
188 {
189 UINT64 MsrValue;
190 UINT32 MemRegionSize;
191 UINTN Pages;
192 UINTN Alignment;
193 UINTN MemRegionBaseAddr;
194 UINTN *ThreadMemRegionTable;
195 UINTN Index;
196 UINTN TopaTableBaseAddr;
197 UINTN AlignedAddress;
198 UINTN *TopaMemArray;
199 PROC_TRACE_TOPA_TABLE *TopaTable;
200 PROC_TRACE_DATA *ProcTraceData;
201 BOOLEAN FirstIn;
202
203 ProcTraceData = (PROC_TRACE_DATA *) ConfigData;
204
205 MemRegionBaseAddr = 0;
206 FirstIn = FALSE;
207
208 if (ProcTraceData->ThreadMemRegionTable == NULL) {
209 FirstIn = TRUE;
210 DEBUG ((DEBUG_INFO, "Initialize Processor Trace\n"));
211 }
212
213 ///
214 /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding
215 ///
216 MemRegionSize = (UINT32) (1 << (ProcTraceData->ProcTraceMemSize + 12));
217 if (FirstIn) {
218 DEBUG ((DEBUG_INFO, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize));
219 }
220
221 //
222 // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b
223 //
224 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
225 if ((MsrValue & BIT0) != 0) {
226 ///
227 /// Clear bit 0 in MSR IA32_RTIT_CTL (570)
228 ///
229 MsrValue &= (UINT64) ~BIT0;
230 CPU_REGISTER_TABLE_WRITE64 (
231 ProcessorNumber,
232 Msr,
233 MSR_IA32_RTIT_CTL,
234 MsrValue
235 );
236
237 ///
238 /// Clear MSR IA32_RTIT_STS (571h) to all zeros
239 ///
240 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_STATUS);
241 MsrValue &= 0x0;
242 CPU_REGISTER_TABLE_WRITE64 (
243 ProcessorNumber,
244 Msr,
245 MSR_IA32_RTIT_STATUS,
246 MsrValue
247 );
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 == OutputSchemeSingleRange)) {
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 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
313 MsrValue &= (UINT64) ~BIT8;
314 CPU_REGISTER_TABLE_WRITE64 (
315 ProcessorNumber,
316 Msr,
317 MSR_IA32_RTIT_CTL,
318 MsrValue
319 );
320
321 //
322 // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[47:12] with the allocated Memory Region
323 //
324 MsrValue = (UINT64) MemRegionBaseAddr;
325 CPU_REGISTER_TABLE_WRITE64 (
326 ProcessorNumber,
327 Msr,
328 MSR_IA32_RTIT_OUTPUT_BASE,
329 MsrValue
330 );
331
332 //
333 // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)
334 //
335 MsrValue = (UINT64) MemRegionSize - 1;
336 CPU_REGISTER_TABLE_WRITE64 (
337 ProcessorNumber,
338 Msr,
339 MSR_IA32_RTIT_OUTPUT_MASK_PTRS,
340 MsrValue
341 );
342
343 }
344
345 //
346 // ToPA(Table of physical address) scheme
347 //
348 if (ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported &&
349 (ProcTraceData->ProcTraceOutputScheme == OutputSchemeToPA)) {
350 //
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.
357 //
358 if (FirstIn) {
359 DEBUG ((DEBUG_INFO, "ProcTrace: Enabling ToPA scheme \n"));
360 //
361 // Let BSP allocate ToPA table mem for all threads
362 //
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;
367 }
368 ProcTraceData->TopaMemArray = TopaMemArray;
369
370 for (Index = 0; Index < ProcTraceData->AllocatedThreads; Index++) {
371 Pages = EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE));
372 Alignment = 0x1000;
373 AlignedAddress = (UINTN) AllocateAlignedReservedPages (Pages, Alignment);
374 if (AlignedAddress == 0) {
375 if (Index < ProcTraceData->AllocatedThreads) {
376 ProcTraceData->AllocatedThreads = Index;
377 }
378 DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocating ToPA mem only for %d threads\n", ProcTraceData->AllocatedThreads));
379 if (Index == 0) {
380 //
381 // Could not allocate for BSP
382 //
383 FreePool ((VOID *) TopaMemArray);
384 TopaMemArray = NULL;
385 return RETURN_OUT_OF_RESOURCES;
386 }
387 break;
388 }
389
390 TopaMemArray[Index] = AlignedAddress;
391 DEBUG ((DEBUG_INFO, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index, (UINT64) TopaMemArray[Index]));
392 }
393
394 DEBUG ((DEBUG_INFO, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData->AllocatedThreads));
395 //
396 // BSP gets the first block
397 //
398 TopaTableBaseAddr = TopaMemArray[0];
399 } else {
400 //
401 // Count for currently executing AP.
402 //
403 if (ProcessorNumber < ProcTraceData->AllocatedThreads) {
404 TopaTableBaseAddr = ProcTraceData->TopaMemArray[ProcessorNumber];
405 } else {
406 return RETURN_SUCCESS;
407 }
408 }
409
410 TopaTable = (PROC_TRACE_TOPA_TABLE *) TopaTableBaseAddr;
411 TopaTable->TopaEntry[0] = (UINT64) (MemRegionBaseAddr | ((ProcTraceData->ProcTraceMemSize) << 6)) & ~BIT0;
412 TopaTable->TopaEntry[1] = (UINT64) TopaTableBaseAddr | BIT0;
413
414 //
415 // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[47:12] with ToPA base
416 //
417 MsrValue = (UINT64) TopaTableBaseAddr;
418 CPU_REGISTER_TABLE_WRITE64 (
419 ProcessorNumber,
420 Msr,
421 MSR_IA32_RTIT_OUTPUT_BASE,
422 MsrValue
423 );
424
425 //
426 // Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0
427 //
428 CPU_REGISTER_TABLE_WRITE64 (
429 ProcessorNumber,
430 Msr,
431 MSR_IA32_RTIT_OUTPUT_MASK_PTRS,
432 0x7F
433 );
434 //
435 // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
436 //
437 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
438 MsrValue |= BIT8;
439 CPU_REGISTER_TABLE_WRITE64 (
440 ProcessorNumber,
441 Msr,
442 MSR_IA32_RTIT_CTL,
443 MsrValue
444 );
445 }
446
447 ///
448 /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)
449 ///
450 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
451 MsrValue |= (UINT64) BIT0 + BIT2 + BIT3 + BIT13;
452 if (!State) {
453 MsrValue &= (UINT64) ~BIT0;
454 }
455 CPU_REGISTER_TABLE_WRITE64 (
456 ProcessorNumber,
457 Msr,
458 MSR_IA32_RTIT_CTL,
459 MsrValue
460 );
461
462 return RETURN_SUCCESS;
463 }