]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
BaseTools: Fix GenSec can't found the depex file
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / PageTbl.c
... / ...
CommitLineData
1/** @file\r
2Page table manipulation functions for IA-32 processors\r
3\r
4Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
6\r
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
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
32 EFI_STATUS Status;\r
33\r
34 //\r
35 // Initialize spin lock\r
36 //\r
37 InitializeSpinLock (mPFLock);\r
38\r
39 mPhysicalAddressBits = 32;\r
40\r
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
57 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
58 ASSERT_EFI_ERROR (Status);\r
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
67 return Gen4GPageTable (TRUE);\r
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
93 IN EFI_EXCEPTION_TYPE InterruptType,\r
94 IN EFI_SYSTEM_CONTEXT SystemContext\r
95 )\r
96{\r
97 UINTN PFAddress;\r
98 UINTN GuardPageAddress;\r
99 UINTN CpuIndex;\r
100\r
101 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);\r
102\r
103 AcquireSpinLock (mPFLock);\r
104\r
105 PFAddress = AsmReadCr2 ();\r
106\r
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
112 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
113 DumpCpuContext (InterruptType, SystemContext);\r
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
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
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
141 DumpCpuContext (InterruptType, SystemContext);\r
142 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
143 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
144 DEBUG_CODE (\r
145 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
146 );\r
147 CpuDeadLoop ();\r
148 }\r
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
156 }\r
157\r
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
170 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
171 SmmProfilePFHandler (\r
172 SystemContext.SystemContextIa32->Eip,\r
173 SystemContext.SystemContextIa32->ExceptionData\r
174 );\r
175 } else {\r
176 DumpCpuContext (InterruptType, SystemContext);\r
177 SmiDefaultPFHandler ();\r
178 }\r
179\r
180 ReleaseSpinLock (mPFLock);\r
181}\r
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
199 //\r
200 // Don't mark page table as read-only if heap guard is enabled.\r
201 //\r
202 // BIT2: SMM page guard enabled\r
203 // BIT3: SMM pool guard enabled\r
204 //\r
205 if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) {\r
206 return ;\r
207 }\r
208\r
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
227 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
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
240 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
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