SmmProfile.c 45 KB

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