]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c
UefiCpuPkg: Enable Processor Trace feature.
[mirror_edk2.git] / UefiCpuPkg / Library / CpuCommonFeaturesLib / ProcTrace.c
CommitLineData
bc230057
ED
1/** @file\r
2 Intel Processor Trace feature.\r
3\r
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuCommonFeatures.h"\r
16\r
17#define MAX_TOPA_ENTRY_COUNT 2\r
18\r
19///\r
20/// Processor trace buffer size selection.\r
21///\r
22typedef enum {\r
23 Enum4K = 0,\r
24 Enum8K,\r
25 Enum16K,\r
26 Enum32K,\r
27 Enum64K,\r
28 Enum128K,\r
29 Enum256K,\r
30 Enum512K,\r
31 Enum1M,\r
32 Enum2M,\r
33 Enum4M,\r
34 Enum8M,\r
35 Enum16M,\r
36 Enum32M,\r
37 Enum64M,\r
38 Enum128M,\r
39 EnumProcTraceMemDisable\r
40} PROC_TRACE_MEM_SIZE;\r
41\r
42///\r
43/// Processor trace output scheme selection.\r
44///\r
45typedef enum {\r
46 OutputSchemeSingleRange = 0,\r
47 OutputSchemeToPA,\r
48 OutputSchemeInvalid\r
49} PROC_TRACE_OUTPUT_SCHEME;\r
50\r
51typedef struct {\r
52 BOOLEAN ProcTraceSupported;\r
53 BOOLEAN TopaSupported;\r
54 BOOLEAN SingleRangeSupported;\r
55} PROC_TRACE_PROCESSOR_DATA;\r
56\r
57typedef struct {\r
58 UINT32 NumberOfProcessors;\r
59\r
60 UINT8 ProcTraceOutputScheme; \r
61 UINT32 ProcTraceMemSize;\r
62\r
63 UINTN *ThreadMemRegionTable;\r
64 UINTN AllocatedThreads;\r
65\r
66 UINTN *TopaMemArray;\r
67 UINTN TopaMemArrayCount;\r
68\r
69 PROC_TRACE_PROCESSOR_DATA *ProcessorData;\r
70} PROC_TRACE_DATA;\r
71\r
72typedef struct {\r
73 UINT64 TopaEntry[MAX_TOPA_ENTRY_COUNT];\r
74} PROC_TRACE_TOPA_TABLE;\r
75\r
76/**\r
77 Prepares for the data used by CPU feature detection and initialization.\r
78\r
79 @param[in] NumberOfProcessors The number of CPUs in the platform.\r
80\r
81 @return Pointer to a buffer of CPU related configuration data.\r
82\r
83 @note This service could be called by BSP only.\r
84**/\r
85VOID *\r
86EFIAPI\r
87ProcTraceGetConfigData (\r
88 IN UINTN NumberOfProcessors\r
89 )\r
90{\r
91 PROC_TRACE_DATA *ConfigData;\r
92\r
93 ConfigData = AllocateZeroPool (sizeof (PROC_TRACE_DATA) + sizeof (PROC_TRACE_PROCESSOR_DATA) * NumberOfProcessors);\r
94 ASSERT (ConfigData != NULL);\r
95 ConfigData->ProcessorData = (PROC_TRACE_PROCESSOR_DATA *) ((UINT8*) ConfigData + sizeof (PROC_TRACE_DATA));\r
96\r
97 ConfigData->NumberOfProcessors = (UINT32) NumberOfProcessors;\r
98 ConfigData->ProcTraceMemSize = PcdGet32 (PcdCpuProcTraceMemSize);\r
99 ConfigData->ProcTraceOutputScheme = PcdGet8 (PcdCpuProcTraceOutputScheme);\r
100\r
101 return ConfigData;\r
102}\r
103\r
104/**\r
105 Detects if Intel Processor Trace feature supported on current \r
106 processor.\r
107\r
108 @param[in] ProcessorNumber The index of the CPU executing this function.\r
109 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION\r
110 structure for the CPU executing this function.\r
111 @param[in] ConfigData A pointer to the configuration buffer returned\r
112 by CPU_FEATURE_GET_CONFIG_DATA. NULL if\r
113 CPU_FEATURE_GET_CONFIG_DATA was not provided in\r
114 RegisterCpuFeature().\r
115\r
116 @retval TRUE Processor Trace feature is supported.\r
117 @retval FALSE Processor Trace feature is not supported.\r
118\r
119 @note This service could be called by BSP/APs.\r
120**/\r
121BOOLEAN\r
122EFIAPI\r
123ProcTraceSupport (\r
124 IN UINTN ProcessorNumber,\r
125 IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,\r
126 IN VOID *ConfigData OPTIONAL\r
127 )\r
128{\r
129 PROC_TRACE_DATA *ProcTraceData;\r
130 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx;\r
131 CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx;\r
132\r
133 //\r
134 // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)\r
135 //\r
136 ProcTraceData = (PROC_TRACE_DATA *) ConfigData;\r
137 if ((ProcTraceData->ProcTraceMemSize >= EnumProcTraceMemDisable) ||\r
138 (ProcTraceData->ProcTraceOutputScheme >= OutputSchemeInvalid)) {\r
139 return FALSE;\r
140 }\r
141\r
142 //\r
143 // Check if Processor Trace is supported\r
144 //\r
145 AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, 0, NULL, &Ebx.Uint32, NULL, NULL);\r
146 ProcTraceData->ProcessorData[ProcessorNumber].ProcTraceSupported = (BOOLEAN) (Ebx.Bits.IntelProcessorTrace == 1);\r
147 if (!ProcTraceData->ProcessorData[ProcessorNumber].ProcTraceSupported) {\r
148 return FALSE;\r
149 }\r
150\r
151 AsmCpuidEx (CPUID_INTEL_PROCESSOR_TRACE, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF, NULL, NULL, &Ecx.Uint32, NULL);\r
152 ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported = (BOOLEAN) (Ecx.Bits.RTIT == 1);\r
153 ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported = (BOOLEAN) (Ecx.Bits.SingleRangeOutput == 1);\r
154 if (ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported || \r
155 ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported) {\r
156 return TRUE;\r
157 }\r
158\r
159 return FALSE;\r
160}\r
161\r
162/**\r
163 Initializes Intel Processor Trace feature to specific state.\r
164\r
165 @param[in] ProcessorNumber The index of the CPU executing this function.\r
166 @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION\r
167 structure for the CPU executing this function.\r
168 @param[in] ConfigData A pointer to the configuration buffer returned\r
169 by CPU_FEATURE_GET_CONFIG_DATA. NULL if\r
170 CPU_FEATURE_GET_CONFIG_DATA was not provided in\r
171 RegisterCpuFeature().\r
172 @param[in] State If TRUE, then the Processor Trace feature must be\r
173 enabled.\r
174 If FALSE, then the Processor Trace feature must be\r
175 disabled.\r
176\r
177 @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.\r
178\r
179**/\r
180RETURN_STATUS\r
181EFIAPI\r
182ProcTraceInitialize (\r
183 IN UINTN ProcessorNumber,\r
184 IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,\r
185 IN VOID *ConfigData, OPTIONAL\r
186 IN BOOLEAN State\r
187 )\r
188{\r
189 UINT64 MsrValue;\r
190 UINT32 MemRegionSize;\r
191 UINTN Pages;\r
192 UINTN Alignment;\r
193 UINTN MemRegionBaseAddr;\r
194 UINTN *ThreadMemRegionTable;\r
195 UINTN Index;\r
196 UINTN TopaTableBaseAddr;\r
197 UINTN AlignedAddress;\r
198 UINTN *TopaMemArray;\r
199 PROC_TRACE_TOPA_TABLE *TopaTable;\r
200 PROC_TRACE_DATA *ProcTraceData;\r
201 BOOLEAN FirstIn;\r
202\r
203 ProcTraceData = (PROC_TRACE_DATA *) ConfigData;\r
204\r
205 MemRegionBaseAddr = 0;\r
206 FirstIn = FALSE;\r
207\r
208 if (ProcTraceData->ThreadMemRegionTable == NULL) {\r
209 FirstIn = TRUE;\r
210 DEBUG ((DEBUG_INFO, "Initialize Processor Trace\n"));\r
211 }\r
212\r
213 ///\r
214 /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding\r
215 ///\r
216 MemRegionSize = (UINT32) (1 << (ProcTraceData->ProcTraceMemSize + 12));\r
217 if (FirstIn) {\r
218 DEBUG ((DEBUG_INFO, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize));\r
219 }\r
220\r
221 //\r
222 // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b\r
223 //\r
224 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);\r
225 if ((MsrValue & BIT0) != 0) {\r
226 ///\r
227 /// Clear bit 0 in MSR IA32_RTIT_CTL (570)\r
228 ///\r
229 MsrValue &= (UINT64) ~BIT0;\r
230 CPU_REGISTER_TABLE_WRITE64 (\r
231 ProcessorNumber,\r
232 Msr,\r
233 MSR_IA32_RTIT_CTL,\r
234 MsrValue\r
235 );\r
236\r
237 ///\r
238 /// Clear MSR IA32_RTIT_STS (571h) to all zeros\r
239 ///\r
240 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_STATUS);\r
241 MsrValue &= 0x0;\r
242 CPU_REGISTER_TABLE_WRITE64 (\r
243 ProcessorNumber,\r
244 Msr,\r
245 MSR_IA32_RTIT_STATUS,\r
246 MsrValue\r
247 );\r
248 }\r
249\r
250 if (FirstIn) {\r
251 //\r
252 // Let BSP allocate and create the necessary memory region (Aligned to the size of\r
253 // the memory region from setup option(ProcTraceMemSize) which is an integral multiple of 4kB)\r
254 // for the all the enabled threads for storing Processor Trace debug data. Then Configure the trace\r
255 // address base in MSR, IA32_RTIT_OUTPUT_BASE (560h) bits 47:12. Note that all regions must be\r
256 // aligned based on their size, not just 4K. Thus a 2M region must have bits 20:12 clear.\r
257 //\r
258 ThreadMemRegionTable = (UINTN *) AllocatePool (ProcTraceData->NumberOfProcessors * sizeof (UINTN *));\r
259 if (ThreadMemRegionTable == NULL) {\r
260 DEBUG ((DEBUG_ERROR, "Allocate ProcTrace ThreadMemRegionTable Failed\n"));\r
261 return RETURN_OUT_OF_RESOURCES;\r
262 }\r
263 ProcTraceData->ThreadMemRegionTable = ThreadMemRegionTable;\r
264\r
265 for (Index = 0; Index < ProcTraceData->NumberOfProcessors; Index++, ProcTraceData->AllocatedThreads++) {\r
266 Pages = EFI_SIZE_TO_PAGES (MemRegionSize);\r
267 Alignment = MemRegionSize;\r
268 AlignedAddress = (UINTN) AllocateAlignedReservedPages (Pages, Alignment);\r
269 if (AlignedAddress == 0) {\r
270 DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocated only for %d threads\n", ProcTraceData->AllocatedThreads));\r
271 if (Index == 0) {\r
272 //\r
273 // Could not allocate for BSP even\r
274 //\r
275 FreePool ((VOID *) ThreadMemRegionTable);\r
276 ThreadMemRegionTable = NULL;\r
277 return RETURN_OUT_OF_RESOURCES;\r
278 }\r
279 break;\r
280 }\r
281\r
282 ThreadMemRegionTable[Index] = AlignedAddress;\r
283 DEBUG ((DEBUG_INFO, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index, (UINT64) ThreadMemRegionTable[Index]));\r
284 }\r
285\r
286 DEBUG ((DEBUG_INFO, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData->AllocatedThreads));\r
287 MemRegionBaseAddr = ThreadMemRegionTable[0];\r
288 } else {\r
289 if (ProcessorNumber < ProcTraceData->AllocatedThreads) {\r
290 MemRegionBaseAddr = ProcTraceData->ThreadMemRegionTable[ProcessorNumber];\r
291 } else {\r
292 return RETURN_SUCCESS;\r
293 }\r
294 }\r
295\r
296 ///\r
297 /// Check Processor Trace output scheme: Single Range output or ToPA table\r
298 ///\r
299\r
300 //\r
301 // Single Range output scheme\r
302 //\r
303 if (ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported && \r
304 (ProcTraceData->ProcTraceOutputScheme == OutputSchemeSingleRange)) {\r
305 if (FirstIn) {\r
306 DEBUG ((DEBUG_INFO, "ProcTrace: Enabling Single Range Output scheme \n"));\r
307 }\r
308\r
309 //\r
310 // Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)\r
311 //\r
312 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);\r
313 MsrValue &= (UINT64) ~BIT8;\r
314 CPU_REGISTER_TABLE_WRITE64 (\r
315 ProcessorNumber,\r
316 Msr,\r
317 MSR_IA32_RTIT_CTL,\r
318 MsrValue\r
319 );\r
320\r
321 //\r
322 // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[47:12] with the allocated Memory Region\r
323 //\r
324 MsrValue = (UINT64) MemRegionBaseAddr;\r
325 CPU_REGISTER_TABLE_WRITE64 (\r
326 ProcessorNumber,\r
327 Msr,\r
328 MSR_IA32_RTIT_OUTPUT_BASE,\r
329 MsrValue\r
330 );\r
331\r
332 //\r
333 // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)\r
334 //\r
335 MsrValue = (UINT64) MemRegionSize - 1;\r
336 CPU_REGISTER_TABLE_WRITE64 (\r
337 ProcessorNumber,\r
338 Msr,\r
339 MSR_IA32_RTIT_OUTPUT_MASK_PTRS,\r
340 MsrValue\r
341 );\r
342\r
343 }\r
344\r
345 //\r
346 // ToPA(Table of physical address) scheme\r
347 //\r
348 if (ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported && \r
349 (ProcTraceData->ProcTraceOutputScheme == OutputSchemeToPA)) {\r
350 //\r
351 // Create ToPA structure aligned at 4KB for each logical thread\r
352 // with at least 2 entries by 8 bytes size each. The first entry\r
353 // should have the trace output base address in bits 47:12, 6:9\r
354 // for Size, bits 4,2 and 0 must be cleared. The second entry\r
355 // should have the base address of the table location in bits\r
356 // 47:12, bits 4 and 2 must be cleared and bit 0 must be set.\r
357 //\r
358 if (FirstIn) {\r
359 DEBUG ((DEBUG_INFO, "ProcTrace: Enabling ToPA scheme \n"));\r
360 //\r
361 // Let BSP allocate ToPA table mem for all threads\r
362 //\r
363 TopaMemArray = (UINTN *) AllocatePool (ProcTraceData->AllocatedThreads * sizeof (UINTN *));\r
364 if (TopaMemArray == NULL) {\r
365 DEBUG ((DEBUG_ERROR, "ProcTrace: Allocate mem for ToPA Failed\n"));\r
366 return RETURN_OUT_OF_RESOURCES;\r
367 }\r
368 ProcTraceData->TopaMemArray = TopaMemArray;\r
369\r
370 for (Index = 0; Index < ProcTraceData->AllocatedThreads; Index++) {\r
371 Pages = EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE));\r
372 Alignment = 0x1000;\r
373 AlignedAddress = (UINTN) AllocateAlignedReservedPages (Pages, Alignment);\r
374 if (AlignedAddress == 0) {\r
375 if (Index < ProcTraceData->AllocatedThreads) {\r
376 ProcTraceData->AllocatedThreads = Index;\r
377 }\r
378 DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocating ToPA mem only for %d threads\n", ProcTraceData->AllocatedThreads));\r
379 if (Index == 0) {\r
380 //\r
381 // Could not allocate for BSP\r
382 //\r
383 FreePool ((VOID *) TopaMemArray);\r
384 TopaMemArray = NULL;\r
385 return RETURN_OUT_OF_RESOURCES;\r
386 }\r
387 break;\r
388 }\r
389\r
390 TopaMemArray[Index] = AlignedAddress;\r
391 DEBUG ((DEBUG_INFO, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index, (UINT64) TopaMemArray[Index]));\r
392 }\r
393\r
394 DEBUG ((DEBUG_INFO, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData->AllocatedThreads));\r
395 //\r
396 // BSP gets the first block\r
397 //\r
398 TopaTableBaseAddr = TopaMemArray[0];\r
399 } else {\r
400 //\r
401 // Count for currently executing AP.\r
402 //\r
403 if (ProcessorNumber < ProcTraceData->AllocatedThreads) {\r
404 TopaTableBaseAddr = ProcTraceData->TopaMemArray[ProcessorNumber];\r
405 } else {\r
406 return RETURN_SUCCESS;\r
407 }\r
408 }\r
409\r
410 TopaTable = (PROC_TRACE_TOPA_TABLE *) TopaTableBaseAddr;\r
411 TopaTable->TopaEntry[0] = (UINT64) (MemRegionBaseAddr | ((ProcTraceData->ProcTraceMemSize) << 6)) & ~BIT0;\r
412 TopaTable->TopaEntry[1] = (UINT64) TopaTableBaseAddr | BIT0;\r
413\r
414 //\r
415 // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[47:12] with ToPA base\r
416 //\r
417 MsrValue = (UINT64) TopaTableBaseAddr;\r
418 CPU_REGISTER_TABLE_WRITE64 (\r
419 ProcessorNumber,\r
420 Msr,\r
421 MSR_IA32_RTIT_OUTPUT_BASE,\r
422 MsrValue\r
423 );\r
424\r
425 //\r
426 // Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0\r
427 //\r
428 CPU_REGISTER_TABLE_WRITE64 (\r
429 ProcessorNumber,\r
430 Msr,\r
431 MSR_IA32_RTIT_OUTPUT_MASK_PTRS,\r
432 0x7F\r
433 );\r
434 //\r
435 // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)\r
436 //\r
437 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);\r
438 MsrValue |= BIT8;\r
439 CPU_REGISTER_TABLE_WRITE64 (\r
440 ProcessorNumber,\r
441 Msr,\r
442 MSR_IA32_RTIT_CTL,\r
443 MsrValue\r
444 );\r
445 }\r
446\r
447 ///\r
448 /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)\r
449 ///\r
450 MsrValue = AsmReadMsr64 (MSR_IA32_RTIT_CTL);\r
451 MsrValue |= (UINT64) BIT0 + BIT2 + BIT3 + BIT13;\r
452 if (!State) {\r
453 MsrValue &= (UINT64) ~BIT0;\r
454 }\r
455 CPU_REGISTER_TABLE_WRITE64 (\r
456 ProcessorNumber,\r
457 Msr,\r
458 MSR_IA32_RTIT_CTL,\r
459 MsrValue\r
460 );\r
461\r
462 return RETURN_SUCCESS;\r
463}\r