]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
BaseTools/EfiRom: Add multiple device id support
[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 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
55 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);\r
56 ASSERT_EFI_ERROR (Status);\r
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
65 return Gen4GPageTable (TRUE);\r
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
96 UINTN GuardPageAddress;\r
97 UINTN CpuIndex;\r
98\r
99 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);\r
100\r
101 AcquireSpinLock (mPFLock);\r
102\r
103 PFAddress = AsmReadCr2 ();\r
104\r
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
110 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {\r
111 DumpCpuContext (InterruptType, SystemContext);\r
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
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
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
139 DumpCpuContext (InterruptType, SystemContext);\r
140 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {\r
141 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));\r
142 DEBUG_CODE (\r
143 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);\r
144 );\r
145 CpuDeadLoop ();\r
146 }\r
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
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
162 DumpCpuContext (InterruptType, SystemContext);\r
163 SmiDefaultPFHandler ();\r
164 }\r
165\r
166 ReleaseSpinLock (mPFLock);\r
167}\r
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
203 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
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
216 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);\r
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