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