]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm: Consume new APIs
[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
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
b8caae19
JF
91 IN EFI_EXCEPTION_TYPE InterruptType,\r
92 IN EFI_SYSTEM_CONTEXT SystemContext\r
7947da3c
MK
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
b8caae19 111 DumpCpuContext (InterruptType, SystemContext);\r
7fa1376c
JY
112 CpuIndex = GetCpuIndex ();\r
113 GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);\r
114 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&\r
115 (PFAddress >= GuardPageAddress) &&\r
116 (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) {\r
117 DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));\r
118 } else {\r
7fa1376c
JY
119 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
120 DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));\r
121 DEBUG_CODE (\r
122 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
123 );\r
124 } else {\r
125 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));\r
126 DEBUG_CODE (\r
127 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
128 );\r
129 }\r
130 }\r
7947da3c
MK
131 CpuDeadLoop ();\r
132 }\r
133\r
134 //\r
135 // If a page fault occurs in SMM range\r
136 //\r
137 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||\r
138 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
b8caae19 139 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c 140 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
717fb604 141 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
7947da3c
MK
142 DEBUG_CODE (\r
143 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
144 );\r
145 CpuDeadLoop ();\r
146 }\r
d2fc7711
JY
147 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {\r
148 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));\r
149 DEBUG_CODE (\r
150 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);\r
151 );\r
152 CpuDeadLoop ();\r
153 }\r
7947da3c
MK
154 }\r
155\r
156 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
157 SmmProfilePFHandler (\r
158 SystemContext.SystemContextIa32->Eip,\r
159 SystemContext.SystemContextIa32->ExceptionData\r
160 );\r
161 } else {\r
b8caae19 162 DumpCpuContext (InterruptType, SystemContext);\r
7947da3c
MK
163 SmiDefaultPFHandler ();\r
164 }\r
165\r
fe3a75bc 166 ReleaseSpinLock (mPFLock);\r
7947da3c 167}\r
717fb604
JY
168\r
169/**\r
170 This function sets memory attribute for page table.\r
171**/\r
172VOID\r
173SetPageTableAttributes (\r
174 VOID\r
175 )\r
176{\r
177 UINTN Index2;\r
178 UINTN Index3;\r
179 UINT64 *L1PageTable;\r
180 UINT64 *L2PageTable;\r
181 UINT64 *L3PageTable;\r
182 BOOLEAN IsSplitted;\r
183 BOOLEAN PageTableSplitted;\r
184\r
185 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));\r
186\r
187 //\r
188 // Disable write protection, because we need mark page table to be write protected.\r
189 // We need *write* page table memory, to mark itself to be *read only*.\r
190 //\r
191 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);\r
192\r
193 do {\r
194 DEBUG ((DEBUG_INFO, "Start...\n"));\r
195 PageTableSplitted = FALSE;\r
196\r
197 L3PageTable = (UINT64 *)GetPageTableBase ();\r
198\r
199 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
200 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
201\r
202 for (Index3 = 0; Index3 < 4; Index3++) {\r
241f9149 203 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
204 if (L2PageTable == NULL) {\r
205 continue;\r
206 }\r
207\r
208 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
209 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
210\r
211 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {\r
212 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {\r
213 // 2M\r
214 continue;\r
215 }\r
241f9149 216 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
717fb604
JY
217 if (L1PageTable == NULL) {\r
218 continue;\r
219 }\r
220 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);\r
221 PageTableSplitted = (PageTableSplitted || IsSplitted);\r
222 }\r
223 }\r
224 } while (PageTableSplitted);\r
225\r
226 //\r
227 // Enable write protection, after page table updated.\r
228 //\r
229 AsmWriteCr0 (AsmReadCr0() | CR0_WP);\r
230\r
231 return ;\r
232}\r