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