1 /** @file 2 Page table manipulation functions for IA-32 processors 3 4 Copyright (c) 2009 - 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 17 SPIN_LOCK mPFLock; 18 19 /** 20 Create PageTable for SMM use. 21 22 @return PageTable Address 23 24 **/ 25 UINT32 26 SmmInitPageTable ( 27 VOID 28 ) 29 { 30 UINTN PageFaultHandlerHookAddress; 31 IA32_IDT_GATE_DESCRIPTOR *IdtEntry; 32 33 // 34 // Initialize spin lock 35 // 36 InitializeSpinLock (&mPFLock); 37 38 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { 39 // 40 // Set own Page Fault entry instead of the default one, because SMM Profile 41 // feature depends on IRET instruction to do Single Step 42 // 43 PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile; 44 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base; 45 IdtEntry += EXCEPT_IA32_PAGE_FAULT; 46 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress; 47 IdtEntry->Bits.Reserved_0 = 0; 48 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; 49 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16); 50 } else { 51 // 52 // Register SMM Page Fault Handler 53 // 54 SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler); 55 } 56 57 // 58 // Additional SMM IDT initialization for SMM stack guard 59 // 60 if (FeaturePcdGet (PcdCpuSmmStackGuard)) { 61 InitializeIDTSmmStackGuard (); 62 } 63 return Gen4GPageTable (0, TRUE); 64 } 65 66 /** 67 Page Fault handler for SMM use. 68 69 **/ 70 VOID 71 SmiDefaultPFHandler ( 72 VOID 73 ) 74 { 75 CpuDeadLoop (); 76 } 77 78 /** 79 ThePage Fault handler wrapper for SMM use. 80 81 @param InterruptType Defines the type of interrupt or exception that 82 occurred on the processor.This parameter is processor architecture specific. 83 @param SystemContext A pointer to the processor context when 84 the interrupt occurred on the processor. 85 **/ 86 VOID 87 EFIAPI 88 SmiPFHandler ( 89 IN EFI_EXCEPTION_TYPE InterruptType, 90 IN EFI_SYSTEM_CONTEXT SystemContext 91 ) 92 { 93 UINTN PFAddress; 94 95 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT); 96 97 AcquireSpinLock (&mPFLock); 98 99 PFAddress = AsmReadCr2 (); 100 101 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) && 102 (PFAddress >= mCpuHotPlugData.SmrrBase) && 103 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) { 104 DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n")); 105 CpuDeadLoop (); 106 } 107 108 // 109 // If a page fault occurs in SMM range 110 // 111 if ((PFAddress < mCpuHotPlugData.SmrrBase) || 112 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) { 113 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) { 114 DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress)); 115 DEBUG_CODE ( 116 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp); 117 ); 118 CpuDeadLoop (); 119 } 120 } 121 122 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { 123 SmmProfilePFHandler ( 124 SystemContext.SystemContextIa32->Eip, 125 SystemContext.SystemContextIa32->ExceptionData 126 ); 127 } else { 128 SmiDefaultPFHandler (); 129 } 130 131 ReleaseSpinLock (&mPFLock); 132 } 133