]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm: Remove mInternalCr3 in PiSmmCpuDxeSmm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / PageTbl.c
CommitLineData
7947da3c
MK
1/** @file\r
2Page table manipulation functions for IA-32 processors\r
3\r
3eb69b08 4Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
241f9149
LD
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
6\r
0acd8697 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
7947da3c
MK
8\r
9**/\r
10\r
11#include "PiSmmCpuDxeSmm.h"\r
12\r
3eb69b08
JY
13/**\r
14 Disable CET.\r
15**/\r
16VOID\r
17EFIAPI\r
18DisableCet (\r
19 VOID\r
20 );\r
21\r
22/**\r
23 Enable CET.\r
24**/\r
25VOID\r
26EFIAPI\r
27EnableCet (\r
28 VOID\r
29 );\r
30\r
7947da3c
MK
31/**\r
32 Create PageTable for SMM use.\r
33\r
34 @return PageTable Address\r
35\r
36**/\r
37UINT32\r
38SmmInitPageTable (\r
39 VOID\r
40 )\r
41{\r
053e878b
MK
42 UINTN PageFaultHandlerHookAddress;\r
43 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
44 EFI_STATUS Status;\r
7947da3c
MK
45\r
46 //\r
47 // Initialize spin lock\r
48 //\r
fe3a75bc 49 InitializeSpinLock (mPFLock);\r
7947da3c 50\r
714c2603
SZ
51 mPhysicalAddressBits = 32;\r
52\r
09afd9a4
JW
53 if (FeaturePcdGet (PcdCpuSmmProfileEnable) ||\r
54 HEAP_GUARD_NONSTOP_MODE ||\r
053e878b
MK
55 NULL_DETECTION_NONSTOP_MODE)\r
56 {\r
7947da3c
MK
57 //\r
58 // Set own Page Fault entry instead of the default one, because SMM Profile\r
59 // feature depends on IRET instruction to do Single Step\r
60 //\r
61 PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;\r
053e878b
MK
62 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
63 IdtEntry += EXCEPT_IA32_PAGE_FAULT;\r
64 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;\r
65 IdtEntry->Bits.Reserved_0 = 0;\r
66 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
67 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);\r
7947da3c
MK
68 } else {\r
69 //\r
70 // Register SMM Page Fault Handler\r
71 //\r
5c88af79
JF
72 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
73 ASSERT_EFI_ERROR (Status);\r
7947da3c
MK
74 }\r
75\r
76 //\r
77 // Additional SMM IDT initialization for SMM stack guard\r
78 //\r
79 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
80 InitializeIDTSmmStackGuard ();\r
81 }\r
053e878b 82\r
717fb604 83 return Gen4GPageTable (TRUE);\r
7947da3c
MK
84}\r
85\r
86/**\r
87 Page Fault handler for SMM use.\r
88\r
89**/\r
90VOID\r
91SmiDefaultPFHandler (\r
92 VOID\r
93 )\r
94{\r
95 CpuDeadLoop ();\r
96}\r
97\r
98/**\r
99 ThePage Fault handler wrapper for SMM use.\r
100\r
101 @param InterruptType Defines the type of interrupt or exception that\r
102 occurred on the processor.This parameter is processor architecture specific.\r
103 @param SystemContext A pointer to the processor context when\r
104 the interrupt occurred on the processor.\r
105**/\r
106VOID\r
107EFIAPI\r
108SmiPFHandler (\r
053e878b
MK
109 IN EFI_EXCEPTION_TYPE InterruptType,\r
110 IN EFI_SYSTEM_CONTEXT SystemContext\r
7947da3c
MK
111 )\r
112{\r
053e878b
MK
113 UINTN PFAddress;\r
114 UINTN GuardPageAddress;\r
115 UINTN CpuIndex;\r
7947da3c
MK
116\r
117 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);\r
118\r
fe3a75bc 119 AcquireSpinLock (mPFLock);\r
7947da3c
MK
120\r
121 PFAddress = AsmReadCr2 ();\r
122\r
7fa1376c
JY
123 //\r
124 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,\r
125 // or SMM page protection violation.\r
126 //\r
127 if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
053e878b
MK
128 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)))\r
129 {\r
b8caae19 130 DumpCpuContext (InterruptType, SystemContext);\r
053e878b 131 CpuIndex = GetCpuIndex ();\r
7fa1376c
JY
132 GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);\r
133 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
134 (PFAddress >= GuardPageAddress) &&\r
053e878b
MK
135 (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE)))\r
136 {\r
7fa1376c
JY
137 DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
138 } else {\r
7fa1376c
JY
139 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
140 DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));\r
141 DEBUG_CODE (\r
142 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
053e878b 143 );\r
7fa1376c
JY
144 } else {\r
145 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));\r
146 DEBUG_CODE (\r
147 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
053e878b 148 );\r
7fa1376c 149 }\r
09afd9a4
JW
150\r
151 if (HEAP_GUARD_NONSTOP_MODE) {\r
152 GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);\r
153 goto Exit;\r
154 }\r
7fa1376c 155 }\r
053e878b 156\r
7947da3c 157 CpuDeadLoop ();\r
3eb69b08 158 goto Exit;\r
7947da3c
MK
159 }\r
160\r
161 //\r
8bf0380e 162 // If a page fault occurs in non-SMRAM range.\r
7947da3c
MK
163 //\r
164 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
053e878b
MK
165 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))\r
166 {\r
7947da3c 167 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
8bf0380e 168 DumpCpuContext (InterruptType, SystemContext);\r
717fb604 169 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
7947da3c
MK
170 DEBUG_CODE (\r
171 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
053e878b 172 );\r
7947da3c 173 CpuDeadLoop ();\r
3eb69b08 174 goto Exit;\r
7947da3c 175 }\r
09afd9a4
JW
176\r
177 //\r
178 // If NULL pointer was just accessed\r
179 //\r
053e878b
MK
180 if (((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) &&\r
181 (PFAddress < EFI_PAGE_SIZE))\r
182 {\r
09afd9a4
JW
183 DumpCpuContext (InterruptType, SystemContext);\r
184 DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));\r
185 DEBUG_CODE (\r
186 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
053e878b 187 );\r
09afd9a4
JW
188\r
189 if (NULL_DETECTION_NONSTOP_MODE) {\r
190 GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);\r
191 goto Exit;\r
192 }\r
193\r
194 CpuDeadLoop ();\r
3eb69b08 195 goto Exit;\r
09afd9a4
JW
196 }\r
197\r
d2fc7711 198 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {\r
8bf0380e 199 DumpCpuContext (InterruptType, SystemContext);\r
d2fc7711
JY
200 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));\r
201 DEBUG_CODE (\r
202 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
053e878b 203 );\r
d2fc7711 204 CpuDeadLoop ();\r
3eb69b08 205 goto Exit;\r
d2fc7711 206 }\r
7947da3c
MK
207 }\r
208\r
209 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
210 SmmProfilePFHandler (\r
211 SystemContext.SystemContextIa32->Eip,\r
212 SystemContext.SystemContextIa32->ExceptionData\r
213 );\r
214 } else {\r
b8caae19 215 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c
MK
216 SmiDefaultPFHandler ();\r
217 }\r
218\r
09afd9a4 219Exit:\r
fe3a75bc 220 ReleaseSpinLock (mPFLock);\r
7947da3c 221}\r
717fb604
JY
222\r
223/**\r
224 This function sets memory attribute for page table.\r
225**/\r
226VOID\r
227SetPageTableAttributes (\r
228 VOID\r
229 )\r
230{\r
053e878b
MK
231 UINTN Index2;\r
232 UINTN Index3;\r
233 UINT64 *L1PageTable;\r
234 UINT64 *L2PageTable;\r
235 UINT64 *L3PageTable;\r
236 UINTN PageTableBase;\r
237 BOOLEAN IsSplitted;\r
238 BOOLEAN PageTableSplitted;\r
239 BOOLEAN CetEnabled;\r
717fb604 240\r
827330cc 241 //\r
1015fb3c 242 // Don't mark page table to read-only if heap guard is enabled.\r
827330cc
JW
243 //\r
244 // BIT2: SMM page guard enabled\r
245 // BIT3: SMM pool guard enabled\r
246 //\r
247 if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) {\r
1015fb3c 248 DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as heap guard is enabled\n"));\r
053e878b 249 return;\r
1015fb3c
SZ
250 }\r
251\r
252 //\r
253 // Don't mark page table to read-only if SMM profile is enabled.\r
254 //\r
255 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
256 DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as SMM profile is enabled\n"));\r
053e878b 257 return;\r
827330cc
JW
258 }\r
259\r
717fb604
JY
260 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
261\r
262 //\r
263 // Disable write protection, because we need mark page table to be write protected.\r
264 // We need *write* page table memory, to mark itself to be *read only*.\r
265 //\r
053e878b 266 CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE;\r
3eb69b08
JY
267 if (CetEnabled) {\r
268 //\r
269 // CET must be disabled if WP is disabled.\r
270 //\r
053e878b 271 DisableCet ();\r
3eb69b08 272 }\r
053e878b
MK
273\r
274 AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP);\r
717fb604
JY
275\r
276 do {\r
277 DEBUG ((DEBUG_INFO, "Start...\n"));\r
278 PageTableSplitted = FALSE;\r
279\r
7b475490
DT
280 PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;\r
281 L3PageTable = (UINT64 *)PageTableBase;\r
717fb604 282\r
7b475490 283 SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)PageTableBase, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
717fb604
JY
284 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
285\r
286 for (Index3 = 0; Index3 < 4; Index3++) {\r
241f9149 287 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
288 if (L2PageTable == NULL) {\r
289 continue;\r
290 }\r
291\r
7b475490 292 SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
717fb604
JY
293 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
294\r
053e878b 295 for (Index2 = 0; Index2 < SIZE_4KB/sizeof (UINT64); Index2++) {\r
717fb604
JY
296 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
297 // 2M\r
298 continue;\r
299 }\r
053e878b 300\r
241f9149 301 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
302 if (L1PageTable == NULL) {\r
303 continue;\r
304 }\r
053e878b 305\r
7b475490 306 SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
717fb604
JY
307 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
308 }\r
309 }\r
310 } while (PageTableSplitted);\r
311\r
312 //\r
313 // Enable write protection, after page table updated.\r
314 //\r
053e878b 315 AsmWriteCr0 (AsmReadCr0 () | CR0_WP);\r
3eb69b08
JY
316 if (CetEnabled) {\r
317 //\r
318 // re-enable CET.\r
319 //\r
053e878b 320 EnableCet ();\r
3eb69b08 321 }\r
717fb604 322\r
053e878b 323 return;\r
717fb604 324}\r
37f9fea5
VN
325\r
326/**\r
327 This function returns with no action for 32 bit.\r
328\r
329 @param[out] *Cr2 Pointer to variable to hold CR2 register value.\r
330**/\r
331VOID\r
332SaveCr2 (\r
333 OUT UINTN *Cr2\r
334 )\r
335{\r
053e878b 336 return;\r
37f9fea5
VN
337}\r
338\r
339/**\r
340 This function returns with no action for 32 bit.\r
341\r
342 @param[in] Cr2 Value to write into CR2 register.\r
343**/\r
344VOID\r
345RestoreCr2 (\r
346 IN UINTN Cr2\r
347 )\r
348{\r
053e878b 349 return;\r
37f9fea5 350}\r
79186ddc
RN
351\r
352/**\r
353 Return whether access to non-SMRAM is restricted.\r
354\r
355 @retval TRUE Access to non-SMRAM is restricted.\r
356 @retval FALSE Access to non-SMRAM is not restricted.\r
9c33f16f 357**/\r
79186ddc
RN
358BOOLEAN\r
359IsRestrictedMemoryAccess (\r
360 VOID\r
361 )\r
362{\r
363 return TRUE;\r
364}\r