Home | History | Annotate | Download | only in PiSmmCpuDxeSmm
      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 < mMaxNumberOfCpus; 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) * mMaxNumberOfCpus);
    829   ASSERT (mPFEntryCount != NULL);
    830   mLastPFEntryValue = (UINT64  (*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool (
    831                                                          sizeof (mLastPFEntryValue[0]) * mMaxNumberOfCpus);
    832   ASSERT (mLastPFEntryValue != NULL);
    833   mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])AllocateZeroPool (
    834                                                            sizeof (mLastPFEntryPointer[0]) * mMaxNumberOfCpus);
    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 *) * mMaxNumberOfCpus);
    876     ASSERT (mMsrDsArea != NULL);
    877     mMsrBTSRecord = (BRANCH_TRACE_RECORD **)AllocateZeroPool (sizeof (BRANCH_TRACE_RECORD *) * mMaxNumberOfCpus);
    878     ASSERT (mMsrBTSRecord != NULL);
    879     mMsrPEBSRecord = (PEBS_RECORD **)AllocateZeroPool (sizeof (PEBS_RECORD *) * mMaxNumberOfCpus);
    880     ASSERT (mMsrPEBSRecord != NULL);
    881 
    882     mMsrDsAreaBase  = (MSR_DS_AREA_STRUCT *)((UINTN)Base + mSmmProfileSize);
    883     MsrDsAreaSizePerCpu = mMsrDsAreaSize / mMaxNumberOfCpus;
    884     mBTSRecordNumber    = (MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER - sizeof(MSR_DS_AREA_STRUCT)) / sizeof(BRANCH_TRACE_RECORD);
    885     for (Index = 0; Index < mMaxNumberOfCpus; 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   EFI_STATUS                        Status;
   1379 
   1380   Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_DEBUG, DebugExceptionHandler);
   1381   ASSERT_EFI_ERROR (Status);
   1382 }
   1383