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