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