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