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