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