]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg PiSmmCpuDxeSmm: SMM profile and static paging mutual exclusion
[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
b8caae19 4Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
241f9149
LD
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
6\r
7947da3c
MK
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "PiSmmCpuDxeSmm.h"\r
18\r
7947da3c
MK
19/**\r
20 Create PageTable for SMM use.\r
21\r
22 @return PageTable Address\r
23\r
24**/\r
25UINT32\r
26SmmInitPageTable (\r
27 VOID\r
28 )\r
29{\r
30 UINTN PageFaultHandlerHookAddress;\r
31 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
5c88af79 32 EFI_STATUS Status;\r
7947da3c
MK
33\r
34 //\r
35 // Initialize spin lock\r
36 //\r
fe3a75bc 37 InitializeSpinLock (mPFLock);\r
7947da3c 38\r
714c2603
SZ
39 mPhysicalAddressBits = 32;\r
40\r
7947da3c
MK
41 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
42 //\r
43 // Set own Page Fault entry instead of the default one, because SMM Profile\r
44 // feature depends on IRET instruction to do Single Step\r
45 //\r
46 PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;\r
47 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base;\r
48 IdtEntry += EXCEPT_IA32_PAGE_FAULT;\r
49 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;\r
50 IdtEntry->Bits.Reserved_0 = 0;\r
51 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
52 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);\r
53 } else {\r
54 //\r
55 // Register SMM Page Fault Handler\r
56 //\r
5c88af79
JF
57 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
58 ASSERT_EFI_ERROR (Status);\r
7947da3c
MK
59 }\r
60\r
61 //\r
62 // Additional SMM IDT initialization for SMM stack guard\r
63 //\r
64 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
65 InitializeIDTSmmStackGuard ();\r
66 }\r
717fb604 67 return Gen4GPageTable (TRUE);\r
7947da3c
MK
68}\r
69\r
70/**\r
71 Page Fault handler for SMM use.\r
72\r
73**/\r
74VOID\r
75SmiDefaultPFHandler (\r
76 VOID\r
77 )\r
78{\r
79 CpuDeadLoop ();\r
80}\r
81\r
82/**\r
83 ThePage Fault handler wrapper for SMM use.\r
84\r
85 @param InterruptType Defines the type of interrupt or exception that\r
86 occurred on the processor.This parameter is processor architecture specific.\r
87 @param SystemContext A pointer to the processor context when\r
88 the interrupt occurred on the processor.\r
89**/\r
90VOID\r
91EFIAPI\r
92SmiPFHandler (\r
b8caae19
JF
93 IN EFI_EXCEPTION_TYPE InterruptType,\r
94 IN EFI_SYSTEM_CONTEXT SystemContext\r
7947da3c
MK
95 )\r
96{\r
97 UINTN PFAddress;\r
7fa1376c
JY
98 UINTN GuardPageAddress;\r
99 UINTN CpuIndex;\r
7947da3c
MK
100\r
101 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);\r
102\r
fe3a75bc 103 AcquireSpinLock (mPFLock);\r
7947da3c
MK
104\r
105 PFAddress = AsmReadCr2 ();\r
106\r
7fa1376c
JY
107 //\r
108 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,\r
109 // or SMM page protection violation.\r
110 //\r
111 if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
7947da3c 112 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
b8caae19 113 DumpCpuContext (InterruptType, SystemContext);\r
7fa1376c
JY
114 CpuIndex = GetCpuIndex ();\r
115 GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);\r
116 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
117 (PFAddress >= GuardPageAddress) &&\r
118 (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) {\r
119 DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
120 } else {\r
7fa1376c
JY
121 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
122 DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));\r
123 DEBUG_CODE (\r
124 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
125 );\r
126 } else {\r
127 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));\r
128 DEBUG_CODE (\r
129 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
130 );\r
131 }\r
132 }\r
7947da3c
MK
133 CpuDeadLoop ();\r
134 }\r
135\r
136 //\r
8bf0380e 137 // If a page fault occurs in non-SMRAM range.\r
7947da3c
MK
138 //\r
139 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
140 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
141 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
8bf0380e 142 DumpCpuContext (InterruptType, SystemContext);\r
717fb604 143 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
7947da3c
MK
144 DEBUG_CODE (\r
145 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
146 );\r
147 CpuDeadLoop ();\r
148 }\r
d2fc7711 149 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {\r
8bf0380e 150 DumpCpuContext (InterruptType, SystemContext);\r
d2fc7711
JY
151 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));\r
152 DEBUG_CODE (\r
153 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
154 );\r
155 CpuDeadLoop ();\r
156 }\r
7947da3c
MK
157 }\r
158\r
f8c1133b
JW
159 //\r
160 // If NULL pointer was just accessed\r
161 //\r
162 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 &&\r
163 (PFAddress < EFI_PAGE_SIZE)) {\r
8bf0380e 164 DumpCpuContext (InterruptType, SystemContext);\r
f8c1133b
JW
165 DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));\r
166 DEBUG_CODE (\r
167 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
168 );\r
169 CpuDeadLoop ();\r
170 }\r
171\r
7947da3c
MK
172 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
173 SmmProfilePFHandler (\r
174 SystemContext.SystemContextIa32->Eip,\r
175 SystemContext.SystemContextIa32->ExceptionData\r
176 );\r
177 } else {\r
b8caae19 178 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c
MK
179 SmiDefaultPFHandler ();\r
180 }\r
181\r
fe3a75bc 182 ReleaseSpinLock (mPFLock);\r
7947da3c 183}\r
717fb604
JY
184\r
185/**\r
186 This function sets memory attribute for page table.\r
187**/\r
188VOID\r
189SetPageTableAttributes (\r
190 VOID\r
191 )\r
192{\r
193 UINTN Index2;\r
194 UINTN Index3;\r
195 UINT64 *L1PageTable;\r
196 UINT64 *L2PageTable;\r
197 UINT64 *L3PageTable;\r
198 BOOLEAN IsSplitted;\r
199 BOOLEAN PageTableSplitted;\r
200\r
827330cc 201 //\r
1015fb3c 202 // Don't mark page table to read-only if heap guard is enabled.\r
827330cc
JW
203 //\r
204 // BIT2: SMM page guard enabled\r
205 // BIT3: SMM pool guard enabled\r
206 //\r
207 if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) {\r
1015fb3c
SZ
208 DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as heap guard is enabled\n"));\r
209 return ;\r
210 }\r
211\r
212 //\r
213 // Don't mark page table to read-only if SMM profile is enabled.\r
214 //\r
215 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
216 DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as SMM profile is enabled\n"));\r
827330cc
JW
217 return ;\r
218 }\r
219\r
717fb604
JY
220 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
221\r
222 //\r
223 // Disable write protection, because we need mark page table to be write protected.\r
224 // We need *write* page table memory, to mark itself to be *read only*.\r
225 //\r
226 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
227\r
228 do {\r
229 DEBUG ((DEBUG_INFO, "Start...\n"));\r
230 PageTableSplitted = FALSE;\r
231\r
232 L3PageTable = (UINT64 *)GetPageTableBase ();\r
233\r
234 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
235 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
236\r
237 for (Index3 = 0; Index3 < 4; Index3++) {\r
241f9149 238 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
239 if (L2PageTable == NULL) {\r
240 continue;\r
241 }\r
242\r
243 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
244 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
245\r
246 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
247 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
248 // 2M\r
249 continue;\r
250 }\r
241f9149 251 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
252 if (L1PageTable == NULL) {\r
253 continue;\r
254 }\r
255 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
256 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
257 }\r
258 }\r
259 } while (PageTableSplitted);\r
260\r
261 //\r
262 // Enable write protection, after page table updated.\r
263 //\r
264 AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
265\r
266 return ;\r
267}\r