]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm: Combine INIT-SIPI-SIPI.
[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 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
159 SmmProfilePFHandler (\r
160 SystemContext.SystemContextIa32->Eip,\r
161 SystemContext.SystemContextIa32->ExceptionData\r
162 );\r
163 } else {\r
164 DumpCpuContext (InterruptType, SystemContext);\r
165 SmiDefaultPFHandler ();\r
166 }\r
167\r
168 ReleaseSpinLock (mPFLock);\r
169}\r
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
205 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
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
218 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
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