]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add support for PCD PcdPteMemoryEncryptionAddressOrMask
[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
fe3a75bc 4Copyright (c) 2009 - 2016, 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
MK
38\r
39 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
40 //\r
41 // Set own Page Fault entry instead of the default one, because SMM Profile\r
42 // feature depends on IRET instruction to do Single Step\r
43 //\r
44 PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;\r
45 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base;\r
46 IdtEntry += EXCEPT_IA32_PAGE_FAULT;\r
47 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;\r
48 IdtEntry->Bits.Reserved_0 = 0;\r
49 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
50 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);\r
51 } else {\r
52 //\r
53 // Register SMM Page Fault Handler\r
54 //\r
5c88af79
JF
55 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
56 ASSERT_EFI_ERROR (Status);\r
7947da3c
MK
57 }\r
58\r
59 //\r
60 // Additional SMM IDT initialization for SMM stack guard\r
61 //\r
62 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
63 InitializeIDTSmmStackGuard ();\r
64 }\r
717fb604 65 return Gen4GPageTable (TRUE);\r
7947da3c
MK
66}\r
67\r
68/**\r
69 Page Fault handler for SMM use.\r
70\r
71**/\r
72VOID\r
73SmiDefaultPFHandler (\r
74 VOID\r
75 )\r
76{\r
77 CpuDeadLoop ();\r
78}\r
79\r
80/**\r
81 ThePage Fault handler wrapper for SMM use.\r
82\r
83 @param InterruptType Defines the type of interrupt or exception that\r
84 occurred on the processor.This parameter is processor architecture specific.\r
85 @param SystemContext A pointer to the processor context when\r
86 the interrupt occurred on the processor.\r
87**/\r
88VOID\r
89EFIAPI\r
90SmiPFHandler (\r
91 IN EFI_EXCEPTION_TYPE InterruptType,\r
92 IN EFI_SYSTEM_CONTEXT SystemContext\r
93 )\r
94{\r
95 UINTN PFAddress;\r
7fa1376c
JY
96 UINTN GuardPageAddress;\r
97 UINTN CpuIndex;\r
7947da3c
MK
98\r
99 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);\r
100\r
fe3a75bc 101 AcquireSpinLock (mPFLock);\r
7947da3c
MK
102\r
103 PFAddress = AsmReadCr2 ();\r
104\r
7fa1376c
JY
105 //\r
106 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,\r
107 // or SMM page protection violation.\r
108 //\r
109 if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&\r
7947da3c 110 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
7fa1376c
JY
111 CpuIndex = GetCpuIndex ();\r
112 GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);\r
113 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
114 (PFAddress >= GuardPageAddress) &&\r
115 (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) {\r
116 DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
117 } else {\r
118 DEBUG ((DEBUG_ERROR, "SMM exception data - 0x%x(", SystemContext.SystemContextIa32->ExceptionData));\r
119 DEBUG ((DEBUG_ERROR, "I:%x, R:%x, U:%x, W:%x, P:%x",\r
120 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,\r
121 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,\r
122 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,\r
123 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,\r
124 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0\r
125 ));\r
126 DEBUG ((DEBUG_ERROR, ")\n"));\r
127 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
128 DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));\r
129 DEBUG_CODE (\r
130 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
131 );\r
132 } else {\r
133 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));\r
134 DEBUG_CODE (\r
135 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
136 );\r
137 }\r
138 }\r
7947da3c
MK
139 CpuDeadLoop ();\r
140 }\r
141\r
142 //\r
143 // If a page fault occurs in SMM range\r
144 //\r
145 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
146 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
147 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
717fb604 148 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
7947da3c
MK
149 DEBUG_CODE (\r
150 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
151 );\r
152 CpuDeadLoop ();\r
153 }\r
d2fc7711
JY
154 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {\r
155 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));\r
156 DEBUG_CODE (\r
157 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
158 );\r
159 CpuDeadLoop ();\r
160 }\r
7947da3c
MK
161 }\r
162\r
163 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
164 SmmProfilePFHandler (\r
165 SystemContext.SystemContextIa32->Eip,\r
166 SystemContext.SystemContextIa32->ExceptionData\r
167 );\r
168 } else {\r
169 SmiDefaultPFHandler ();\r
170 }\r
171\r
fe3a75bc 172 ReleaseSpinLock (mPFLock);\r
7947da3c 173}\r
717fb604
JY
174\r
175/**\r
176 This function sets memory attribute for page table.\r
177**/\r
178VOID\r
179SetPageTableAttributes (\r
180 VOID\r
181 )\r
182{\r
183 UINTN Index2;\r
184 UINTN Index3;\r
185 UINT64 *L1PageTable;\r
186 UINT64 *L2PageTable;\r
187 UINT64 *L3PageTable;\r
188 BOOLEAN IsSplitted;\r
189 BOOLEAN PageTableSplitted;\r
190\r
191 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
192\r
193 //\r
194 // Disable write protection, because we need mark page table to be write protected.\r
195 // We need *write* page table memory, to mark itself to be *read only*.\r
196 //\r
197 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
198\r
199 do {\r
200 DEBUG ((DEBUG_INFO, "Start...\n"));\r
201 PageTableSplitted = FALSE;\r
202\r
203 L3PageTable = (UINT64 *)GetPageTableBase ();\r
204\r
205 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
206 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
207\r
208 for (Index3 = 0; Index3 < 4; Index3++) {\r
241f9149 209 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
210 if (L2PageTable == NULL) {\r
211 continue;\r
212 }\r
213\r
214 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
215 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
216\r
217 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
218 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
219 // 2M\r
220 continue;\r
221 }\r
241f9149 222 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
223 if (L1PageTable == NULL) {\r
224 continue;\r
225 }\r
226 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
227 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
228 }\r
229 }\r
230 } while (PageTableSplitted);\r
231\r
232 //\r
233 // Enable write protection, after page table updated.\r
234 //\r
235 AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
236\r
237 return ;\r
238}\r