File: | home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/stm/Stm/StmPkg/Core/Runtime/SmmEptHandler.c |
Warning: | line 150, column 7 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /** @file | |||
2 | SMM EPT handler | |||
3 | ||||
4 | Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR> | |||
5 | This program and the accompanying materials | |||
6 | are licensed and made available under the terms and conditions of the BSD License | |||
7 | which accompanies this distribution. The full text of the license may be found at | |||
8 | http://opensource.org/licenses/bsd-license.php. | |||
9 | ||||
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |||
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |||
12 | ||||
13 | **/ | |||
14 | ||||
15 | #include "StmRuntime.h" | |||
16 | #include "PeStm.h" | |||
17 | ||||
18 | #define BUS_FROM_PCIE_ADDRESS(PcieAddress)(UINT8)(((UINTN)(PcieAddress) & 0x0FF00000) >> 20) (UINT8)(((UINTN)(PcieAddress) & 0x0FF00000) >> 20) | |||
19 | #define DEVICE_FROM_PCIE_ADDRESS(PcieAddress)(UINT8)(((UINTN)(PcieAddress) & 0x000F8000) >> 15) (UINT8)(((UINTN)(PcieAddress) & 0x000F8000) >> 15) | |||
20 | #define FUNCTION_FROM_PCIE_ADDRESS(PcieAddress)(UINT8)(((UINTN)(PcieAddress) & 0x00007000) >> 12) (UINT8)(((UINTN)(PcieAddress) & 0x00007000) >> 12) | |||
21 | #define REGISTER_FROM_PCIE_ADDRESS(PcieAddress)(UINT16)((UINTN)(PcieAddress) & 0x00000FFF) (UINT16)((UINTN)(PcieAddress) & 0x00000FFF) | |||
22 | ||||
23 | #define PAGE_PROGATE_BITS(0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020) (BIT00x00000001 | BIT10x00000002 | BIT20x00000004 | BIT30x00000008 | BIT40x00000010 | BIT50x00000020) | |||
24 | ||||
25 | #define PAGING_4K_MASK0xFFF 0xFFF | |||
26 | #define PAGING_2M_MASK0x1FFFFF 0x1FFFFF | |||
27 | #define PAGING_1G_MASK0x3FFFFFFF 0x3FFFFFFF | |||
28 | ||||
29 | #define PAGING_PAE_INDEX_MASK0x1FF 0x1FF | |||
30 | ||||
31 | #define PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull 0x000FFFFFFFFFF000ull | |||
32 | #define PAGING_2M_ADDRESS_MASK_640x000FFFFFFFE00000ull 0x000FFFFFFFE00000ull | |||
33 | #define PAGING_1G_ADDRESS_MASK_640x000FFFFFC0000000ull 0x000FFFFFC0000000ull | |||
34 | ||||
35 | typedef enum { | |||
36 | PageNone, | |||
37 | Page4K, | |||
38 | Page2M, | |||
39 | Page1G, | |||
40 | } PAGE_ATTRIBUTE; | |||
41 | ||||
42 | typedef struct { | |||
43 | PAGE_ATTRIBUTE Attribute; | |||
44 | UINT64 Length; | |||
45 | UINT64 AddressMask; | |||
46 | } PAGE_ATTRIBUTE_TABLE; | |||
47 | ||||
48 | PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = { | |||
49 | {Page4K, SIZE_4KB0x00001000, PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull}, | |||
50 | {Page2M, SIZE_2MB0x00200000, PAGING_2M_ADDRESS_MASK_640x000FFFFFFFE00000ull}, | |||
51 | {Page1G, SIZE_1GB0x40000000, PAGING_1G_ADDRESS_MASK_640x000FFFFFC0000000ull}, | |||
52 | }; | |||
53 | ||||
54 | extern UINT64 | |||
55 | EptAllocatePte( | |||
56 | IN UINT64 EptPointer, | |||
57 | IN UINT64 BaseAddress, | |||
58 | IN UINT64 Length, | |||
59 | IN UINT64 PhySize | |||
60 | ); | |||
61 | ||||
62 | extern UINT8 GetMemoryType (IN UINT64 BaseAddress); | |||
63 | ||||
64 | /** | |||
65 | Return length according to page attributes. | |||
66 | ||||
67 | @param[in] PageAttributes The page attribute of the page entry. | |||
68 | ||||
69 | @return The length of page entry. | |||
70 | **/ | |||
71 | UINTN | |||
72 | PageAttributeToLength ( | |||
73 | IN PAGE_ATTRIBUTE PageAttribute | |||
74 | ) | |||
75 | { | |||
76 | UINTN Index; | |||
77 | for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) { | |||
78 | if (PageAttribute == mPageAttributeTable[Index].Attribute) { | |||
79 | return (UINTN)mPageAttributeTable[Index].Length; | |||
80 | } | |||
81 | } | |||
82 | return 0; | |||
83 | } | |||
84 | ||||
85 | /** | |||
86 | Return address mask according to page attributes. | |||
87 | ||||
88 | @param[in] PageAttributes The page attribute of the page entry. | |||
89 | ||||
90 | @return The address mask of page entry. | |||
91 | **/ | |||
92 | UINTN | |||
93 | PageAttributeToMask ( | |||
94 | IN PAGE_ATTRIBUTE PageAttribute | |||
95 | ) | |||
96 | { | |||
97 | UINTN Index; | |||
98 | for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) { | |||
99 | if (PageAttribute == mPageAttributeTable[Index].Attribute) { | |||
100 | return (UINTN)mPageAttributeTable[Index].AddressMask; | |||
101 | } | |||
102 | } | |||
103 | return 0; | |||
104 | } | |||
105 | ||||
106 | /** | |||
107 | Return page table entry to match the address. | |||
108 | ||||
109 | @param[in] Address The address to be checked. | |||
110 | @param[out] PageAttributes The page attribute of the page entry. | |||
111 | ||||
112 | @return The page entry. | |||
113 | **/ | |||
114 | EPT_ENTRY * | |||
115 | GetPageTableEntry ( | |||
116 | IN UINT64 EptPointer, | |||
117 | IN PHYSICAL_ADDRESS Address, | |||
118 | IN PHYSICAL_ADDRESS PhyAddress, | |||
119 | IN UINT64 PhySize, | |||
120 | OUT PAGE_ATTRIBUTE *PageAttribute | |||
121 | ) | |||
122 | { | |||
123 | UINTN Index1; | |||
124 | UINTN Index2; | |||
125 | UINTN Index3; | |||
126 | UINTN Index4; | |||
127 | EPT_ENTRY *L1PageTable; | |||
128 | EPT_ENTRY *L2PageTable; | |||
129 | EPT_ENTRY *L3PageTable; | |||
130 | EPT_ENTRY *L4PageTable; | |||
131 | ||||
132 | //DEBUG ((EFI_D_INFO, "GetPageTableEntry: Address(guest) %llx Address(Physical) %llx Size %llx\n", (UINTN)Address, (UINTN) PhyAddress, (UINTN) PhySize)); | |||
133 | ||||
134 | Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK0x1FF; | |||
135 | Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK0x1FF; | |||
136 | Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK0x1FF; | |||
137 | Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK0x1FF; | |||
138 | //DEBUG ((EFI_D_INFO, "Index: %x %x %x %x\n", Index4, Index3, Index2, Index1)); | |||
139 | ||||
140 | L4PageTable = (EPT_ENTRY *)(UINTN) EptPointer; //(mGuestContextCommonSmm.EptPointer.Uint64 & PAGING_4K_ADDRESS_MASK_64); | |||
141 | if (L4PageTable[Index4].Uint64 == 0) { | |||
142 | if(EptAllocatePte(EptPointer, Address, PhyAddress, PhySize) == 0) | |||
143 | { | |||
144 | *PageAttribute = PageNone; | |||
145 | return NULL((void *) 0); | |||
146 | } | |||
147 | } | |||
148 | ||||
149 | L3PageTable = (EPT_ENTRY *)(UINTN)(L4PageTable[Index4].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
150 | if (L3PageTable[Index3].Uint64 == 0) { | |||
| ||||
151 | if(EptAllocatePte(EptPointer, Address, PhyAddress, PhySize) == 0) | |||
152 | { | |||
153 | *PageAttribute = PageNone; | |||
154 | return NULL((void *) 0); | |||
155 | } | |||
156 | } | |||
157 | if (L3PageTable[Index3].Bits32.Sp != 0) { | |||
158 | // 1G | |||
159 | *PageAttribute = Page1G; | |||
160 | return &L3PageTable[Index3]; | |||
161 | } | |||
162 | ||||
163 | L2PageTable = (EPT_ENTRY *)(UINTN)(L3PageTable[Index3].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
164 | if (L2PageTable[Index2].Uint64 == 0) { | |||
165 | if(EptAllocatePte(EptPointer, Address, PhyAddress, PhySize) == 0) | |||
166 | { | |||
167 | *PageAttribute = PageNone; | |||
168 | return NULL((void *) 0); | |||
169 | } | |||
170 | } | |||
171 | if (L2PageTable[Index2].Bits32.Sp != 0) { | |||
172 | // 2M | |||
173 | *PageAttribute = Page2M; | |||
174 | return &L2PageTable[Index2]; | |||
175 | } | |||
176 | ||||
177 | // Special case where there exists a L1 Page Table and the caller wants the range to be 2M | |||
178 | // If the stars line up (both Address and PhyAddress are on 2MB boundries), then | |||
179 | // free the L1 Page table and replace it with a super page | |||
180 | ||||
181 | if ((Address >= BASE_2MB0x00200000) && | |||
182 | ((Address & PAGING_2M_MASK0x1FFFFF) == 0) && | |||
183 | ((PhyAddress & PAGING_2M_MASK0x1FFFFF) == 0) && | |||
184 | (PhySize > PAGING_2M_MASK0x1FFFFF)) | |||
185 | { | |||
186 | //DEBUG((EFI_D_INFO, "GetPageTableEntry: replacing L1PageTable: 0x%llx with superpage\n", L2PageTable[Index2].Uint64)); | |||
187 | FreePages((UINT64 *)((UINTN)(L2PageTable[Index2].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull)), 1); // free up the L2 | |||
188 | ||||
189 | L2PageTable[Index2].Uint64 = 0; | |||
190 | if(EptAllocatePte(EptPointer, Address, PhyAddress, PhySize) == 0) | |||
191 | { | |||
192 | *PageAttribute = PageNone; | |||
193 | return NULL((void *) 0); | |||
194 | } | |||
195 | *PageAttribute = Page2M; | |||
196 | return &L2PageTable[Index2]; | |||
197 | } | |||
198 | ||||
199 | // 4k | |||
200 | L1PageTable = (EPT_ENTRY *)(UINTN)(L2PageTable[Index2].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
201 | if ((L1PageTable[Index1].Uint64 == 0) && (Address != 0)) { | |||
202 | if(EptAllocatePte(EptPointer, Address, PhyAddress, PhySize) == 0){ | |||
203 | *PageAttribute = PageNone; | |||
204 | return NULL((void *) 0); | |||
205 | } | |||
206 | } | |||
207 | *PageAttribute = Page4K; | |||
208 | return &L1PageTable[Index1]; | |||
209 | } | |||
210 | ||||
211 | /** | |||
212 | Modify memory attributes of page entry. | |||
213 | ||||
214 | @param[in] PageEntry The page entry. | |||
215 | @param[in] Attributes The bit mask of attributes to modify for the memory region. | |||
216 | @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes. | |||
217 | @param[out] IsModified TRUE means page table modified. FALSE means page table not modified. | |||
218 | **/ | |||
219 | VOIDvoid | |||
220 | ConvertPageEntryAttribute ( | |||
221 | IN EPT_ENTRY *PageEntry, | |||
222 | IN UINT32 Ra, | |||
223 | IN UINT32 Wa, | |||
224 | IN UINT32 Xa, | |||
225 | IN EPT_PAGE_ATTRIBUTE_SETTING EptPageAttributeSetting, | |||
226 | IN UINT32 EMT | |||
227 | ) | |||
228 | { | |||
229 | UINT64 CurrentPageEntry; | |||
230 | ||||
231 | CurrentPageEntry = PageEntry->Uint64; | |||
232 | switch (EptPageAttributeSetting) { | |||
233 | case EptPageAttributeSet: | |||
234 | PageEntry->Bits32.Ra = (UINT32)Ra; | |||
235 | PageEntry->Bits32.Wa = (UINT32)Wa; | |||
236 | PageEntry->Bits32.Xa = (UINT32)Xa; | |||
237 | break; | |||
238 | case EptPageAttributeAnd: | |||
239 | PageEntry->Bits32.Ra &= (UINT32)Ra; | |||
240 | PageEntry->Bits32.Wa &= (UINT32)Wa; | |||
241 | PageEntry->Bits32.Xa &= (UINT32)Xa; | |||
242 | break; | |||
243 | case EptPageAttributeOr: | |||
244 | PageEntry->Bits32.Ra |= (UINT32)Ra; | |||
245 | PageEntry->Bits32.Wa |= (UINT32)Wa; | |||
246 | PageEntry->Bits32.Xa |= (UINT32)Xa; | |||
247 | break; | |||
248 | default: | |||
249 | CpuDeadLoop (); | |||
250 | break; | |||
251 | } | |||
252 | ||||
253 | if(PageEntry->Bits32.Wa == 1) | |||
254 | PageEntry->Bits.Ra = 1; // have to have read with write(vol 3c 28.2.3.1) | |||
255 | if(PageEntry->Bits32.Xa == 1) | |||
256 | PageEntry->Bits32.Ra = 1; //have to have read with execute (except for some processors) | |||
257 | ||||
258 | if(EMT == -1) | |||
259 | PageEntry->Bits32.Emt = GetMemoryType((PageEntry->Uint64) & PAGING_4K_MASK0xFFF ); | |||
260 | else | |||
261 | PageEntry->Bits32.Emt = EMT; // let caller set the memory type (at his own risk) | |||
262 | ||||
263 | #ifdef DEBUGPRINT | |||
264 | DEBUG((EFI_D_INFO, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n",do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))) | |||
265 | (UINT64) CurrentPageEntry,do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))) | |||
266 | PageEntry->Uint64,do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))) | |||
267 | PageEntry->Bits32.Ra,do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))) | |||
268 | PageEntry->Bits32.Wa,do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))) | |||
269 | PageEntry->Bits32.Xa,do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))) | |||
270 | PageEntry->Bits32.Emt))do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "ConvertPageEntryAttribute - 0x%llx->0x%llx (%1x%1x%1x) Emt: %3x\n" , (UINT64) CurrentPageEntry, PageEntry->Uint64, PageEntry-> Bits32.Ra, PageEntry->Bits32.Wa, PageEntry->Bits32.Xa, PageEntry ->Bits32.Emt); } } while (((BOOLEAN)(0==1))); | |||
271 | #endif | |||
272 | if (CurrentPageEntry != PageEntry->Uint64) { | |||
273 | //DEBUG ((EFI_D_INFO, "ConvertPageEntryAttribute 0x%lx->0x%lx\n", CurrentPageEntry, PageEntry->Uint64)); | |||
274 | } | |||
275 | } | |||
276 | ||||
277 | /** | |||
278 | This function returns if there is need to split page entry. | |||
279 | ||||
280 | @param[in] BaseAddress The base address to be checked. | |||
281 | @param[in] Length The length to be checked. | |||
282 | @param[in] PageAttribute The page attribute of the page entry. | |||
283 | ||||
284 | @retval SplitAttributes on if there is need to split page entry. | |||
285 | **/ | |||
286 | PAGE_ATTRIBUTE | |||
287 | NeedSplitPage ( | |||
288 | IN PHYSICAL_ADDRESS BaseAddress, | |||
289 | IN UINT64 Length, | |||
290 | IN PAGE_ATTRIBUTE PageAttribute | |||
291 | ) | |||
292 | { | |||
293 | UINT64 PageEntryLength; | |||
294 | ||||
295 | PageEntryLength = PageAttributeToLength (PageAttribute); | |||
296 | ||||
297 | if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) { | |||
298 | return PageNone; | |||
299 | } | |||
300 | ||||
301 | if (((BaseAddress & PAGING_2M_MASK0x1FFFFF) != 0) || (Length < SIZE_2MB0x00200000)) { | |||
302 | return Page4K; | |||
303 | } | |||
304 | ||||
305 | return Page2M; | |||
306 | } | |||
307 | ||||
308 | /** | |||
309 | This function splits one page entry to small page entries. | |||
310 | ||||
311 | @param[in] PageEntry The page entry to be splitted. | |||
312 | @param[in] PageAttribute The page attribute of the page entry. | |||
313 | @param[in] SplitAttribute How to split the page entry. | |||
314 | ||||
315 | @retval RETURN_SUCCESS The page entry is splitted. | |||
316 | @retval RETURN_UNSUPPORTED The page entry does not support to be splitted. | |||
317 | @retval RETURN_OUT_OF_RESOURCES No resource to split page entry. | |||
318 | **/ | |||
319 | RETURN_STATUS | |||
320 | SplitPage ( | |||
321 | IN EPT_ENTRY *PageEntry, | |||
322 | IN PAGE_ATTRIBUTE PageAttribute, | |||
323 | IN PAGE_ATTRIBUTE SplitAttribute | |||
324 | ) | |||
325 | { | |||
326 | UINT64 BaseAddress; | |||
327 | EPT_ENTRY *NewPageEntry; | |||
328 | UINTN Index; | |||
329 | ||||
330 | ASSERT (PageAttribute == Page2M || PageAttribute == Page1G)do { if (DebugAssertEnabled ()) { if (!(PageAttribute == Page2M || PageAttribute == Page1G)) { DebugAssert ("/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/stm/Stm/StmPkg/Core/Runtime/SmmEptHandler.c" , 330, "PageAttribute == Page2M || PageAttribute == Page1G"); } } } while (((BOOLEAN)(0==1))); | |||
331 | ||||
332 | if (PageAttribute == Page2M) { | |||
333 | // | |||
334 | // Split 2M to 4K | |||
335 | // | |||
336 | ASSERT (SplitAttribute == Page4K)do { if (DebugAssertEnabled ()) { if (!(SplitAttribute == Page4K )) { DebugAssert ("/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/stm/Stm/StmPkg/Core/Runtime/SmmEptHandler.c" , 336, "SplitAttribute == Page4K"); } } } while (((BOOLEAN)(0 ==1))); | |||
337 | if (SplitAttribute == Page4K) { | |||
338 | NewPageEntry = (EPT_ENTRY *)AllocatePages (1); | |||
339 | //DEBUG ((EFI_D_INFO, "Split - 0x%x\n", NewPageEntry)); | |||
340 | if (NewPageEntry == NULL((void *) 0)) { | |||
341 | return RETURN_OUT_OF_RESOURCES((RETURN_STATUS)(0x8000000000000000ULL | (9))); | |||
342 | } | |||
343 | BaseAddress = PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_640x000FFFFFFFE00000ull; | |||
344 | for (Index = 0; Index < SIZE_4KB0x00001000 / sizeof(UINT64); Index++) { | |||
345 | NewPageEntry[Index].Uint64 = BaseAddress + SIZE_4KB0x00001000 * Index + (PageEntry->Uint64 & PAGE_PROGATE_BITS(0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020)); | |||
346 | } | |||
347 | PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry; | |||
348 | PageEntry->Bits32.Ra = 1; | |||
349 | PageEntry->Bits32.Wa = 1; | |||
350 | PageEntry->Bits32.Xa = 1; | |||
351 | return RETURN_SUCCESS0; | |||
352 | } else { | |||
353 | return RETURN_UNSUPPORTED((RETURN_STATUS)(0x8000000000000000ULL | (3))); | |||
354 | } | |||
355 | } else if (PageAttribute == Page1G) { | |||
356 | // | |||
357 | // Split 1G to 2M | |||
358 | // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table. | |||
359 | // | |||
360 | ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K)do { if (DebugAssertEnabled ()) { if (!(SplitAttribute == Page2M || SplitAttribute == Page4K)) { DebugAssert ("/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/stm/Stm/StmPkg/Core/Runtime/SmmEptHandler.c" , 360, "SplitAttribute == Page2M || SplitAttribute == Page4K" ); } } } while (((BOOLEAN)(0==1))); | |||
361 | if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) { | |||
362 | NewPageEntry = (EPT_ENTRY *)AllocatePages (1); | |||
363 | DEBUG ((EFI_D_INFO, "Split - 0x%x\n", NewPageEntry))do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "Split - 0x%x\n" , NewPageEntry); } } while (((BOOLEAN)(0==1))); | |||
364 | if (NewPageEntry == NULL((void *) 0)) { | |||
365 | return RETURN_OUT_OF_RESOURCES((RETURN_STATUS)(0x8000000000000000ULL | (9))); | |||
366 | } | |||
367 | BaseAddress = PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_640x000FFFFFC0000000ull; | |||
368 | for (Index = 0; Index < SIZE_4KB0x00001000 / sizeof(UINT64); Index++) { | |||
369 | NewPageEntry[Index].Uint64 = BaseAddress + SIZE_2MB0x00200000 * Index + (PageEntry->Uint64 & PAGE_PROGATE_BITS(0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020)); | |||
370 | NewPageEntry[Index].Bits32.Sp = 1; | |||
371 | } | |||
372 | PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry; | |||
373 | PageEntry->Bits32.Ra = 1; | |||
374 | PageEntry->Bits32.Wa = 1; | |||
375 | PageEntry->Bits32.Xa = 1; | |||
376 | return RETURN_SUCCESS0; | |||
377 | } else { | |||
378 | return RETURN_UNSUPPORTED((RETURN_STATUS)(0x8000000000000000ULL | (3))); | |||
379 | } | |||
380 | } else { | |||
381 | return RETURN_UNSUPPORTED((RETURN_STATUS)(0x8000000000000000ULL | (3))); | |||
382 | } | |||
383 | } | |||
384 | ||||
385 | /** | |||
386 | ||||
387 | This function translate guest physical address to host address. | |||
388 | ||||
389 | @param Addr Guest physical address | |||
390 | @param EntryPtr EPT entry pointer | |||
391 | NULL on output means Entry not found. | |||
392 | ||||
393 | @return Host physical address | |||
394 | **/ | |||
395 | UINTN | |||
396 | TranslateEPTGuestToHost ( | |||
397 | IN UINT64 EptPointer, | |||
398 | IN UINTN Addr, | |||
399 | OUT EPT_ENTRY **EntryPtr OPTIONAL | |||
400 | ); | |||
401 | ||||
402 | /** | |||
403 | ||||
404 | This function translate guest physical address to host address. | |||
405 | ||||
406 | @param EptPointer EPT pointer | |||
407 | @param GuestPhysicalAddress Guest physical address | |||
408 | @param HostPhysicalAddress Host physical address | |||
409 | ||||
410 | @retval TRUE HostPhysicalAddress is found | |||
411 | @retval FALSE HostPhysicalAddress is not found | |||
412 | **/ | |||
413 | BOOLEAN | |||
414 | LookupSmiGuestPhysicalToHostPhysical ( | |||
415 | IN UINT64 EptPointer, | |||
416 | IN UINTN GuestPhysicalAddress, | |||
417 | OUT UINTN *HostPhysicalAddress | |||
418 | ) | |||
419 | { | |||
420 | EPT_ENTRY *EptEntry; | |||
421 | ||||
422 | EptEntry = NULL((void *) 0); | |||
423 | *HostPhysicalAddress = TranslateEPTGuestToHost (EptPointer, GuestPhysicalAddress, &EptEntry); | |||
424 | if (EptEntry == NULL((void *) 0)) { | |||
425 | return FALSE((BOOLEAN)(0==1)); | |||
426 | } else { | |||
427 | return TRUE((BOOLEAN)(1==1)); | |||
428 | } | |||
429 | } | |||
430 | ||||
431 | /** | |||
432 | ||||
433 | This function translate guest linear address to host address. | |||
434 | ||||
435 | @param CpuIndex CPU index | |||
436 | @param GuestLinearAddress Guest linear address | |||
437 | ||||
438 | @return Host physical address | |||
439 | **/ | |||
440 | UINTN | |||
441 | GuestLinearToHostPhysical ( | |||
442 | IN UINT32 CpuIndex, | |||
443 | IN UINTN GuestLinearAddress | |||
444 | ) | |||
445 | { | |||
446 | UINTN GuestPhysicalAddress; | |||
447 | UINT32 VmType = mHostContextCommon.HostContextPerCpu[CpuIndex].GuestVmType; | |||
448 | ||||
449 | GuestPhysicalAddress = (UINTN)GuestLinearToGuestPhysical (CpuIndex, GuestLinearAddress); | |||
450 | return TranslateEPTGuestToHost (mGuestContextCommonSmm[VmType].EptPointer.Uint64, GuestPhysicalAddress, NULL((void *) 0)); | |||
451 | } | |||
452 | ||||
453 | /** | |||
454 | ||||
455 | This function translate guest physical address to host address. | |||
456 | ||||
457 | @param EptPointer EPT pointer | |||
458 | @param Addr Guest physical address | |||
459 | @param EntryPtr EPT entry pointer. | |||
460 | NULL on output means Entry not found. | |||
461 | ||||
462 | @return Host physical address | |||
463 | **/ | |||
464 | UINTN | |||
465 | TranslateEPTGuestToHost ( | |||
466 | IN UINT64 EptPointer, | |||
467 | IN UINTN Addr, | |||
468 | OUT EPT_ENTRY **EntryPtr OPTIONAL | |||
469 | ) | |||
470 | { | |||
471 | EPT_ENTRY *L1PageTable; | |||
472 | EPT_ENTRY *L2PageTable; | |||
473 | EPT_ENTRY *L3PageTable; | |||
474 | EPT_ENTRY *L4PageTable; | |||
475 | UINTN Index1; | |||
476 | UINTN Index2; | |||
477 | UINTN Index3; | |||
478 | UINTN Index4; | |||
479 | UINTN Offset; | |||
480 | ||||
481 | Index4 = ((UINTN)RShiftU64 (Addr, 39)) & 0x1ff; | |||
482 | Index3 = ((UINTN)Addr >> 30) & 0x1ff; | |||
483 | Index2 = ((UINTN)Addr >> 21) & 0x1ff; | |||
484 | Index1 = ((UINTN)Addr >> 12) & 0x1ff; | |||
485 | Offset = ((UINTN)Addr & 0xFFF); | |||
486 | ||||
487 | if (EntryPtr != NULL((void *) 0)) { | |||
488 | *EntryPtr = NULL((void *) 0); | |||
489 | } | |||
490 | L4PageTable = (EPT_ENTRY *)(UINTN)((UINTN)EptPointer & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
491 | if ((L4PageTable[Index4].Bits32.Ra == 0) && | |||
492 | (L4PageTable[Index4].Bits32.Wa == 0) && | |||
493 | (L4PageTable[Index4].Bits32.Xa == 0)) { | |||
494 | if (EntryPtr != NULL((void *) 0)) { | |||
495 | *EntryPtr = &L4PageTable[Index4]; | |||
496 | } | |||
497 | return 0; | |||
498 | } | |||
499 | L3PageTable = (EPT_ENTRY *)(UINTN)((UINTN)L4PageTable[Index4].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
500 | if ((L3PageTable[Index3].Bits32.Ra == 0) && | |||
501 | (L3PageTable[Index3].Bits32.Wa == 0) && | |||
502 | (L3PageTable[Index3].Bits32.Xa == 0)) { | |||
503 | if (EntryPtr != NULL((void *) 0)) { | |||
504 | *EntryPtr = &L3PageTable[Index3]; | |||
505 | } | |||
506 | return 0; | |||
507 | } | |||
508 | if (L3PageTable[Index2].Bits32.Sp == 1) { | |||
509 | if (EntryPtr != NULL((void *) 0)) { | |||
510 | *EntryPtr = &L3PageTable[Index3]; | |||
511 | } | |||
512 | return ((UINTN)L3PageTable[Index3].Uint64 & PAGING_1G_ADDRESS_MASK_640x000FFFFFC0000000ull) + ((UINTN)Addr & PAGING_1G_MASK0x3FFFFFFF); | |||
513 | } | |||
514 | ||||
515 | L2PageTable = (EPT_ENTRY *)(UINTN)((UINTN)L3PageTable[Index3].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
516 | if ((L2PageTable[Index2].Bits32.Ra == 0) && | |||
517 | (L2PageTable[Index2].Bits32.Wa == 0) && | |||
518 | (L2PageTable[Index2].Bits32.Xa == 0)) { | |||
519 | if (EntryPtr != NULL((void *) 0)) { | |||
520 | *EntryPtr = &L2PageTable[Index2]; | |||
521 | } | |||
522 | return 0; | |||
523 | } | |||
524 | ||||
525 | if (L2PageTable[Index2].Bits32.Sp == 1) { | |||
526 | if (EntryPtr != NULL((void *) 0)) { | |||
527 | *EntryPtr = &L2PageTable[Index2]; | |||
528 | } | |||
529 | return ((UINTN)L2PageTable[Index2].Uint64 & PAGING_2M_ADDRESS_MASK_640x000FFFFFFFE00000ull) + ((UINTN)Addr & PAGING_2M_MASK0x1FFFFF); | |||
530 | } | |||
531 | ||||
532 | L1PageTable = (EPT_ENTRY *)(UINTN)((UINTN)L2PageTable[Index2].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull); | |||
533 | if ((L1PageTable[Index1].Bits32.Ra == 0) && | |||
534 | (L1PageTable[Index1].Bits32.Wa == 0) && | |||
535 | (L1PageTable[Index1].Bits32.Xa == 0)) { | |||
536 | // not check last one, since user may update it | |||
537 | // return 0; | |||
538 | } | |||
539 | ||||
540 | if (EntryPtr != NULL((void *) 0)) { | |||
541 | *EntryPtr = &L1PageTable[Index1]; | |||
542 | } | |||
543 | return ((UINTN)L1PageTable[Index1].Uint64 & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull) + Offset; | |||
544 | } | |||
545 | ||||
546 | /** | |||
547 | ||||
548 | This function set EPT page table attribute by range. | |||
549 | ||||
550 | @param Base Memory base | |||
551 | @param Length Memory length | |||
552 | @param Ra Read access | |||
553 | @param Wa Write access | |||
554 | @param Xa Execute access | |||
555 | @param EptPageAttributeSetting EPT page attribute setting | |||
556 | ||||
557 | STM/PE note: | |||
558 | ||||
559 | **/ | |||
560 | RETURN_STATUS | |||
561 | EPTSetPageAttributeRange ( | |||
562 | IN UINT64 EptPointerIN, | |||
563 | IN UINT64 Base, | |||
564 | IN UINT64 Length, | |||
565 | IN UINT64 PhysMem, | |||
566 | IN UINT32 Ra, | |||
567 | IN UINT32 Wa, | |||
568 | IN UINT32 Xa, | |||
569 | IN EPT_PAGE_ATTRIBUTE_SETTING EptPageAttributeSetting, | |||
570 | IN INT32 EMT | |||
571 | ) | |||
572 | { | |||
573 | EPT_ENTRY *PageEntry; | |||
574 | PAGE_ATTRIBUTE PageAttribute; | |||
575 | UINTN PageEntryLength; | |||
576 | PAGE_ATTRIBUTE SplitAttribute; | |||
577 | RETURN_STATUS Status; | |||
578 | UINT_128 Data128; | |||
579 | UINT64 EptPointer; | |||
580 | UINT64 Offset; // offset of address into the page | |||
581 | UINT64 OLength; // Length plus offset | |||
582 | #if 0 | |||
583 | DEBUG ((EFI_D_INFO, "EPTSetPageAttributeRange - Base: 0x%016lx - Length: 0x%016lx - PhysMem: 0x%016lx (%1x%1x%1x) EMT:%d\n", Base, Length, PhysMem, Ra, Wa,Xa, EMT))do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "EPTSetPageAttributeRange - Base: 0x%016lx - Length: 0x%016lx - PhysMem: 0x%016lx (%1x%1x%1x) EMT:%d\n" , Base, Length, PhysMem, Ra, Wa,Xa, EMT); } } while (((BOOLEAN )(0==1))); | |||
584 | #endif | |||
585 | // assumption, the user does not change PhysMem on us | |||
586 | ||||
587 | EptPointer = EptPointerIN & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull; // make sure we have only the address | |||
588 | ||||
589 | // Normalize the request to page boundries and lengths | |||
590 | ||||
591 | Offset = Base & PAGING_4K_MASK0xFFF; | |||
592 | OLength = Length + Offset; // actual length based on the start of the page | |||
593 | Length = OLength & PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull; | |||
594 | ||||
595 | if(((OLength & PAGING_4K_MASK0xFFF) > 0) || | |||
596 | (Length == 0)) | |||
597 | { | |||
598 | Length = Length + SIZE_4KB0x00001000; | |||
599 | } | |||
600 | ||||
601 | Base &= PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull; | |||
602 | PhysMem &= PAGING_4K_ADDRESS_MASK_640x000FFFFFFFFFF000ull; | |||
603 | ||||
604 | while (Length
| |||
605 | PageEntry = GetPageTableEntry (EptPointer, Base, PhysMem, Length, &PageAttribute); | |||
606 | // DEBUG((EFI_D_INFO, "EPTSetPageAttributeRange - received page entry: %llx\n", PageEntry->Uint64)); | |||
607 | if (PageEntry == NULL((void *) 0)) { | |||
608 | DEBUG ((EFI_D_INFO, "EPTSetPageAttributeRange - PageEntry == NULL\n"))do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "EPTSetPageAttributeRange - PageEntry == NULL\n" ); } } while (((BOOLEAN)(0==1))); | |||
609 | return RETURN_UNSUPPORTED((RETURN_STATUS)(0x8000000000000000ULL | (3))); | |||
610 | } | |||
611 | PageEntryLength = PageAttributeToLength (PageAttribute); | |||
612 | SplitAttribute = NeedSplitPage (Base, Length, PageAttribute); | |||
613 | if (SplitAttribute == PageNone) { | |||
614 | ConvertPageEntryAttribute (PageEntry, Ra, Wa, Xa, EptPageAttributeSetting, EMT); | |||
615 | // | |||
616 | // Convert success, move to next | |||
617 | // | |||
618 | Base += PageEntryLength; | |||
619 | PhysMem += PageEntryLength; | |||
620 | Length -= PageEntryLength; | |||
621 | } else { | |||
622 | Status = SplitPage (PageEntry, PageAttribute, SplitAttribute); | |||
623 | if (RETURN_ERROR (Status)(((INTN)(RETURN_STATUS)(Status)) < 0)) { | |||
624 | DEBUG ((EFI_D_INFO, "EPTSetPageAttributeRange - SplitPage Error - %r\n", Status))do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "EPTSetPageAttributeRange - SplitPage Error - %r\n" , Status); } } while (((BOOLEAN)(0==1))); | |||
625 | return RETURN_UNSUPPORTED((RETURN_STATUS)(0x8000000000000000ULL | (3))); | |||
626 | } | |||
627 | // | |||
628 | // Just split current page | |||
629 | // Convert success in next around | |||
630 | // | |||
631 | } | |||
632 | } | |||
633 | ||||
634 | Data128.Lo = EptPointerIN; | |||
635 | Data128.Hi = 0; | |||
636 | AsmInvEpt (INVEPT_TYPE_SINGLE_CONTEXT_INVALIDATION1, &Data128); | |||
637 | ||||
638 | //DEBUG ((EFI_D_INFO, "EPTSetPageAttributeRange - %r\n", RETURN_SUCCESS)); | |||
639 | return RETURN_SUCCESS0; | |||
640 | } | |||
641 | ||||
642 | /** | |||
643 | ||||
644 | This function is EPT violation handler for SMM. | |||
645 | ||||
646 | @param Index CPU index | |||
647 | ||||
648 | **/ | |||
649 | ||||
650 | extern unsigned int StmVmPeNmiExCount; | |||
651 | VOIDvoid | |||
652 | SmmEPTViolationHandler ( | |||
653 | IN UINT32 Index | |||
654 | ) | |||
655 | { | |||
656 | VM_EXIT_QUALIFICATION Qualification; | |||
657 | STM_RSC_MEM_DESC *MemDesc; | |||
658 | UINT64 Address; | |||
659 | STM_RSC_PCI_CFG_DESC *PciCfgDesc; | |||
660 | UINT64 PciExpressAddress; | |||
661 | STM_RSC_MEM_DESC LocalMemDesc; | |||
662 | STM_RSC_PCI_CFG_DESC *LocalPciCfgDescPtr; | |||
663 | UINT8 LocalPciCfgDescBuf[STM_LOG_ENTRY_SIZE256]; | |||
664 | UINT32 VmType = SMI_HANDLER0; | |||
665 | ||||
666 | Qualification.UintN = VmReadN (VMCS_N_RO_EXIT_QUALIFICATION_INDEX0x6400); | |||
667 | ||||
668 | DEBUG ((EFI_D_ERROR, "%ld !!!EPTViolationHandler!!!\n", (UINTN)Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld !!!EPTViolationHandler!!!\n" , (UINTN)Index); } } while (((BOOLEAN)(0==1))); | |||
| ||||
669 | DEBUG ((EFI_D_ERROR, "%ld Qualification - %016lx\n", (UINTN) Index, (UINT64)Qualification.UintN))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld Qualification - %016lx\n" , (UINTN) Index, (UINT64)Qualification.UintN); } } while (((BOOLEAN )(0==1))); | |||
670 | DEBUG ((EFI_D_ERROR, "%ld GuestPhysicalAddress - %016lx\n", (UINTN) Index, VmRead64 (VMCS_64_RO_GUEST_PHYSICAL_ADDR_INDEX)))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld GuestPhysicalAddress - %016lx\n" , (UINTN) Index, VmRead64 (0x2400)); } } while (((BOOLEAN)(0== 1))); | |||
671 | ||||
672 | StmVmPeNmiExCount++; // make sure there is no smi processors waiting | |||
673 | ||||
674 | if (Qualification.EptViolation.GlaValid == 0) { | |||
675 | // | |||
676 | // 0=Linear address invalid. | |||
677 | // | |||
678 | DEBUG ((EFI_D_ERROR, "%ld SmmEPTViolationHandler - Linear address invalid\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld SmmEPTViolationHandler - Linear address invalid\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
679 | } else { | |||
680 | if (Qualification.EptViolation.Gpa == 0) { | |||
681 | // | |||
682 | // 1=Linear address valid but does not match provided physical address. EPT violation occurred while performing a guest page walk. | |||
683 | // 1) No-read EPT page encountered when trying to read from the guest IA32 page tables (e.g fetching a PML4, PDE, PTE). | |||
684 | // 2) No-write EPT page encountered when trying to write an A or D bit. | |||
685 | // | |||
686 | ||||
687 | DEBUG ((EFI_D_ERROR, "%ld SmmEPTViolationHandler - EPT violation occurred while performing a guest page walk\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld SmmEPTViolationHandler - EPT violation occurred while performing a guest page walk\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
688 | ||||
689 | } else { | |||
690 | // | |||
691 | // 3=Linear address valid and match provided physical address. This is the normal case. | |||
692 | // | |||
693 | Address = VmRead64 (VMCS_64_RO_GUEST_PHYSICAL_ADDR_INDEX0x2400); | |||
694 | MemDesc = GetStmResourceMem ( | |||
695 | mHostContextCommon.MleProtectedResource.Base, | |||
696 | Address, | |||
697 | (UINT32)(Qualification.UintN & 0x7) | |||
698 | ); | |||
699 | if (MemDesc != NULL((void *) 0)) { | |||
700 | DEBUG ((EFI_D_ERROR, "%ld SmmEPTViolationHandler - SMI Handler attempted to access MLE protected resource\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld SmmEPTViolationHandler - SMI Handler attempted to access MLE protected resource\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
701 | AddEventLogForResource (EvtHandledProtectionException, (STM_RSC *)MemDesc); | |||
702 | SmmExceptionHandler (Index); | |||
703 | CpuDeadLoop (); | |||
704 | } | |||
705 | ||||
706 | MemDesc = GetStmResourceMem ( | |||
707 | (STM_RSC *)(UINTN)mGuestContextCommonSmm[VmType].BiosHwResourceRequirementsPtr, | |||
708 | Address, | |||
709 | (UINT32)(Qualification.UintN & 0x7) | |||
710 | ); | |||
711 | if (MemDesc == NULL((void *) 0)) { | |||
712 | DEBUG((EFI_D_ERROR, "%ld SmmEPTViolationHandler - Add unclaimed MEM_RSC!\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld SmmEPTViolationHandler - Add unclaimed MEM_RSC!\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
713 | ZeroMem (&LocalMemDesc, sizeof(LocalMemDesc)); | |||
714 | LocalMemDesc.Hdr.RscType = MEM_RANGE1; | |||
715 | LocalMemDesc.Hdr.Length = sizeof(LocalMemDesc); | |||
716 | LocalMemDesc.Base = Address; | |||
717 | LocalMemDesc.Length = 1; | |||
718 | LocalMemDesc.RWXAttributes = (UINT8)(Qualification.UintN & 0x7); | |||
719 | AddEventLogForResource (EvtBiosAccessToUnclaimedResource, (STM_RSC *)&LocalMemDesc); | |||
720 | // BUGBUG: it should not happen? | |||
721 | // TBD: We need create EPT mapping here, if so? | |||
722 | ||||
723 | if(EPTSetPageAttributeRange ( | |||
724 | mGuestContextCommonSmm[SMI_HANDLER0].EptPointer.Uint64, | |||
725 | LocalMemDesc.Base, | |||
726 | LocalMemDesc.Length, | |||
727 | LocalMemDesc.Base, | |||
728 | ((LocalMemDesc.RWXAttributes & STM_RSC_MEM_R0x1) != 0) ? 0 : 1, | |||
729 | ((LocalMemDesc.RWXAttributes & STM_RSC_MEM_W0x2) != 0) ? 0 : 1, | |||
730 | ((LocalMemDesc.RWXAttributes & STM_RSC_MEM_X0x4) != 0) ? 0 : 1, | |||
731 | EptPageAttributeSet, | |||
732 | -1 | |||
733 | ) != 0) | |||
734 | { | |||
735 | DEBUG((EFI_D_ERROR, "%ld SmmEPTViolationHandler - STM ERROR unable to add resource to EPT map\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld SmmEPTViolationHandler - STM ERROR unable to add resource to EPT map\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
736 | CpuDeadLoop (); | |||
737 | } | |||
738 | } | |||
739 | ||||
740 | // Check PCIE MMIO. | |||
741 | if ((mHostContextCommon.PciExpressBaseAddress != 0) && | |||
742 | (Address >= mHostContextCommon.PciExpressBaseAddress) && | |||
743 | (Address < (mHostContextCommon.PciExpressBaseAddress + mHostContextCommon.PciExpressLength))) { | |||
744 | PciExpressAddress = Address - mHostContextCommon.PciExpressBaseAddress; | |||
745 | PciCfgDesc = GetStmResourcePci ( | |||
746 | mHostContextCommon.MleProtectedResource.Base, | |||
747 | BUS_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x0FF00000) >> 20), | |||
748 | DEVICE_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x000F8000) >> 15), | |||
749 | FUNCTION_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x00007000) >> 12), | |||
750 | REGISTER_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT16)((UINTN)(PciExpressAddress) & 0x00000FFF), | |||
751 | (UINT8)(Qualification.UintN & 0x3) | |||
752 | ); | |||
753 | if (PciCfgDesc != NULL((void *) 0)) { | |||
754 | DEBUG ((EFI_D_ERROR, "%ld EPT (PCIE) violation!\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld EPT (PCIE) violation!\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
755 | AddEventLogForResource (EvtHandledProtectionException, (STM_RSC *)PciCfgDesc); | |||
756 | SmmExceptionHandler (Index); | |||
757 | CpuDeadLoop (); | |||
758 | } | |||
759 | ||||
760 | PciCfgDesc = GetStmResourcePci ( | |||
761 | (STM_RSC *)(UINTN)mGuestContextCommonSmm[VmType].BiosHwResourceRequirementsPtr, | |||
762 | BUS_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x0FF00000) >> 20), | |||
763 | DEVICE_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x000F8000) >> 15), | |||
764 | FUNCTION_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x00007000) >> 12), | |||
765 | REGISTER_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT16)((UINTN)(PciExpressAddress) & 0x00000FFF), | |||
766 | (UINT8)(Qualification.UintN & 0x3) | |||
767 | ); | |||
768 | if (PciCfgDesc == NULL((void *) 0)) { | |||
769 | LocalPciCfgDescPtr = (STM_RSC_PCI_CFG_DESC *)LocalPciCfgDescBuf; | |||
770 | ZeroMem (LocalPciCfgDescBuf, sizeof(LocalPciCfgDescBuf)); | |||
771 | LocalPciCfgDescPtr->Hdr.RscType = PCI_CFG_RANGE5; | |||
772 | LocalPciCfgDescPtr->Hdr.Length = sizeof(STM_RSC_PCI_CFG_DESC); // BUGBUG: Just report this PCI device, it is hard to create PCI hierachy here. | |||
773 | LocalPciCfgDescPtr->RWAttributes = (UINT8)(Qualification.UintN & 0x3); | |||
774 | LocalPciCfgDescPtr->Base = REGISTER_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT16)((UINTN)(PciExpressAddress) & 0x00000FFF); | |||
775 | LocalPciCfgDescPtr->Length = 1; | |||
776 | LocalPciCfgDescPtr->OriginatingBusNumber = BUS_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x0FF00000) >> 20); | |||
777 | LocalPciCfgDescPtr->LastNodeIndex = 0; | |||
778 | LocalPciCfgDescPtr->PciDevicePath[0].Type = 1; | |||
779 | LocalPciCfgDescPtr->PciDevicePath[0].Subtype = 1; | |||
780 | LocalPciCfgDescPtr->PciDevicePath[0].Length = sizeof(STM_PCI_DEVICE_PATH_NODE); | |||
781 | LocalPciCfgDescPtr->PciDevicePath[0].PciFunction = FUNCTION_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x00007000) >> 12); | |||
782 | LocalPciCfgDescPtr->PciDevicePath[0].PciDevice = DEVICE_FROM_PCIE_ADDRESS(PciExpressAddress)(UINT8)(((UINTN)(PciExpressAddress) & 0x000F8000) >> 15); | |||
783 | AddEventLogForResource (EvtBiosAccessToUnclaimedResource, (STM_RSC *)LocalPciCfgDescPtr); | |||
784 | } | |||
785 | ||||
786 | } | |||
787 | } | |||
788 | } | |||
789 | ||||
790 | VmWriteN (VMCS_N_GUEST_RIP_INDEX0x681E, VmReadN(VMCS_N_GUEST_RIP_INDEX0x681E) + VmRead32(VMCS_32_RO_VMEXIT_INSTRUCTION_LENGTH_INDEX0x440C)); | |||
791 | ||||
792 | return ; | |||
793 | } | |||
794 | ||||
795 | /** | |||
796 | ||||
797 | This function is EPT misconfiguration handler for SMM. | |||
798 | ||||
799 | @param Index CPU index | |||
800 | ||||
801 | **/ | |||
802 | VOIDvoid | |||
803 | SmmEPTMisconfigurationHandler ( | |||
804 | IN UINT32 Index | |||
805 | ) | |||
806 | { | |||
807 | // | |||
808 | // Should not happen | |||
809 | // | |||
810 | DEBUG ((EFI_D_ERROR, "%ld !!!EPTMisconfigurationHandler!!!\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld !!!EPTMisconfigurationHandler!!!\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
811 | DumpVmcsAllField (Index); | |||
812 | ||||
813 | CpuDeadLoop (); | |||
814 | ||||
815 | return ; | |||
816 | } | |||
817 | ||||
818 | /** | |||
819 | ||||
820 | This function is INVEPT handler for SMM. | |||
821 | ||||
822 | @param Index CPU index | |||
823 | ||||
824 | **/ | |||
825 | VOIDvoid | |||
826 | SmmInvEPTHandler ( | |||
827 | IN UINT32 Index | |||
828 | ) | |||
829 | { | |||
830 | DEBUG ((EFI_D_ERROR, "%ld !!!InvEPTHandler!!!\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x80000000, "%ld !!!InvEPTHandler!!!\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
831 | DumpVmcsAllField (Index); | |||
832 | ||||
833 | CpuDeadLoop (); | |||
834 | ||||
835 | return ; | |||
836 | } | |||
837 | ||||
838 | /** | |||
839 | ||||
840 | This function sync Ia32PAE page table for EPT. | |||
841 | ||||
842 | @param Index CPU index | |||
843 | ||||
844 | **/ | |||
845 | VOIDvoid | |||
846 | Ia32PAESync ( | |||
847 | IN UINT32 Index | |||
848 | ) | |||
849 | { | |||
850 | UINTN Cr0; | |||
851 | UINTN Cr3; | |||
852 | UINTN Cr4; | |||
853 | UINT32 VmType; | |||
854 | ||||
855 | DEBUG ((EFI_D_INFO, "%ld Ia32PAESync\n", Index))do { if (DebugPrintEnabled ()) { DebugPrint (0x00000040, "%ld Ia32PAESync\n" , Index); } } while (((BOOLEAN)(0==1))); | |||
856 | ||||
857 | VmType = mHostContextCommon.HostContextPerCpu[Index].GuestVmType; // any VmType other than SMI_HANDLER is a PeVm | |||
858 | ||||
859 | if(SMI_HANDLER0 != VmType) | |||
860 | Index = 0; // PE VM index is always 0 | |||
861 | // | |||
862 | // If EPT is enabled and Guest is in IA32 PAE Mode, we need to write PDPTR. | |||
863 | // | |||
864 | Cr0 = VmReadN (VMCS_N_GUEST_CR0_INDEX0x6800); | |||
865 | Cr3 = VmReadN (VMCS_N_GUEST_CR3_INDEX0x6802); | |||
866 | Cr4 = VmReadN (VMCS_N_GUEST_CR4_INDEX0x6804); | |||
867 | if (((Cr4 & CR4_PAE(1u << 5)) != 0) && | |||
868 | ((Cr0 & CR0_PG(1u << 31)) != 0) && | |||
869 | ((mGuestContextCommonSmm[VmType].GuestContextPerCpu[Index].Efer & IA32_EFER_MSR_MLA(1u << 10)) == 0)) { | |||
870 | VmWrite64 (VMCS_64_GUEST_PDPTE0_INDEX0x280A, *(UINT64 *)(Cr3 + sizeof(UINT64) * 0)); | |||
871 | VmWrite64 (VMCS_64_GUEST_PDPTE1_INDEX0x280C, *(UINT64 *)(Cr3 + sizeof(UINT64) * 1)); | |||
872 | VmWrite64 (VMCS_64_GUEST_PDPTE2_INDEX0x280E, *(UINT64 *)(Cr3 + sizeof(UINT64) * 2)); | |||
873 | VmWrite64 (VMCS_64_GUEST_PDPTE3_INDEX0x2810, *(UINT64 *)(Cr3 + sizeof(UINT64) * 3)); | |||
874 | } | |||
875 | ||||
876 | return ; | |||
877 | } |