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