]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
UefiCpuPkg: Remove redundant library classes, Ppis and GUIDs
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmmProfile.c
CommitLineData
529a5a86
MK
1/** @file\r
2Enable SMM profile.\r
3\r
97f1061e 4Copyright (c) 2012 - 2017, Intel Corporation. All rights reserved.<BR>\r
241f9149
LD
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
6\r
529a5a86
MK
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "PiSmmCpuDxeSmm.h"\r
18#include "SmmProfileInternal.h"\r
19\r
20UINT32 mSmmProfileCr3;\r
21\r
22SMM_PROFILE_HEADER *mSmmProfileBase;\r
23MSR_DS_AREA_STRUCT *mMsrDsAreaBase;\r
24//\r
25// The buffer to store SMM profile data.\r
26//\r
27UINTN mSmmProfileSize;\r
28\r
29//\r
30// The buffer to enable branch trace store.\r
31//\r
32UINTN mMsrDsAreaSize = SMM_PROFILE_DTS_SIZE;\r
33\r
3c5ce64f
LE
34//\r
35// The flag indicates if execute-disable is supported by processor.\r
36//\r
37BOOLEAN mXdSupported = TRUE;\r
38\r
529a5a86
MK
39//\r
40// The flag indicates if execute-disable is enabled on processor.\r
41//\r
42BOOLEAN mXdEnabled = FALSE;\r
43\r
44//\r
45// The flag indicates if BTS is supported by processor.\r
46//\r
a46a4c90 47BOOLEAN mBtsSupported = TRUE;\r
529a5a86
MK
48\r
49//\r
50// The flag indicates if SMM profile starts to record data.\r
51//\r
52BOOLEAN mSmmProfileStart = FALSE;\r
53\r
09afd9a4
JW
54//\r
55// The flag indicates if #DB will be setup in #PF handler.\r
56//\r
57BOOLEAN mSetupDebugTrap = FALSE;\r
58\r
529a5a86
MK
59//\r
60// Record the page fault exception count for one instruction execution.\r
61//\r
62UINTN *mPFEntryCount;\r
63\r
64UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT];\r
65UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];\r
66\r
67MSR_DS_AREA_STRUCT **mMsrDsArea;\r
68BRANCH_TRACE_RECORD **mMsrBTSRecord;\r
69UINTN mBTSRecordNumber;\r
70PEBS_RECORD **mMsrPEBSRecord;\r
71\r
72//\r
73// These memory ranges are always present, they does not generate the access type of page fault exception,\r
74// but they possibly generate instruction fetch type of page fault exception.\r
75//\r
76MEMORY_PROTECTION_RANGE *mProtectionMemRange = NULL;\r
77UINTN mProtectionMemRangeCount = 0;\r
78\r
79//\r
80// Some predefined memory ranges.\r
81//\r
82MEMORY_PROTECTION_RANGE mProtectionMemRangeTemplate[] = {\r
83 //\r
84 // SMRAM range (to be fixed in runtime).\r
85 // It is always present and instruction fetches are allowed.\r
86 //\r
87 {{0x00000000, 0x00000000},TRUE,FALSE},\r
88\r
89 //\r
90 // SMM profile data range( to be fixed in runtime).\r
91 // It is always present and instruction fetches are not allowed.\r
92 //\r
93 {{0x00000000, 0x00000000},TRUE,TRUE},\r
94\r
ee584389
JF
95 //\r
96 // SMRAM ranges not covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz (to be fixed in runtime).\r
97 // It is always present and instruction fetches are allowed.\r
98 // {{0x00000000, 0x00000000},TRUE,FALSE},\r
99 //\r
100\r
529a5a86
MK
101 //\r
102 // Future extended range could be added here.\r
103 //\r
104\r
105 //\r
106 // PCI MMIO ranges (to be added in runtime).\r
107 // They are always present and instruction fetches are not allowed.\r
108 //\r
109};\r
110\r
111//\r
112// These memory ranges are mapped by 4KB-page instead of 2MB-page.\r
113//\r
114MEMORY_RANGE *mSplitMemRange = NULL;\r
115UINTN mSplitMemRangeCount = 0;\r
116\r
117//\r
118// SMI command port.\r
119//\r
120UINT32 mSmiCommandPort;\r
121\r
122/**\r
123 Disable branch trace store.\r
124\r
125**/\r
126VOID\r
127DisableBTS (\r
128 VOID\r
129 )\r
130{\r
131 AsmMsrAnd64 (MSR_DEBUG_CTL, ~((UINT64)(MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR)));\r
132}\r
133\r
134/**\r
135 Enable branch trace store.\r
136\r
137**/\r
138VOID\r
139EnableBTS (\r
140 VOID\r
141 )\r
142{\r
143 AsmMsrOr64 (MSR_DEBUG_CTL, (MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR));\r
144}\r
145\r
146/**\r
147 Get CPU Index from APIC ID.\r
148\r
149**/\r
150UINTN\r
151GetCpuIndex (\r
152 VOID\r
153 )\r
154{\r
155 UINTN Index;\r
156 UINT32 ApicId;\r
157\r
158 ApicId = GetApicId ();\r
159\r
bb767506 160 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
529a5a86
MK
161 if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) {\r
162 return Index;\r
163 }\r
164 }\r
165 ASSERT (FALSE);\r
166 return 0;\r
167}\r
168\r
169/**\r
170 Get the source of IP after execute-disable exception is triggered.\r
171\r
172 @param CpuIndex The index of CPU.\r
173 @param DestinationIP The destination address.\r
174\r
175**/\r
176UINT64\r
177GetSourceFromDestinationOnBts (\r
178 UINTN CpuIndex,\r
179 UINT64 DestinationIP\r
180 )\r
181{\r
182 BRANCH_TRACE_RECORD *CurrentBTSRecord;\r
183 UINTN Index;\r
184 BOOLEAN FirstMatch;\r
185\r
186 FirstMatch = FALSE;\r
187\r
188 CurrentBTSRecord = (BRANCH_TRACE_RECORD *)mMsrDsArea[CpuIndex]->BTSIndex;\r
189 for (Index = 0; Index < mBTSRecordNumber; Index++) {\r
190 if ((UINTN)CurrentBTSRecord < (UINTN)mMsrBTSRecord[CpuIndex]) {\r
191 //\r
192 // Underflow\r
193 //\r
194 CurrentBTSRecord = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[CpuIndex]->BTSAbsoluteMaximum - 1);\r
195 CurrentBTSRecord --;\r
196 }\r
197 if (CurrentBTSRecord->LastBranchTo == DestinationIP) {\r
198 //\r
199 // Good! find 1st one, then find 2nd one.\r
200 //\r
201 if (!FirstMatch) {\r
202 //\r
203 // The first one is DEBUG exception\r
204 //\r
205 FirstMatch = TRUE;\r
206 } else {\r
207 //\r
208 // Good find proper one.\r
209 //\r
210 return CurrentBTSRecord->LastBranchFrom;\r
211 }\r
212 }\r
213 CurrentBTSRecord--;\r
214 }\r
215\r
216 return 0;\r
217}\r
218\r
219/**\r
220 SMM profile specific INT 1 (single-step) exception handler.\r
221\r
222 @param InterruptType Defines the type of interrupt or exception that\r
223 occurred on the processor.This parameter is processor architecture specific.\r
224 @param SystemContext A pointer to the processor context when\r
225 the interrupt occurred on the processor.\r
226**/\r
227VOID\r
228EFIAPI\r
229DebugExceptionHandler (\r
230 IN EFI_EXCEPTION_TYPE InterruptType,\r
231 IN EFI_SYSTEM_CONTEXT SystemContext\r
232 )\r
233{\r
234 UINTN CpuIndex;\r
235 UINTN PFEntry;\r
236\r
09afd9a4
JW
237 if (!mSmmProfileStart &&\r
238 !HEAP_GUARD_NONSTOP_MODE &&\r
239 !NULL_DETECTION_NONSTOP_MODE) {\r
529a5a86
MK
240 return;\r
241 }\r
242 CpuIndex = GetCpuIndex ();\r
243\r
244 //\r
245 // Clear last PF entries\r
246 //\r
247 for (PFEntry = 0; PFEntry < mPFEntryCount[CpuIndex]; PFEntry++) {\r
248 *mLastPFEntryPointer[CpuIndex][PFEntry] = mLastPFEntryValue[CpuIndex][PFEntry];\r
249 }\r
250\r
251 //\r
252 // Reset page fault exception count for next page fault.\r
253 //\r
254 mPFEntryCount[CpuIndex] = 0;\r
255\r
256 //\r
257 // Flush TLB\r
258 //\r
259 CpuFlushTlb ();\r
260\r
261 //\r
262 // Clear TF in EFLAGS\r
263 //\r
264 ClearTrapFlag (SystemContext);\r
265}\r
266\r
97f1061e
JF
267/**\r
268 Check if the input address is in SMM ranges.\r
269\r
270 @param[in] Address The input address.\r
271\r
272 @retval TRUE The input address is in SMM.\r
273 @retval FALSE The input address is not in SMM.\r
274**/\r
275BOOLEAN\r
276IsInSmmRanges (\r
277 IN EFI_PHYSICAL_ADDRESS Address\r
278 )\r
279{\r
280 UINTN Index;\r
281\r
29dc8aa8 282 if ((Address >= mCpuHotPlugData.SmrrBase) && (Address < mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
97f1061e
JF
283 return TRUE;\r
284 }\r
285 for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {\r
286 if (Address >= mSmmCpuSmramRanges[Index].CpuStart &&\r
287 Address < mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize) {\r
288 return TRUE;\r
289 }\r
290 }\r
291 return FALSE;\r
292}\r
293\r
529a5a86
MK
294/**\r
295 Check if the memory address will be mapped by 4KB-page.\r
296\r
297 @param Address The address of Memory.\r
298 @param Nx The flag indicates if the memory is execute-disable.\r
299\r
300**/\r
301BOOLEAN\r
302IsAddressValid (\r
303 IN EFI_PHYSICAL_ADDRESS Address,\r
304 IN BOOLEAN *Nx\r
305 )\r
306{\r
307 UINTN Index;\r
308\r
529a5a86
MK
309 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
310 //\r
311 // Check configuration\r
312 //\r
313 for (Index = 0; Index < mProtectionMemRangeCount; Index++) {\r
314 if ((Address >= mProtectionMemRange[Index].Range.Base) && (Address < mProtectionMemRange[Index].Range.Top)) {\r
315 *Nx = mProtectionMemRange[Index].Nx;\r
316 return mProtectionMemRange[Index].Present;\r
317 }\r
318 }\r
319 *Nx = TRUE;\r
320 return FALSE;\r
321\r
322 } else {\r
97f1061e
JF
323 *Nx = TRUE;\r
324 if (IsInSmmRanges (Address)) {\r
325 *Nx = FALSE;\r
529a5a86
MK
326 }\r
327 return TRUE;\r
328 }\r
329}\r
330\r
331/**\r
332 Check if the memory address will be mapped by 4KB-page.\r
333\r
334 @param Address The address of Memory.\r
335\r
336**/\r
337BOOLEAN\r
338IsAddressSplit (\r
339 IN EFI_PHYSICAL_ADDRESS Address\r
340 )\r
341{\r
342 UINTN Index;\r
343\r
344 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
345 //\r
346 // Check configuration\r
347 //\r
348 for (Index = 0; Index < mSplitMemRangeCount; Index++) {\r
349 if ((Address >= mSplitMemRange[Index].Base) && (Address < mSplitMemRange[Index].Top)) {\r
350 return TRUE;\r
351 }\r
352 }\r
353 } else {\r
354 if (Address < mCpuHotPlugData.SmrrBase) {\r
355 if ((mCpuHotPlugData.SmrrBase - Address) < BASE_2MB) {\r
356 return TRUE;\r
357 }\r
358 } else if (Address > (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize - BASE_2MB)) {\r
359 if ((Address - (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize - BASE_2MB)) < BASE_2MB) {\r
360 return TRUE;\r
361 }\r
362 }\r
363 }\r
364 //\r
365 // Return default\r
366 //\r
367 return FALSE;\r
368}\r
369\r
370/**\r
371 Initialize the protected memory ranges and the 4KB-page mapped memory ranges.\r
372\r
373**/\r
374VOID\r
375InitProtectedMemRange (\r
376 VOID\r
377 )\r
378{\r
379 UINTN Index;\r
380 UINTN NumberOfDescriptors;\r
ee584389 381 UINTN NumberOfAddedDescriptors;\r
529a5a86
MK
382 UINTN NumberOfProtectRange;\r
383 UINTN NumberOfSpliteRange;\r
384 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
385 UINTN TotalSize;\r
529a5a86
MK
386 EFI_PHYSICAL_ADDRESS ProtectBaseAddress;\r
387 EFI_PHYSICAL_ADDRESS ProtectEndAddress;\r
388 EFI_PHYSICAL_ADDRESS Top2MBAlignedAddress;\r
389 EFI_PHYSICAL_ADDRESS Base2MBAlignedAddress;\r
390 UINT64 High4KBPageSize;\r
391 UINT64 Low4KBPageSize;\r
392\r
393 NumberOfDescriptors = 0;\r
ee584389 394 NumberOfAddedDescriptors = mSmmCpuSmramRangeCount;\r
529a5a86
MK
395 NumberOfSpliteRange = 0;\r
396 MemorySpaceMap = NULL;\r
397\r
398 //\r
399 // Get MMIO ranges from GCD and add them into protected memory ranges.\r
400 //\r
dc0a7143
LE
401 gDS->GetMemorySpaceMap (\r
402 &NumberOfDescriptors,\r
403 &MemorySpaceMap\r
404 );\r
529a5a86
MK
405 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
406 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
ee584389 407 NumberOfAddedDescriptors++;\r
529a5a86
MK
408 }\r
409 }\r
410\r
ee584389
JF
411 if (NumberOfAddedDescriptors != 0) {\r
412 TotalSize = NumberOfAddedDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate);\r
529a5a86
MK
413 mProtectionMemRange = (MEMORY_PROTECTION_RANGE *) AllocateZeroPool (TotalSize);\r
414 ASSERT (mProtectionMemRange != NULL);\r
415 mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE);\r
416\r
417 //\r
418 // Copy existing ranges.\r
419 //\r
420 CopyMem (mProtectionMemRange, mProtectionMemRangeTemplate, sizeof (mProtectionMemRangeTemplate));\r
421\r
422 //\r
423 // Create split ranges which come from protected ranges.\r
424 //\r
425 TotalSize = (TotalSize / sizeof (MEMORY_PROTECTION_RANGE)) * sizeof (MEMORY_RANGE);\r
426 mSplitMemRange = (MEMORY_RANGE *) AllocateZeroPool (TotalSize);\r
427 ASSERT (mSplitMemRange != NULL);\r
428\r
ee584389
JF
429 //\r
430 // Create SMM ranges which are set to present and execution-enable.\r
431 //\r
432 NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);\r
433 for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {\r
434 if (mSmmCpuSmramRanges[Index].CpuStart >= mProtectionMemRange[0].Range.Base &&\r
435 mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize < mProtectionMemRange[0].Range.Top) {\r
436 //\r
437 // If the address have been already covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz\r
438 //\r
439 break;\r
440 }\r
441 mProtectionMemRange[NumberOfProtectRange].Range.Base = mSmmCpuSmramRanges[Index].CpuStart;\r
442 mProtectionMemRange[NumberOfProtectRange].Range.Top = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize;\r
443 mProtectionMemRange[NumberOfProtectRange].Present = TRUE;\r
444 mProtectionMemRange[NumberOfProtectRange].Nx = FALSE;\r
445 NumberOfProtectRange++;\r
446 }\r
447\r
529a5a86
MK
448 //\r
449 // Create MMIO ranges which are set to present and execution-disable.\r
450 //\r
529a5a86
MK
451 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
452 if (MemorySpaceMap[Index].GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
453 continue;\r
454 }\r
455 mProtectionMemRange[NumberOfProtectRange].Range.Base = MemorySpaceMap[Index].BaseAddress;\r
456 mProtectionMemRange[NumberOfProtectRange].Range.Top = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length;\r
457 mProtectionMemRange[NumberOfProtectRange].Present = TRUE;\r
458 mProtectionMemRange[NumberOfProtectRange].Nx = TRUE;\r
459 NumberOfProtectRange++;\r
460 }\r
ee584389
JF
461\r
462 //\r
463 // Check and updated actual protected memory ranges count\r
464 //\r
465 ASSERT (NumberOfProtectRange <= mProtectionMemRangeCount);\r
466 mProtectionMemRangeCount = NumberOfProtectRange;\r
529a5a86
MK
467 }\r
468\r
469 //\r
470 // According to protected ranges, create the ranges which will be mapped by 2KB page.\r
471 //\r
472 NumberOfSpliteRange = 0;\r
473 NumberOfProtectRange = mProtectionMemRangeCount;\r
474 for (Index = 0; Index < NumberOfProtectRange; Index++) {\r
475 //\r
476 // If MMIO base address is not 2MB alignment, make 2MB alignment for create 4KB page in page table.\r
477 //\r
478 ProtectBaseAddress = mProtectionMemRange[Index].Range.Base;\r
479 ProtectEndAddress = mProtectionMemRange[Index].Range.Top;\r
480 if (((ProtectBaseAddress & (SIZE_2MB - 1)) != 0) || ((ProtectEndAddress & (SIZE_2MB - 1)) != 0)) {\r
481 //\r
482 // Check if it is possible to create 4KB-page for not 2MB-aligned range and to create 2MB-page for 2MB-aligned range.\r
483 // A mix of 4KB and 2MB page could save SMRAM space.\r
484 //\r
485 Top2MBAlignedAddress = ProtectEndAddress & ~(SIZE_2MB - 1);\r
486 Base2MBAlignedAddress = (ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);\r
487 if ((Top2MBAlignedAddress > Base2MBAlignedAddress) &&\r
488 ((Top2MBAlignedAddress - Base2MBAlignedAddress) >= SIZE_2MB)) {\r
489 //\r
490 // There is an range which could be mapped by 2MB-page.\r
491 //\r
492 High4KBPageSize = ((ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1)) - (ProtectEndAddress & ~(SIZE_2MB - 1));\r
493 Low4KBPageSize = ((ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1)) - (ProtectBaseAddress & ~(SIZE_2MB - 1));\r
494 if (High4KBPageSize != 0) {\r
495 //\r
496 // Add not 2MB-aligned range to be mapped by 4KB-page.\r
497 //\r
498 mSplitMemRange[NumberOfSpliteRange].Base = ProtectEndAddress & ~(SIZE_2MB - 1);\r
499 mSplitMemRange[NumberOfSpliteRange].Top = (ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);\r
500 NumberOfSpliteRange++;\r
501 }\r
502 if (Low4KBPageSize != 0) {\r
503 //\r
504 // Add not 2MB-aligned range to be mapped by 4KB-page.\r
505 //\r
506 mSplitMemRange[NumberOfSpliteRange].Base = ProtectBaseAddress & ~(SIZE_2MB - 1);\r
507 mSplitMemRange[NumberOfSpliteRange].Top = (ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);\r
508 NumberOfSpliteRange++;\r
509 }\r
510 } else {\r
511 //\r
512 // The range could only be mapped by 4KB-page.\r
513 //\r
514 mSplitMemRange[NumberOfSpliteRange].Base = ProtectBaseAddress & ~(SIZE_2MB - 1);\r
515 mSplitMemRange[NumberOfSpliteRange].Top = (ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);\r
516 NumberOfSpliteRange++;\r
517 }\r
518 }\r
519 }\r
520\r
521 mSplitMemRangeCount = NumberOfSpliteRange;\r
522\r
523 DEBUG ((EFI_D_INFO, "SMM Profile Memory Ranges:\n"));\r
524 for (Index = 0; Index < mProtectionMemRangeCount; Index++) {\r
525 DEBUG ((EFI_D_INFO, "mProtectionMemRange[%d].Base = %lx\n", Index, mProtectionMemRange[Index].Range.Base));\r
526 DEBUG ((EFI_D_INFO, "mProtectionMemRange[%d].Top = %lx\n", Index, mProtectionMemRange[Index].Range.Top));\r
527 }\r
528 for (Index = 0; Index < mSplitMemRangeCount; Index++) {\r
529 DEBUG ((EFI_D_INFO, "mSplitMemRange[%d].Base = %lx\n", Index, mSplitMemRange[Index].Base));\r
530 DEBUG ((EFI_D_INFO, "mSplitMemRange[%d].Top = %lx\n", Index, mSplitMemRange[Index].Top));\r
531 }\r
532}\r
533\r
534/**\r
535 Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.\r
536\r
537**/\r
538VOID\r
539InitPaging (\r
540 VOID\r
541 )\r
542{\r
543 UINT64 *Pml4;\r
544 UINT64 *Pde;\r
545 UINT64 *Pte;\r
546 UINT64 *Pt;\r
547 UINTN Address;\r
548 UINTN Level1;\r
549 UINTN Level2;\r
550 UINTN Level3;\r
551 UINTN Level4;\r
552 UINTN NumberOfPdpEntries;\r
553 UINTN NumberOfPml4Entries;\r
554 UINTN SizeOfMemorySpace;\r
555 BOOLEAN Nx;\r
556\r
557 if (sizeof (UINTN) == sizeof (UINT64)) {\r
558 Pml4 = (UINT64*)(UINTN)mSmmProfileCr3;\r
559 SizeOfMemorySpace = HighBitSet64 (gPhyMask) + 1;\r
560 //\r
561 // Calculate the table entries of PML4E and PDPTE.\r
562 //\r
563 if (SizeOfMemorySpace <= 39 ) {\r
564 NumberOfPml4Entries = 1;\r
565 NumberOfPdpEntries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 30));\r
566 } else {\r
567 NumberOfPml4Entries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 39));\r
568 NumberOfPdpEntries = 512;\r
569 }\r
570 } else {\r
571 NumberOfPml4Entries = 1;\r
572 NumberOfPdpEntries = 4;\r
573 }\r
574\r
575 //\r
576 // Go through page table and change 2MB-page into 4KB-page.\r
577 //\r
578 for (Level1 = 0; Level1 < NumberOfPml4Entries; Level1++) {\r
579 if (sizeof (UINTN) == sizeof (UINT64)) {\r
580 if ((Pml4[Level1] & IA32_PG_P) == 0) {\r
581 //\r
582 // If Pml4 entry does not exist, skip it\r
583 //\r
584 continue;\r
585 }\r
241f9149 586 Pde = (UINT64 *)(UINTN)(Pml4[Level1] & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);\r
529a5a86
MK
587 } else {\r
588 Pde = (UINT64*)(UINTN)mSmmProfileCr3;\r
589 }\r
590 for (Level2 = 0; Level2 < NumberOfPdpEntries; Level2++, Pde++) {\r
591 if ((*Pde & IA32_PG_P) == 0) {\r
592 //\r
593 // If PDE entry does not exist, skip it\r
594 //\r
595 continue;\r
596 }\r
717fb604
JY
597 if ((*Pde & IA32_PG_PS) != 0) {\r
598 //\r
599 // This is 1G entry, skip it\r
600 //\r
601 continue;\r
602 }\r
241f9149 603 Pte = (UINT64 *)(UINTN)(*Pde & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);\r
529a5a86
MK
604 if (Pte == 0) {\r
605 continue;\r
606 }\r
607 for (Level3 = 0; Level3 < SIZE_4KB / sizeof (*Pte); Level3++, Pte++) {\r
608 if ((*Pte & IA32_PG_P) == 0) {\r
609 //\r
610 // If PTE entry does not exist, skip it\r
611 //\r
612 continue;\r
613 }\r
614 Address = (((Level2 << 9) + Level3) << 21);\r
615\r
616 //\r
617 // If it is 2M page, check IsAddressSplit()\r
618 //\r
619 if (((*Pte & IA32_PG_PS) != 0) && IsAddressSplit (Address)) {\r
620 //\r
621 // Based on current page table, create 4KB page table for split area.\r
622 //\r
623 ASSERT (Address == (*Pte & PHYSICAL_ADDRESS_MASK));\r
624\r
21c17193 625 Pt = AllocatePageTableMemory (1);\r
529a5a86
MK
626 ASSERT (Pt != NULL);\r
627\r
628 // Split it\r
629 for (Level4 = 0; Level4 < SIZE_4KB / sizeof(*Pt); Level4++) {\r
241f9149 630 Pt[Level4] = Address + ((Level4 << 12) | mAddressEncMask | PAGE_ATTRIBUTE_BITS);\r
529a5a86 631 } // end for PT\r
241f9149 632 *Pte = (UINT64)(UINTN)Pt | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
529a5a86
MK
633 } // end if IsAddressSplit\r
634 } // end for PTE\r
635 } // end for PDE\r
636 }\r
637\r
638 //\r
639 // Go through page table and set several page table entries to absent or execute-disable.\r
640 //\r
641 DEBUG ((EFI_D_INFO, "Patch page table start ...\n"));\r
642 for (Level1 = 0; Level1 < NumberOfPml4Entries; Level1++) {\r
643 if (sizeof (UINTN) == sizeof (UINT64)) {\r
644 if ((Pml4[Level1] & IA32_PG_P) == 0) {\r
645 //\r
646 // If Pml4 entry does not exist, skip it\r
647 //\r
648 continue;\r
649 }\r
241f9149 650 Pde = (UINT64 *)(UINTN)(Pml4[Level1] & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);\r
529a5a86
MK
651 } else {\r
652 Pde = (UINT64*)(UINTN)mSmmProfileCr3;\r
653 }\r
654 for (Level2 = 0; Level2 < NumberOfPdpEntries; Level2++, Pde++) {\r
655 if ((*Pde & IA32_PG_P) == 0) {\r
656 //\r
657 // If PDE entry does not exist, skip it\r
658 //\r
659 continue;\r
660 }\r
717fb604
JY
661 if ((*Pde & IA32_PG_PS) != 0) {\r
662 //\r
663 // This is 1G entry, set NX bit and skip it\r
664 //\r
665 if (mXdSupported) {\r
666 *Pde = *Pde | IA32_PG_NX;\r
667 }\r
668 continue;\r
669 }\r
241f9149 670 Pte = (UINT64 *)(UINTN)(*Pde & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);\r
529a5a86
MK
671 if (Pte == 0) {\r
672 continue;\r
673 }\r
674 for (Level3 = 0; Level3 < SIZE_4KB / sizeof (*Pte); Level3++, Pte++) {\r
675 if ((*Pte & IA32_PG_P) == 0) {\r
676 //\r
677 // If PTE entry does not exist, skip it\r
678 //\r
679 continue;\r
680 }\r
681 Address = (((Level2 << 9) + Level3) << 21);\r
682\r
683 if ((*Pte & IA32_PG_PS) != 0) {\r
684 // 2MB page\r
685\r
686 if (!IsAddressValid (Address, &Nx)) {\r
687 //\r
688 // Patch to remove Present flag and RW flag\r
689 //\r
881520ea 690 *Pte = *Pte & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);\r
529a5a86
MK
691 }\r
692 if (Nx && mXdSupported) {\r
693 *Pte = *Pte | IA32_PG_NX;\r
694 }\r
695 } else {\r
696 // 4KB page\r
241f9149 697 Pt = (UINT64 *)(UINTN)(*Pte & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);\r
529a5a86
MK
698 if (Pt == 0) {\r
699 continue;\r
700 }\r
701 for (Level4 = 0; Level4 < SIZE_4KB / sizeof(*Pt); Level4++, Pt++) {\r
702 if (!IsAddressValid (Address, &Nx)) {\r
881520ea 703 *Pt = *Pt & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);\r
529a5a86
MK
704 }\r
705 if (Nx && mXdSupported) {\r
706 *Pt = *Pt | IA32_PG_NX;\r
707 }\r
708 Address += SIZE_4KB;\r
709 } // end for PT\r
710 } // end if PS\r
711 } // end for PTE\r
712 } // end for PDE\r
713 }\r
714\r
715 //\r
716 // Flush TLB\r
717 //\r
718 CpuFlushTlb ();\r
719 DEBUG ((EFI_D_INFO, "Patch page table done!\n"));\r
720 //\r
721 // Set execute-disable flag\r
722 //\r
723 mXdEnabled = TRUE;\r
724\r
725 return ;\r
726}\r
727\r
728/**\r
729 To find FADT in ACPI tables.\r
730\r
731 @param AcpiTableGuid The GUID used to find ACPI table in UEFI ConfigurationTable.\r
732\r
733 @return FADT table pointer.\r
734**/\r
735EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *\r
736FindAcpiFadtTableByAcpiGuid (\r
737 IN EFI_GUID *AcpiTableGuid\r
738 )\r
739{\r
740 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;\r
741 EFI_ACPI_DESCRIPTION_HEADER *Rsdt;\r
742 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
743 UINTN Index;\r
744 UINT32 Data32;\r
745 Rsdp = NULL;\r
746 Rsdt = NULL;\r
747 Fadt = NULL;\r
748 //\r
749 // found ACPI table RSD_PTR from system table\r
750 //\r
751 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
752 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {\r
753 //\r
754 // A match was found.\r
755 //\r
756 Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
757 break;\r
758 }\r
759 }\r
760\r
761 if (Rsdp == NULL) {\r
762 return NULL;\r
763 }\r
764\r
765 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;\r
766 if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {\r
767 return NULL;\r
768 }\r
769\r
770 for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) {\r
771\r
772 Data32 = *(UINT32 *) ((UINT8 *) Rsdt + Index);\r
773 Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32;\r
774 if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
775 break;\r
776 }\r
777 }\r
778\r
779 if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
780 return NULL;\r
781 }\r
782\r
783 return Fadt;\r
784}\r
785\r
786/**\r
787 To find FADT in ACPI tables.\r
788\r
789 @return FADT table pointer.\r
790**/\r
791EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *\r
792FindAcpiFadtTable (\r
793 VOID\r
794 )\r
795{\r
796 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
797\r
798 Fadt = FindAcpiFadtTableByAcpiGuid (&gEfiAcpi20TableGuid);\r
799 if (Fadt != NULL) {\r
800 return Fadt;\r
801 }\r
802\r
803 return FindAcpiFadtTableByAcpiGuid (&gEfiAcpi10TableGuid);\r
804}\r
805\r
806/**\r
807 To get system port address of the SMI Command Port in FADT table.\r
808\r
809**/\r
810VOID\r
811GetSmiCommandPort (\r
812 VOID\r
813 )\r
814{\r
815 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
816\r
817 Fadt = FindAcpiFadtTable ();\r
818 ASSERT (Fadt != NULL);\r
819\r
820 mSmiCommandPort = Fadt->SmiCmd;\r
821 DEBUG ((EFI_D_INFO, "mSmiCommandPort = %x\n", mSmiCommandPort));\r
822}\r
823\r
824/**\r
825 Updates page table to make some memory ranges (like system memory) absent\r
826 and make some memory ranges (like MMIO) present and execute disable. It also\r
827 update 2MB-page to 4KB-page for some memory ranges.\r
828\r
829**/\r
830VOID\r
831SmmProfileStart (\r
832 VOID\r
833 )\r
834{\r
835 //\r
836 // The flag indicates SMM profile starts to work.\r
837 //\r
838 mSmmProfileStart = TRUE;\r
839}\r
840\r
841/**\r
842 Initialize SMM profile in SmmReadyToLock protocol callback function.\r
843\r
844 @param Protocol Points to the protocol's unique identifier.\r
845 @param Interface Points to the interface instance.\r
846 @param Handle The handle on which the interface was installed.\r
847\r
848 @retval EFI_SUCCESS SmmReadyToLock protocol callback runs successfully.\r
849**/\r
850EFI_STATUS\r
851EFIAPI\r
852InitSmmProfileCallBack (\r
853 IN CONST EFI_GUID *Protocol,\r
854 IN VOID *Interface,\r
855 IN EFI_HANDLE Handle\r
856 )\r
857{\r
529a5a86
MK
858 //\r
859 // Save to variable so that SMM profile data can be found.\r
860 //\r
dc0a7143
LE
861 gRT->SetVariable (\r
862 SMM_PROFILE_NAME,\r
863 &gEfiCallerIdGuid,\r
864 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
865 sizeof(mSmmProfileBase),\r
866 &mSmmProfileBase\r
867 );\r
529a5a86
MK
868\r
869 //\r
870 // Get Software SMI from FADT\r
871 //\r
872 GetSmiCommandPort ();\r
873\r
874 //\r
875 // Initialize protected memory range for patching page table later.\r
876 //\r
877 InitProtectedMemRange ();\r
878\r
879 return EFI_SUCCESS;\r
880}\r
881\r
882/**\r
883 Initialize SMM profile data structures.\r
884\r
885**/\r
886VOID\r
887InitSmmProfileInternal (\r
888 VOID\r
889 )\r
890{\r
891 EFI_STATUS Status;\r
892 EFI_PHYSICAL_ADDRESS Base;\r
893 VOID *Registration;\r
894 UINTN Index;\r
895 UINTN MsrDsAreaSizePerCpu;\r
896 UINTN TotalSize;\r
897\r
bb767506 898 mPFEntryCount = (UINTN *)AllocateZeroPool (sizeof (UINTN) * mMaxNumberOfCpus);\r
529a5a86
MK
899 ASSERT (mPFEntryCount != NULL);\r
900 mLastPFEntryValue = (UINT64 (*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool (\r
bb767506 901 sizeof (mLastPFEntryValue[0]) * mMaxNumberOfCpus);\r
529a5a86
MK
902 ASSERT (mLastPFEntryValue != NULL);\r
903 mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool (\r
bb767506 904 sizeof (mLastPFEntryPointer[0]) * mMaxNumberOfCpus);\r
529a5a86
MK
905 ASSERT (mLastPFEntryPointer != NULL);\r
906\r
907 //\r
908 // Allocate memory for SmmProfile below 4GB.\r
909 // The base address\r
910 //\r
911 mSmmProfileSize = PcdGet32 (PcdCpuSmmProfileSize);\r
912 ASSERT ((mSmmProfileSize & 0xFFF) == 0);\r
913\r
914 if (mBtsSupported) {\r
915 TotalSize = mSmmProfileSize + mMsrDsAreaSize;\r
916 } else {\r
917 TotalSize = mSmmProfileSize;\r
918 }\r
919\r
920 Base = 0xFFFFFFFF;\r
921 Status = gBS->AllocatePages (\r
922 AllocateMaxAddress,\r
923 EfiReservedMemoryType,\r
924 EFI_SIZE_TO_PAGES (TotalSize),\r
925 &Base\r
926 );\r
927 ASSERT_EFI_ERROR (Status);\r
928 ZeroMem ((VOID *)(UINTN)Base, TotalSize);\r
929 mSmmProfileBase = (SMM_PROFILE_HEADER *)(UINTN)Base;\r
930\r
931 //\r
932 // Initialize SMM profile data header.\r
933 //\r
934 mSmmProfileBase->HeaderSize = sizeof (SMM_PROFILE_HEADER);\r
935 mSmmProfileBase->MaxDataEntries = (UINT64)((mSmmProfileSize - sizeof(SMM_PROFILE_HEADER)) / sizeof (SMM_PROFILE_ENTRY));\r
936 mSmmProfileBase->MaxDataSize = MultU64x64 (mSmmProfileBase->MaxDataEntries, sizeof(SMM_PROFILE_ENTRY));\r
937 mSmmProfileBase->CurDataEntries = 0;\r
938 mSmmProfileBase->CurDataSize = 0;\r
939 mSmmProfileBase->TsegStart = mCpuHotPlugData.SmrrBase;\r
940 mSmmProfileBase->TsegSize = mCpuHotPlugData.SmrrSize;\r
941 mSmmProfileBase->NumSmis = 0;\r
942 mSmmProfileBase->NumCpus = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
943\r
944 if (mBtsSupported) {\r
bb767506 945 mMsrDsArea = (MSR_DS_AREA_STRUCT **)AllocateZeroPool (sizeof (MSR_DS_AREA_STRUCT *) * mMaxNumberOfCpus);\r
529a5a86 946 ASSERT (mMsrDsArea != NULL);\r
bb767506 947 mMsrBTSRecord = (BRANCH_TRACE_RECORD **)AllocateZeroPool (sizeof (BRANCH_TRACE_RECORD *) * mMaxNumberOfCpus);\r
529a5a86 948 ASSERT (mMsrBTSRecord != NULL);\r
bb767506 949 mMsrPEBSRecord = (PEBS_RECORD **)AllocateZeroPool (sizeof (PEBS_RECORD *) * mMaxNumberOfCpus);\r
529a5a86
MK
950 ASSERT (mMsrPEBSRecord != NULL);\r
951\r
952 mMsrDsAreaBase = (MSR_DS_AREA_STRUCT *)((UINTN)Base + mSmmProfileSize);\r
bb767506 953 MsrDsAreaSizePerCpu = mMsrDsAreaSize / mMaxNumberOfCpus;\r
529a5a86 954 mBTSRecordNumber = (MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER - sizeof(MSR_DS_AREA_STRUCT)) / sizeof(BRANCH_TRACE_RECORD);\r
bb767506 955 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
529a5a86
MK
956 mMsrDsArea[Index] = (MSR_DS_AREA_STRUCT *)((UINTN)mMsrDsAreaBase + MsrDsAreaSizePerCpu * Index);\r
957 mMsrBTSRecord[Index] = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[Index] + sizeof(MSR_DS_AREA_STRUCT));\r
958 mMsrPEBSRecord[Index] = (PEBS_RECORD *)((UINTN)mMsrDsArea[Index] + MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER);\r
959\r
960 mMsrDsArea[Index]->BTSBufferBase = (UINTN)mMsrBTSRecord[Index];\r
961 mMsrDsArea[Index]->BTSIndex = mMsrDsArea[Index]->BTSBufferBase;\r
962 mMsrDsArea[Index]->BTSAbsoluteMaximum = mMsrDsArea[Index]->BTSBufferBase + mBTSRecordNumber * sizeof(BRANCH_TRACE_RECORD) + 1;\r
963 mMsrDsArea[Index]->BTSInterruptThreshold = mMsrDsArea[Index]->BTSAbsoluteMaximum + 1;\r
964\r
965 mMsrDsArea[Index]->PEBSBufferBase = (UINTN)mMsrPEBSRecord[Index];\r
966 mMsrDsArea[Index]->PEBSIndex = mMsrDsArea[Index]->PEBSBufferBase;\r
967 mMsrDsArea[Index]->PEBSAbsoluteMaximum = mMsrDsArea[Index]->PEBSBufferBase + PEBS_RECORD_NUMBER * sizeof(PEBS_RECORD) + 1;\r
968 mMsrDsArea[Index]->PEBSInterruptThreshold = mMsrDsArea[Index]->PEBSAbsoluteMaximum + 1;\r
969 }\r
970 }\r
971\r
972 mProtectionMemRange = mProtectionMemRangeTemplate;\r
973 mProtectionMemRangeCount = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);\r
974\r
975 //\r
976 // Update TSeg entry.\r
977 //\r
978 mProtectionMemRange[0].Range.Base = mCpuHotPlugData.SmrrBase;\r
979 mProtectionMemRange[0].Range.Top = mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize;\r
980\r
981 //\r
982 // Update SMM profile entry.\r
983 //\r
984 mProtectionMemRange[1].Range.Base = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase;\r
985 mProtectionMemRange[1].Range.Top = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase + TotalSize;\r
986\r
987 //\r
988 // Allocate memory reserved for creating 4KB pages.\r
989 //\r
990 InitPagesForPFHandler ();\r
991\r
992 //\r
993 // Start SMM profile when SmmReadyToLock protocol is installed.\r
994 //\r
995 Status = gSmst->SmmRegisterProtocolNotify (\r
996 &gEfiSmmReadyToLockProtocolGuid,\r
997 InitSmmProfileCallBack,\r
998 &Registration\r
999 );\r
1000 ASSERT_EFI_ERROR (Status);\r
1001\r
1002 return ;\r
1003}\r
1004\r
1005/**\r
1006 Check if XD feature is supported by a processor.\r
1007\r
1008**/\r
1009VOID\r
1010CheckFeatureSupported (\r
51773d49 1011 VOID\r
529a5a86
MK
1012 )\r
1013{\r
f85d3ce2
JF
1014 UINT32 RegEax;\r
1015 UINT32 RegEdx;\r
1016 MSR_IA32_MISC_ENABLE_REGISTER MiscEnableMsr;\r
529a5a86
MK
1017\r
1018 if (mXdSupported) {\r
1019 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
1020 if (RegEax <= CPUID_EXTENDED_FUNCTION) {\r
1021 //\r
1022 // Extended CPUID functions are not supported on this processor.\r
1023 //\r
1024 mXdSupported = FALSE;\r
3c5ce64f 1025 PatchInstructionX86 (gPatchXdSupported, mXdSupported, 1);\r
529a5a86
MK
1026 }\r
1027\r
1028 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
1029 if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {\r
1030 //\r
1031 // Execute Disable Bit feature is not supported on this processor.\r
1032 //\r
1033 mXdSupported = FALSE;\r
3c5ce64f 1034 PatchInstructionX86 (gPatchXdSupported, mXdSupported, 1);\r
529a5a86
MK
1035 }\r
1036 }\r
1037\r
1038 if (mBtsSupported) {\r
1039 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);\r
1040 if ((RegEdx & CPUID1_EDX_BTS_AVAILABLE) != 0) {\r
1041 //\r
1042 // Per IA32 manuals:\r
1043 // When CPUID.1:EDX[21] is set, the following BTS facilities are available:\r
1044 // 1. The BTS_UNAVAILABLE flag in the IA32_MISC_ENABLE MSR indicates the\r
1045 // availability of the BTS facilities, including the ability to set the BTS and\r
1046 // BTINT bits in the MSR_DEBUGCTLA MSR.\r
1047 // 2. The IA32_DS_AREA MSR can be programmed to point to the DS save area.\r
1048 //\r
f85d3ce2
JF
1049 MiscEnableMsr.Uint64 = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);\r
1050 if (MiscEnableMsr.Bits.BTS == 1) {\r
529a5a86 1051 //\r
f85d3ce2 1052 // BTS facilities is not supported if MSR_IA32_MISC_ENABLE.BTS bit is set.\r
529a5a86
MK
1053 //\r
1054 mBtsSupported = FALSE;\r
1055 }\r
1056 }\r
1057 }\r
1058}\r
1059\r
529a5a86
MK
1060/**\r
1061 Enable single step.\r
1062\r
1063**/\r
1064VOID\r
1065ActivateSingleStepDB (\r
1066 VOID\r
1067 )\r
1068{\r
1069 UINTN Dr6;\r
1070\r
1071 Dr6 = AsmReadDr6 ();\r
1072 if ((Dr6 & DR6_SINGLE_STEP) != 0) {\r
1073 return;\r
1074 }\r
1075 Dr6 |= DR6_SINGLE_STEP;\r
1076 AsmWriteDr6 (Dr6);\r
1077}\r
1078\r
1079/**\r
1080 Enable last branch.\r
1081\r
1082**/\r
1083VOID\r
1084ActivateLBR (\r
1085 VOID\r
1086 )\r
1087{\r
1088 UINT64 DebugCtl;\r
1089\r
1090 DebugCtl = AsmReadMsr64 (MSR_DEBUG_CTL);\r
1091 if ((DebugCtl & MSR_DEBUG_CTL_LBR) != 0) {\r
1092 return ;\r
1093 }\r
529a5a86
MK
1094 DebugCtl |= MSR_DEBUG_CTL_LBR;\r
1095 AsmWriteMsr64 (MSR_DEBUG_CTL, DebugCtl);\r
1096}\r
1097\r
1098/**\r
1099 Enable branch trace store.\r
1100\r
1101 @param CpuIndex The index of the processor.\r
1102\r
1103**/\r
1104VOID\r
1105ActivateBTS (\r
1106 IN UINTN CpuIndex\r
1107 )\r
1108{\r
1109 UINT64 DebugCtl;\r
1110\r
1111 DebugCtl = AsmReadMsr64 (MSR_DEBUG_CTL);\r
1112 if ((DebugCtl & MSR_DEBUG_CTL_BTS) != 0) {\r
1113 return ;\r
1114 }\r
1115\r
1116 AsmWriteMsr64 (MSR_DS_AREA, (UINT64)(UINTN)mMsrDsArea[CpuIndex]);\r
1117 DebugCtl |= (UINT64)(MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR);\r
1118 DebugCtl &= ~((UINT64)MSR_DEBUG_CTL_BTINT);\r
1119 AsmWriteMsr64 (MSR_DEBUG_CTL, DebugCtl);\r
1120}\r
1121\r
1122/**\r
1123 Increase SMI number in each SMI entry.\r
1124\r
1125**/\r
1126VOID\r
1127SmmProfileRecordSmiNum (\r
1128 VOID\r
1129 )\r
1130{\r
1131 if (mSmmProfileStart) {\r
1132 mSmmProfileBase->NumSmis++;\r
1133 }\r
1134}\r
1135\r
1136/**\r
1137 Initialize processor environment for SMM profile.\r
1138\r
1139 @param CpuIndex The index of the processor.\r
1140\r
1141**/\r
1142VOID\r
1143ActivateSmmProfile (\r
1144 IN UINTN CpuIndex\r
1145 )\r
1146{\r
1147 //\r
1148 // Enable Single Step DB#\r
1149 //\r
1150 ActivateSingleStepDB ();\r
1151\r
1152 if (mBtsSupported) {\r
1153 //\r
1154 // We can not get useful information from LER, so we have to use BTS.\r
1155 //\r
1156 ActivateLBR ();\r
1157\r
1158 //\r
1159 // Enable BTS\r
1160 //\r
1161 ActivateBTS (CpuIndex);\r
1162 }\r
1163}\r
1164\r
1165/**\r
1166 Initialize SMM profile in SMM CPU entry point.\r
1167\r
1168 @param[in] Cr3 The base address of the page tables to use in SMM.\r
1169\r
1170**/\r
1171VOID\r
1172InitSmmProfile (\r
1173 UINT32 Cr3\r
1174 )\r
1175{\r
1176 //\r
1177 // Save Cr3\r
1178 //\r
1179 mSmmProfileCr3 = Cr3;\r
1180\r
1181 //\r
1182 // Skip SMM profile initialization if feature is disabled\r
1183 //\r
09afd9a4
JW
1184 if (!FeaturePcdGet (PcdCpuSmmProfileEnable) &&\r
1185 !HEAP_GUARD_NONSTOP_MODE &&\r
1186 !NULL_DETECTION_NONSTOP_MODE) {\r
529a5a86
MK
1187 return;\r
1188 }\r
1189\r
1190 //\r
1191 // Initialize SmmProfile here\r
1192 //\r
1193 InitSmmProfileInternal ();\r
1194\r
1195 //\r
1196 // Initialize profile IDT.\r
1197 //\r
1198 InitIdtr ();\r
09afd9a4
JW
1199\r
1200 //\r
1201 // Tell #PF handler to prepare a #DB subsequently.\r
1202 //\r
1203 mSetupDebugTrap = TRUE;\r
529a5a86
MK
1204}\r
1205\r
1206/**\r
1207 Update page table to map the memory correctly in order to make the instruction\r
1208 which caused page fault execute successfully. And it also save the original page\r
1209 table to be restored in single-step exception.\r
1210\r
1211 @param PageTable PageTable Address.\r
1212 @param PFAddress The memory address which caused page fault exception.\r
1213 @param CpuIndex The index of the processor.\r
1214 @param ErrorCode The Error code of exception.\r
1215\r
1216**/\r
1217VOID\r
1218RestorePageTableBelow4G (\r
1219 UINT64 *PageTable,\r
1220 UINT64 PFAddress,\r
1221 UINTN CpuIndex,\r
1222 UINTN ErrorCode\r
1223 )\r
1224{\r
1225 UINTN PTIndex;\r
1226 UINTN PFIndex;\r
1227\r
1228 //\r
1229 // PML4\r
1230 //\r
1231 if (sizeof(UINT64) == sizeof(UINTN)) {\r
1232 PTIndex = (UINTN)BitFieldRead64 (PFAddress, 39, 47);\r
1233 ASSERT (PageTable[PTIndex] != 0);\r
1234 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);\r
1235 }\r
1236\r
1237 //\r
1238 // PDPTE\r
1239 //\r
1240 PTIndex = (UINTN)BitFieldRead64 (PFAddress, 30, 38);\r
1241 ASSERT (PageTable[PTIndex] != 0);\r
1242 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);\r
1243\r
1244 //\r
1245 // PD\r
1246 //\r
1247 PTIndex = (UINTN)BitFieldRead64 (PFAddress, 21, 29);\r
1248 if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {\r
1249 //\r
1250 // Large page\r
1251 //\r
1252\r
1253 //\r
1254 // Record old entries with non-present status\r
1255 // Old entries include the memory which instruction is at and the memory which instruction access.\r
1256 //\r
1257 //\r
1258 ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT);\r
1259 if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) {\r
1260 PFIndex = mPFEntryCount[CpuIndex];\r
1261 mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex];\r
1262 mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex];\r
1263 mPFEntryCount[CpuIndex]++;\r
1264 }\r
1265\r
1266 //\r
1267 // Set new entry\r
1268 //\r
1269 PageTable[PTIndex] = (PFAddress & ~((1ull << 21) - 1));\r
1270 PageTable[PTIndex] |= (UINT64)IA32_PG_PS;\r
881520ea 1271 PageTable[PTIndex] |= (UINT64)PAGE_ATTRIBUTE_BITS;\r
529a5a86
MK
1272 if ((ErrorCode & IA32_PF_EC_ID) != 0) {\r
1273 PageTable[PTIndex] &= ~IA32_PG_NX;\r
1274 }\r
1275 } else {\r
1276 //\r
1277 // Small page\r
1278 //\r
1279 ASSERT (PageTable[PTIndex] != 0);\r
1280 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);\r
1281\r
1282 //\r
1283 // 4K PTE\r
1284 //\r
1285 PTIndex = (UINTN)BitFieldRead64 (PFAddress, 12, 20);\r
1286\r
1287 //\r
1288 // Record old entries with non-present status\r
1289 // Old entries include the memory which instruction is at and the memory which instruction access.\r
1290 //\r
1291 //\r
1292 ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT);\r
1293 if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) {\r
1294 PFIndex = mPFEntryCount[CpuIndex];\r
1295 mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex];\r
1296 mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex];\r
1297 mPFEntryCount[CpuIndex]++;\r
1298 }\r
1299\r
1300 //\r
1301 // Set new entry\r
1302 //\r
1303 PageTable[PTIndex] = (PFAddress & ~((1ull << 12) - 1));\r
881520ea 1304 PageTable[PTIndex] |= (UINT64)PAGE_ATTRIBUTE_BITS;\r
529a5a86
MK
1305 if ((ErrorCode & IA32_PF_EC_ID) != 0) {\r
1306 PageTable[PTIndex] &= ~IA32_PG_NX;\r
1307 }\r
1308 }\r
1309}\r
1310\r
09afd9a4
JW
1311/**\r
1312 Handler for Page Fault triggered by Guard page.\r
1313\r
1314 @param ErrorCode The Error code of exception.\r
1315\r
1316**/\r
1317VOID\r
1318GuardPagePFHandler (\r
1319 UINTN ErrorCode\r
1320 )\r
1321{\r
1322 UINT64 *PageTable;\r
1323 UINT64 PFAddress;\r
1324 UINT64 RestoreAddress;\r
1325 UINTN RestorePageNumber;\r
1326 UINTN CpuIndex;\r
1327\r
1328 PageTable = (UINT64 *)AsmReadCr3 ();\r
1329 PFAddress = AsmReadCr2 ();\r
1330 CpuIndex = GetCpuIndex ();\r
1331\r
1332 //\r
1333 // Memory operation cross pages, like "rep mov" instruction, will cause\r
1334 // infinite loop between this and Debug Trap handler. We have to make sure\r
1335 // that current page and the page followed are both in PRESENT state.\r
1336 //\r
1337 RestorePageNumber = 2;\r
1338 RestoreAddress = PFAddress;\r
1339 while (RestorePageNumber > 0) {\r
1340 RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);\r
1341 RestoreAddress += EFI_PAGE_SIZE;\r
1342 RestorePageNumber--;\r
1343 }\r
1344\r
1345 //\r
1346 // Flush TLB\r
1347 //\r
1348 CpuFlushTlb ();\r
1349}\r
1350\r
529a5a86
MK
1351/**\r
1352 The Page fault handler to save SMM profile data.\r
1353\r
1354 @param Rip The RIP when exception happens.\r
1355 @param ErrorCode The Error code of exception.\r
1356\r
1357**/\r
1358VOID\r
1359SmmProfilePFHandler (\r
1360 UINTN Rip,\r
1361 UINTN ErrorCode\r
1362 )\r
1363{\r
1364 UINT64 *PageTable;\r
1365 UINT64 PFAddress;\r
890d9ee5
JW
1366 UINT64 RestoreAddress;\r
1367 UINTN RestorePageNumber;\r
529a5a86
MK
1368 UINTN CpuIndex;\r
1369 UINTN Index;\r
1370 UINT64 InstructionAddress;\r
1371 UINTN MaxEntryNumber;\r
1372 UINTN CurrentEntryNumber;\r
1373 BOOLEAN IsValidPFAddress;\r
1374 SMM_PROFILE_ENTRY *SmmProfileEntry;\r
1375 UINT64 SmiCommand;\r
1376 EFI_STATUS Status;\r
529a5a86
MK
1377 UINT8 SoftSmiValue;\r
1378 EFI_SMM_SAVE_STATE_IO_INFO IoInfo;\r
1379\r
1380 if (!mSmmProfileStart) {\r
1381 //\r
1382 // If SMM profile does not start, call original page fault handler.\r
1383 //\r
1384 SmiDefaultPFHandler ();\r
1385 return;\r
1386 }\r
1387\r
1388 if (mBtsSupported) {\r
1389 DisableBTS ();\r
1390 }\r
1391\r
1392 IsValidPFAddress = FALSE;\r
1393 PageTable = (UINT64 *)AsmReadCr3 ();\r
1394 PFAddress = AsmReadCr2 ();\r
1395 CpuIndex = GetCpuIndex ();\r
1396\r
890d9ee5
JW
1397 //\r
1398 // Memory operation cross pages, like "rep mov" instruction, will cause\r
1399 // infinite loop between this and Debug Trap handler. We have to make sure\r
1400 // that current page and the page followed are both in PRESENT state.\r
1401 //\r
1402 RestorePageNumber = 2;\r
1403 RestoreAddress = PFAddress;\r
1404 while (RestorePageNumber > 0) {\r
1405 if (RestoreAddress <= 0xFFFFFFFF) {\r
1406 RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);\r
1407 } else {\r
1408 RestorePageTableAbove4G (PageTable, RestoreAddress, CpuIndex, ErrorCode, &IsValidPFAddress);\r
1409 }\r
1410 RestoreAddress += EFI_PAGE_SIZE;\r
1411 RestorePageNumber--;\r
529a5a86
MK
1412 }\r
1413\r
1414 if (!IsValidPFAddress) {\r
1415 InstructionAddress = Rip;\r
1416 if ((ErrorCode & IA32_PF_EC_ID) != 0 && (mBtsSupported)) {\r
1417 //\r
1418 // If it is instruction fetch failure, get the correct IP from BTS.\r
1419 //\r
1420 InstructionAddress = GetSourceFromDestinationOnBts (CpuIndex, Rip);\r
1421 if (InstructionAddress == 0) {\r
1422 //\r
1423 // It indicates the instruction which caused page fault is not a jump instruction,\r
1424 // set instruction address same as the page fault address.\r
1425 //\r
1426 InstructionAddress = PFAddress;\r
1427 }\r
1428 }\r
1429\r
529a5a86
MK
1430 //\r
1431 // Indicate it is not software SMI\r
1432 //\r
1433 SmiCommand = 0xFFFFFFFFFFFFFFFFULL;\r
1434 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
1435 Status = SmmReadSaveState(&mSmmCpu, sizeof(IoInfo), EFI_SMM_SAVE_STATE_REGISTER_IO, Index, &IoInfo);\r
1436 if (EFI_ERROR (Status)) {\r
1437 continue;\r
1438 }\r
1439 if (IoInfo.IoPort == mSmiCommandPort) {\r
529a5a86
MK
1440 //\r
1441 // A software SMI triggered by SMI command port has been found, get SmiCommand from SMI command port.\r
1442 //\r
1443 SoftSmiValue = IoRead8 (mSmiCommandPort);\r
1444 SmiCommand = (UINT64)SoftSmiValue;\r
1445 break;\r
1446 }\r
1447 }\r
1448\r
1449 SmmProfileEntry = (SMM_PROFILE_ENTRY *)(UINTN)(mSmmProfileBase + 1);\r
1450 //\r
1451 // Check if there is already a same entry in profile data.\r
1452 //\r
1453 for (Index = 0; Index < (UINTN) mSmmProfileBase->CurDataEntries; Index++) {\r
1454 if ((SmmProfileEntry[Index].ErrorCode == (UINT64)ErrorCode) &&\r
1455 (SmmProfileEntry[Index].Address == PFAddress) &&\r
1456 (SmmProfileEntry[Index].CpuNum == (UINT64)CpuIndex) &&\r
1457 (SmmProfileEntry[Index].Instruction == InstructionAddress) &&\r
1458 (SmmProfileEntry[Index].SmiCmd == SmiCommand)) {\r
1459 //\r
1460 // Same record exist, need not save again.\r
1461 //\r
1462 break;\r
1463 }\r
1464 }\r
1465 if (Index == mSmmProfileBase->CurDataEntries) {\r
1466 CurrentEntryNumber = (UINTN) mSmmProfileBase->CurDataEntries;\r
1467 MaxEntryNumber = (UINTN) mSmmProfileBase->MaxDataEntries;\r
1468 if (FeaturePcdGet (PcdCpuSmmProfileRingBuffer)) {\r
1469 CurrentEntryNumber = CurrentEntryNumber % MaxEntryNumber;\r
1470 }\r
1471 if (CurrentEntryNumber < MaxEntryNumber) {\r
1472 //\r
1473 // Log the new entry\r
1474 //\r
1475 SmmProfileEntry[CurrentEntryNumber].SmiNum = mSmmProfileBase->NumSmis;\r
1476 SmmProfileEntry[CurrentEntryNumber].ErrorCode = (UINT64)ErrorCode;\r
1477 SmmProfileEntry[CurrentEntryNumber].ApicId = (UINT64)GetApicId ();\r
1478 SmmProfileEntry[CurrentEntryNumber].CpuNum = (UINT64)CpuIndex;\r
1479 SmmProfileEntry[CurrentEntryNumber].Address = PFAddress;\r
1480 SmmProfileEntry[CurrentEntryNumber].Instruction = InstructionAddress;\r
1481 SmmProfileEntry[CurrentEntryNumber].SmiCmd = SmiCommand;\r
1482 //\r
1483 // Update current entry index and data size in the header.\r
1484 //\r
1485 mSmmProfileBase->CurDataEntries++;\r
1486 mSmmProfileBase->CurDataSize = MultU64x64 (mSmmProfileBase->CurDataEntries, sizeof (SMM_PROFILE_ENTRY));\r
1487 }\r
1488 }\r
1489 }\r
1490 //\r
1491 // Flush TLB\r
1492 //\r
1493 CpuFlushTlb ();\r
1494\r
1495 if (mBtsSupported) {\r
1496 EnableBTS ();\r
1497 }\r
1498}\r
1499\r
1500/**\r
1501 Replace INT1 exception handler to restore page table to absent/execute-disable state\r
1502 in order to trigger page fault again to save SMM profile data..\r
1503\r
1504**/\r
1505VOID\r
1506InitIdtr (\r
1507 VOID\r
1508 )\r
1509{\r
5c88af79
JF
1510 EFI_STATUS Status;\r
1511\r
1512 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_DEBUG, DebugExceptionHandler);\r
1513 ASSERT_EFI_ERROR (Status);\r
529a5a86 1514}\r