]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
MdeModulePkg/Core/Dxe: Add EndOfDxe workaround for NULL pointer detection
[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
158 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
159 SmmProfilePFHandler (\r
160 SystemContext.SystemContextIa32->Eip,\r
161 SystemContext.SystemContextIa32->ExceptionData\r
162 );\r
163 } else {\r
b8caae19 164 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c
MK
165 SmiDefaultPFHandler ();\r
166 }\r
167\r
fe3a75bc 168 ReleaseSpinLock (mPFLock);\r
7947da3c 169}\r
717fb604
JY
170\r
171/**\r
172 This function sets memory attribute for page table.\r
173**/\r
174VOID\r
175SetPageTableAttributes (\r
176 VOID\r
177 )\r
178{\r
179 UINTN Index2;\r
180 UINTN Index3;\r
181 UINT64 *L1PageTable;\r
182 UINT64 *L2PageTable;\r
183 UINT64 *L3PageTable;\r
184 BOOLEAN IsSplitted;\r
185 BOOLEAN PageTableSplitted;\r
186\r
187 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
188\r
189 //\r
190 // Disable write protection, because we need mark page table to be write protected.\r
191 // We need *write* page table memory, to mark itself to be *read only*.\r
192 //\r
193 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
194\r
195 do {\r
196 DEBUG ((DEBUG_INFO, "Start...\n"));\r
197 PageTableSplitted = FALSE;\r
198\r
199 L3PageTable = (UINT64 *)GetPageTableBase ();\r
200\r
201 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
202 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
203\r
204 for (Index3 = 0; Index3 < 4; Index3++) {\r
241f9149 205 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
206 if (L2PageTable == NULL) {\r
207 continue;\r
208 }\r
209\r
210 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
211 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
212\r
213 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
214 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
215 // 2M\r
216 continue;\r
217 }\r
241f9149 218 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
219 if (L1PageTable == NULL) {\r
220 continue;\r
221 }\r
222 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
223 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
224 }\r
225 }\r
226 } while (PageTableSplitted);\r
227\r
228 //\r
229 // Enable write protection, after page table updated.\r
230 //\r
231 AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
232\r
233 return ;\r
234}\r