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