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
SmmInitPageTable(VOID)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
SmiDefaultPFHandler(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
SmiPFHandler(IN EFI_EXCEPTION_TYPE InterruptType,IN EFI_SYSTEM_CONTEXT SystemContext)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