UefiCpuPkg/PiSmmCpuDxeSmm: Add SmmMemoryAttribute protocol
[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
137 // If a page fault occurs in SMM range\r
138 //\r
139 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
140 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
b8caae19 141 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c 142 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\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
JY
149 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {\r
150 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));\r
151 DEBUG_CODE (\r
152 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
153 );\r
154 CpuDeadLoop ();\r
155 }\r
7947da3c
MK
156 }\r
157\r
f8c1133b
JW
158 //\r
159 // If NULL pointer was just accessed\r
160 //\r
161 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 &&\r
162 (PFAddress < EFI_PAGE_SIZE)) {\r
163 DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));\r
164 DEBUG_CODE (\r
165 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
166 );\r
167 CpuDeadLoop ();\r
168 }\r
169\r
7947da3c
MK
170 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
171 SmmProfilePFHandler (\r
172 SystemContext.SystemContextIa32->Eip,\r
173 SystemContext.SystemContextIa32->ExceptionData\r
174 );\r
175 } else {\r
b8caae19 176 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c
MK
177 SmiDefaultPFHandler ();\r
178 }\r
179\r
fe3a75bc 180 ReleaseSpinLock (mPFLock);\r
7947da3c 181}\r
717fb604
JY
182\r
183/**\r
184 This function sets memory attribute for page table.\r
185**/\r
186VOID\r
187SetPageTableAttributes (\r
188 VOID\r
189 )\r
190{\r
191 UINTN Index2;\r
192 UINTN Index3;\r
193 UINT64 *L1PageTable;\r
194 UINT64 *L2PageTable;\r
195 UINT64 *L3PageTable;\r
196 BOOLEAN IsSplitted;\r
197 BOOLEAN PageTableSplitted;\r
198\r
af4f4b34
JW
199 //
200 // Don't mark page table as read-only if heap guard is enabled.
201 //
202 // BIT2: SMM page guard enabled
203 // BIT3: SMM pool guard enabled
204 //
205 if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) {
206 return ;
207 }
208
717fb604
JY
209 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
210\r
211 //\r
212 // Disable write protection, because we need mark page table to be write protected.\r
213 // We need *write* page table memory, to mark itself to be *read only*.\r
214 //\r
215 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
216\r
217 do {\r
218 DEBUG ((DEBUG_INFO, "Start...\n"));\r
219 PageTableSplitted = FALSE;\r
220\r
221 L3PageTable = (UINT64 *)GetPageTableBase ();\r
222\r
223 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
224 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
225\r
226 for (Index3 = 0; Index3 < 4; Index3++) {\r
241f9149 227 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
228 if (L2PageTable == NULL) {\r
229 continue;\r
230 }\r
231\r
232 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
233 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
234\r
235 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
236 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
237 // 2M\r
238 continue;\r
239 }\r
241f9149 240 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
241 if (L1PageTable == NULL) {\r
242 continue;\r
243 }\r
244 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
245 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
246 }\r
247 }\r
248 } while (PageTableSplitted);\r
249\r
250 //\r
251 // Enable write protection, after page table updated.\r
252 //\r
253 AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
254\r
255 return ;\r
256}\r