]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / PageTbl.c
1 /** @file
2 Page table manipulation functions for IA-32 processors
3
4 Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "PiSmmCpuDxeSmm.h"
12
13 /**
14 Create PageTable for SMM use.
15
16 @return PageTable Address
17
18 **/
19 UINT32
20 SmmInitPageTable (
21 VOID
22 )
23 {
24 UINTN PageFaultHandlerHookAddress;
25 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
26 EFI_STATUS Status;
27
28 //
29 // Initialize spin lock
30 //
31 InitializeSpinLock (mPFLock);
32
33 mPhysicalAddressBits = 32;
34
35 if (FeaturePcdGet (PcdCpuSmmProfileEnable) ||
36 HEAP_GUARD_NONSTOP_MODE ||
37 NULL_DETECTION_NONSTOP_MODE)
38 {
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 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
55 ASSERT_EFI_ERROR (Status);
56 }
57
58 //
59 // Additional SMM IDT initialization for SMM stack guard
60 //
61 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
62 InitializeIDTSmmStackGuard ();
63 }
64
65 return Gen4GPageTable (TRUE);
66 }
67
68 /**
69 Page Fault handler for SMM use.
70
71 **/
72 VOID
73 SmiDefaultPFHandler (
74 VOID
75 )
76 {
77 CpuDeadLoop ();
78 }
79
80 /**
81 ThePage Fault handler wrapper for SMM use.
82
83 @param InterruptType Defines the type of interrupt or exception that
84 occurred on the processor.This parameter is processor architecture specific.
85 @param SystemContext A pointer to the processor context when
86 the interrupt occurred on the processor.
87 **/
88 VOID
89 EFIAPI
90 SmiPFHandler (
91 IN EFI_EXCEPTION_TYPE InterruptType,
92 IN EFI_SYSTEM_CONTEXT SystemContext
93 )
94 {
95 UINTN PFAddress;
96 UINTN GuardPageAddress;
97 UINTN CpuIndex;
98
99 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
100
101 AcquireSpinLock (mPFLock);
102
103 PFAddress = AsmReadCr2 ();
104
105 //
106 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,
107 // or SMM page protection violation.
108 //
109 if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&
110 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)))
111 {
112 DumpCpuContext (InterruptType, SystemContext);
113 CpuIndex = GetCpuIndex ();
114 GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);
115 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
116 (PFAddress >= GuardPageAddress) &&
117 (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE)))
118 {
119 DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));
120 } else {
121 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
122 DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));
123 DEBUG_CODE (
124 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
125 );
126 } else {
127 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));
128 DEBUG_CODE (
129 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
130 );
131 }
132
133 if (HEAP_GUARD_NONSTOP_MODE) {
134 GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
135 goto Exit;
136 }
137 }
138
139 CpuDeadLoop ();
140 goto Exit;
141 }
142
143 //
144 // If a page fault occurs in non-SMRAM range.
145 //
146 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
147 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))
148 {
149 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
150 DumpCpuContext (InterruptType, SystemContext);
151 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
152 DEBUG_CODE (
153 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
154 );
155 CpuDeadLoop ();
156 goto Exit;
157 }
158
159 //
160 // If NULL pointer was just accessed
161 //
162 if (((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) &&
163 (PFAddress < EFI_PAGE_SIZE))
164 {
165 DumpCpuContext (InterruptType, SystemContext);
166 DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));
167 DEBUG_CODE (
168 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
169 );
170
171 if (NULL_DETECTION_NONSTOP_MODE) {
172 GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
173 goto Exit;
174 }
175
176 CpuDeadLoop ();
177 goto Exit;
178 }
179
180 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
181 DumpCpuContext (InterruptType, SystemContext);
182 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));
183 DEBUG_CODE (
184 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
185 );
186 CpuDeadLoop ();
187 goto Exit;
188 }
189 }
190
191 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
192 SmmProfilePFHandler (
193 SystemContext.SystemContextIa32->Eip,
194 SystemContext.SystemContextIa32->ExceptionData
195 );
196 } else {
197 DumpCpuContext (InterruptType, SystemContext);
198 SmiDefaultPFHandler ();
199 }
200
201 Exit:
202 ReleaseSpinLock (mPFLock);
203 }
204
205 /**
206 This function returns with no action for 32 bit.
207
208 @param[out] *Cr2 Pointer to variable to hold CR2 register value.
209 **/
210 VOID
211 SaveCr2 (
212 OUT UINTN *Cr2
213 )
214 {
215 return;
216 }
217
218 /**
219 This function returns with no action for 32 bit.
220
221 @param[in] Cr2 Value to write into CR2 register.
222 **/
223 VOID
224 RestoreCr2 (
225 IN UINTN Cr2
226 )
227 {
228 return;
229 }
230
231 /**
232 Return whether access to non-SMRAM is restricted.
233
234 @retval TRUE Access to non-SMRAM is restricted.
235 @retval FALSE Access to non-SMRAM is not restricted.
236 **/
237 BOOLEAN
238 IsRestrictedMemoryAccess (
239 VOID
240 )
241 {
242 return TRUE;
243 }