]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelSiliconPkg/IntelVTdDxe/TranslationTable.c
IntelSiliconPkg: Fix VS2015 NOOPT IA32 build failure in IntelVTdDxe
[mirror_edk2.git] / IntelSiliconPkg / IntelVTdDxe / TranslationTable.c
... / ...
CommitLineData
1/** @file\r
2\r
3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
4 This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution. The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php.\r
8\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12**/\r
13\r
14#include "DmaProtection.h"\r
15\r
16/**\r
17 Create extended context entry.\r
18\r
19 @param[in] VtdIndex The index of the VTd engine.\r
20\r
21 @retval EFI_SUCCESS The extended context entry is created.\r
22 @retval EFI_OUT_OF_RESOURCE No enough resource to create extended context entry.\r
23**/\r
24EFI_STATUS\r
25CreateExtContextEntry (\r
26 IN UINTN VtdIndex\r
27 );\r
28\r
29/**\r
30 Allocate zero pages.\r
31\r
32 @param[in] Pages the number of pages.\r
33\r
34 @return the page address.\r
35 @retval NULL No resource to allocate pages.\r
36**/\r
37VOID *\r
38EFIAPI\r
39AllocateZeroPages (\r
40 IN UINTN Pages\r
41 )\r
42{\r
43 VOID *Addr;\r
44\r
45 Addr = AllocatePages (Pages);\r
46 if (Addr == NULL) {\r
47 return NULL;\r
48 }\r
49 ZeroMem (Addr, EFI_PAGES_TO_SIZE(Pages));\r
50 return Addr;\r
51}\r
52\r
53/**\r
54 Set second level paging entry attribute based upon IoMmuAccess.\r
55\r
56 @param[in] PtEntry The paging entry.\r
57 @param[in] IoMmuAccess The IOMMU access.\r
58**/\r
59VOID\r
60SetSecondLevelPagingEntryAttribute (\r
61 IN VTD_SECOND_LEVEL_PAGING_ENTRY *PtEntry,\r
62 IN UINT64 IoMmuAccess\r
63 )\r
64{\r
65 PtEntry->Bits.Read = ((IoMmuAccess & EDKII_IOMMU_ACCESS_READ) != 0);\r
66 PtEntry->Bits.Write = ((IoMmuAccess & EDKII_IOMMU_ACCESS_WRITE) != 0);\r
67}\r
68\r
69/**\r
70 Create context entry.\r
71\r
72 @param[in] VtdIndex The index of the VTd engine.\r
73\r
74 @retval EFI_SUCCESS The context entry is created.\r
75 @retval EFI_OUT_OF_RESOURCE No enough resource to create context entry.\r
76**/\r
77EFI_STATUS\r
78CreateContextEntry (\r
79 IN UINTN VtdIndex\r
80 )\r
81{\r
82 UINTN Index;\r
83 VOID *Buffer;\r
84 UINTN RootPages;\r
85 UINTN ContextPages;\r
86 VTD_ROOT_ENTRY *RootEntry;\r
87 VTD_CONTEXT_ENTRY *ContextEntryTable;\r
88 VTD_CONTEXT_ENTRY *ContextEntry;\r
89 VTD_SOURCE_ID *PciDescriptor;\r
90 VTD_SOURCE_ID SourceId;\r
91 UINTN MaxBusNumber;\r
92 UINTN EntryTablePages;\r
93\r
94 MaxBusNumber = 0;\r
95 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
96 PciDescriptor = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index];\r
97 if (PciDescriptor->Bits.Bus > MaxBusNumber) {\r
98 MaxBusNumber = PciDescriptor->Bits.Bus;\r
99 }\r
100 }\r
101 DEBUG ((DEBUG_INFO," MaxBusNumber - 0x%x\n", MaxBusNumber));\r
102\r
103 RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);\r
104 ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);\r
105 EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);\r
106 Buffer = AllocateZeroPages (EntryTablePages);\r
107 if (Buffer == NULL) {\r
108 DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));\r
109 return EFI_OUT_OF_RESOURCES;\r
110 }\r
111 mVtdUnitInformation[VtdIndex].RootEntryTable = (VTD_ROOT_ENTRY *)Buffer;\r
112 Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);\r
113\r
114 for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {\r
115 PciDescriptor = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index];\r
116\r
117 SourceId.Bits.Bus = PciDescriptor->Bits.Bus;\r
118 SourceId.Bits.Device = PciDescriptor->Bits.Device;\r
119 SourceId.Bits.Function = PciDescriptor->Bits.Function;\r
120\r
121 RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];\r
122 if (RootEntry->Bits.Present == 0) {\r
123 RootEntry->Bits.ContextTablePointerLo = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12);\r
124 RootEntry->Bits.ContextTablePointerHi = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 32);\r
125 RootEntry->Bits.Present = 1;\r
126 Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);\r
127 }\r
128\r
129 ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;\r
130 ContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];\r
131 ContextEntry->Bits.TranslationType = 0;\r
132 ContextEntry->Bits.FaultProcessingDisable = 0;\r
133 ContextEntry->Bits.Present = 0;\r
134\r
135 DEBUG ((DEBUG_INFO,"Source: S%04x B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
136\r
137 switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {\r
138 case BIT1:\r
139 ContextEntry->Bits.AddressWidth = 0x1;\r
140 break;\r
141 case BIT2:\r
142 ContextEntry->Bits.AddressWidth = 0x2;\r
143 break;\r
144 }\r
145 }\r
146\r
147 return EFI_SUCCESS;\r
148}\r
149\r
150/**\r
151 Create second level paging entry table.\r
152\r
153 @param[in] VtdIndex The index of the VTd engine.\r
154 @param[in] SecondLevelPagingEntry The second level paging entry.\r
155 @param[in] MemoryBase The base of the memory.\r
156 @param[in] MemoryLimit The limit of the memory.\r
157 @param[in] IoMmuAccess The IOMMU access.\r
158\r
159 @return The second level paging entry.\r
160**/\r
161VTD_SECOND_LEVEL_PAGING_ENTRY *\r
162CreateSecondLevelPagingEntryTable (\r
163 IN UINTN VtdIndex,\r
164 IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
165 IN UINT64 MemoryBase,\r
166 IN UINT64 MemoryLimit,\r
167 IN UINT64 IoMmuAccess\r
168 )\r
169{\r
170 UINTN Index4;\r
171 UINTN Index3;\r
172 UINTN Index2;\r
173 UINTN Lvl4Start;\r
174 UINTN Lvl4End;\r
175 UINTN Lvl3Start;\r
176 UINTN Lvl3End;\r
177 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;\r
178 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;\r
179 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;\r
180 UINT64 BaseAddress;\r
181 UINT64 EndAddress;\r
182\r
183 if (MemoryLimit == 0) {\r
184 return EFI_SUCCESS;\r
185 }\r
186\r
187 BaseAddress = ALIGN_VALUE_LOW(MemoryBase, SIZE_2MB);\r
188 EndAddress = ALIGN_VALUE_UP(MemoryLimit, SIZE_2MB);\r
189 DEBUG ((DEBUG_INFO,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%016lx, EndAddress - 0x%016lx\n", BaseAddress, EndAddress));\r
190\r
191 if (SecondLevelPagingEntry == NULL) {\r
192 SecondLevelPagingEntry = AllocateZeroPages (1);\r
193 if (SecondLevelPagingEntry == NULL) {\r
194 DEBUG ((DEBUG_ERROR,"Could not Alloc LVL4 PT. \n"));\r
195 return NULL;\r
196 }\r
197 }\r
198\r
199 //\r
200 // If no access is needed, just create not present entry.\r
201 //\r
202 if (IoMmuAccess == 0) {\r
203 return SecondLevelPagingEntry;\r
204 }\r
205\r
206 Lvl4Start = RShiftU64 (BaseAddress, 39) & 0x1FF;\r
207 Lvl4End = RShiftU64 (EndAddress - 1, 39) & 0x1FF;\r
208\r
209 DEBUG ((DEBUG_INFO," Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start, Lvl4End));\r
210\r
211 Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;\r
212 for (Index4 = Lvl4Start; Index4 <= Lvl4End; Index4++) {\r
213 if (Lvl4PtEntry[Index4].Uint64 == 0) {\r
214 Lvl4PtEntry[Index4].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);\r
215 if (Lvl4PtEntry[Index4].Uint64 == 0) {\r
216 DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));\r
217 ASSERT(FALSE);\r
218 return NULL;\r
219 }\r
220 SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
221 }\r
222\r
223 Lvl3Start = RShiftU64 (BaseAddress, 30) & 0x1FF;\r
224 if (ALIGN_VALUE_LOW(BaseAddress + SIZE_1GB, SIZE_1GB) <= EndAddress) {\r
225 Lvl3End = SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY);\r
226 } else {\r
227 Lvl3End = RShiftU64 (EndAddress - 1, 30) & 0x1FF;\r
228 }\r
229 DEBUG ((DEBUG_INFO," Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n", Index4, Lvl3Start, Lvl3End));\r
230\r
231 Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi);\r
232 for (Index3 = Lvl3Start; Index3 <= Lvl3End; Index3++) {\r
233 if (Lvl3PtEntry[Index3].Uint64 == 0) {\r
234 Lvl3PtEntry[Index3].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);\r
235 if (Lvl3PtEntry[Index3].Uint64 == 0) {\r
236 DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));\r
237 ASSERT(FALSE);\r
238 return NULL;\r
239 }\r
240 SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
241 }\r
242\r
243 Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi);\r
244 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {\r
245 Lvl2PtEntry[Index2].Uint64 = BaseAddress;\r
246 SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry[Index2], IoMmuAccess);\r
247 Lvl2PtEntry[Index2].Bits.PageSize = 1;\r
248 BaseAddress += SIZE_2MB;\r
249 if (BaseAddress >= MemoryLimit) {\r
250 goto Done;\r
251 }\r
252 }\r
253 }\r
254 }\r
255\r
256Done:\r
257 return SecondLevelPagingEntry;\r
258}\r
259\r
260/**\r
261 Create second level paging entry.\r
262\r
263 @param[in] VtdIndex The index of the VTd engine.\r
264 @param[in] IoMmuAccess The IOMMU access.\r
265\r
266 @return The second level paging entry.\r
267**/\r
268VTD_SECOND_LEVEL_PAGING_ENTRY *\r
269CreateSecondLevelPagingEntry (\r
270 IN UINTN VtdIndex,\r
271 IN UINT64 IoMmuAccess\r
272 )\r
273{\r
274 VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
275\r
276 SecondLevelPagingEntry = NULL;\r
277 SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, 0, mBelow4GMemoryLimit, IoMmuAccess);\r
278 if (SecondLevelPagingEntry == NULL) {\r
279 return NULL;\r
280 }\r
281 SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, SIZE_4GB, mAbove4GMemoryLimit, IoMmuAccess);\r
282 if (SecondLevelPagingEntry == NULL) {\r
283 return NULL;\r
284 }\r
285\r
286 return SecondLevelPagingEntry;\r
287}\r
288\r
289/**\r
290 Setup VTd translation table.\r
291\r
292 @retval EFI_SUCCESS Setup translation table successfully.\r
293 @retval EFI_OUT_OF_RESOURCE Setup translation table fail.\r
294**/\r
295EFI_STATUS\r
296SetupTranslationTable (\r
297 VOID\r
298 )\r
299{\r
300 EFI_STATUS Status;\r
301 UINTN Index;\r
302\r
303 for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
304 DEBUG((DEBUG_INFO, "CreateContextEntry - %d\n", Index));\r
305 if (mVtdUnitInformation[Index].ECapReg.Bits.ECS) {\r
306 Status = CreateExtContextEntry (Index);\r
307 } else {\r
308 Status = CreateContextEntry (Index);\r
309 }\r
310 if (EFI_ERROR (Status)) {\r
311 return Status;\r
312 }\r
313 }\r
314\r
315 return EFI_SUCCESS;\r
316}\r
317\r
318/**\r
319 Dump DMAR context entry table.\r
320\r
321 @param[in] RootEntry DMAR root entry.\r
322**/\r
323VOID\r
324DumpDmarContextEntryTable (\r
325 IN VTD_ROOT_ENTRY *RootEntry\r
326 )\r
327{\r
328 UINTN Index;\r
329 UINTN Index2;\r
330 VTD_CONTEXT_ENTRY *ContextEntry;\r
331\r
332 DEBUG ((DEBUG_INFO,"=========================\n"));\r
333 DEBUG ((DEBUG_INFO,"DMAR Context Entry Table:\n"));\r
334\r
335 DEBUG ((DEBUG_INFO,"RootEntry Address - 0x%x\n", RootEntry));\r
336\r
337 for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {\r
338 if ((RootEntry[Index].Uint128.Uint64Lo != 0) || (RootEntry[Index].Uint128.Uint64Hi != 0)) {\r
339 DEBUG ((DEBUG_INFO," RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",\r
340 Index, Index, RootEntry[Index].Uint128.Uint64Hi, RootEntry[Index].Uint128.Uint64Lo));\r
341 }\r
342 if (RootEntry[Index].Bits.Present == 0) {\r
343 continue;\r
344 }\r
345 ContextEntry = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry[Index].Bits.ContextTablePointerLo, RootEntry[Index].Bits.ContextTablePointerHi);\r
346 for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER; Index2++) {\r
347 if ((ContextEntry[Index2].Uint128.Uint64Lo != 0) || (ContextEntry[Index2].Uint128.Uint64Hi != 0)) {\r
348 DEBUG ((DEBUG_INFO," ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n",\r
349 Index2, Index2 >> 3, Index2 & 0x7, ContextEntry[Index2].Uint128.Uint64Hi, ContextEntry[Index2].Uint128.Uint64Lo));\r
350 }\r
351 if (ContextEntry[Index2].Bits.Present == 0) {\r
352 continue;\r
353 }\r
354 DumpSecondLevelPagingEntry ((VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerLo, ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerHi));\r
355 }\r
356 }\r
357 DEBUG ((DEBUG_INFO,"=========================\n"));\r
358}\r
359\r
360/**\r
361 Dump DMAR second level paging entry.\r
362\r
363 @param[in] SecondLevelPagingEntry The second level paging entry.\r
364**/\r
365VOID\r
366DumpSecondLevelPagingEntry (\r
367 IN VOID *SecondLevelPagingEntry\r
368 )\r
369{\r
370 UINTN Index4;\r
371 UINTN Index3;\r
372 UINTN Index2;\r
373 UINTN Index1;\r
374 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry;\r
375 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry;\r
376 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry;\r
377 VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl1PtEntry;\r
378\r
379 DEBUG ((DEBUG_VERBOSE,"================\n"));\r
380 DEBUG ((DEBUG_VERBOSE,"DMAR Second Level Page Table:\n"));\r
381\r
382 DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));\r
383 Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;\r
384 for (Index4 = 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index4++) {\r
385 if (Lvl4PtEntry[Index4].Uint64 != 0) {\r
386 DEBUG ((DEBUG_VERBOSE," Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4, Lvl4PtEntry[Index4].Uint64));\r
387 }\r
388 if (Lvl4PtEntry[Index4].Uint64 == 0) {\r
389 continue;\r
390 }\r
391 Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi);\r
392 for (Index3 = 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index3++) {\r
393 if (Lvl3PtEntry[Index3].Uint64 != 0) {\r
394 DEBUG ((DEBUG_VERBOSE," Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3, Lvl3PtEntry[Index3].Uint64));\r
395 }\r
396 if (Lvl3PtEntry[Index3].Uint64 == 0) {\r
397 continue;\r
398 }\r
399\r
400 Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi);\r
401 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {\r
402 if (Lvl2PtEntry[Index2].Uint64 != 0) {\r
403 DEBUG ((DEBUG_VERBOSE," Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2, Lvl2PtEntry[Index2].Uint64));\r
404 }\r
405 if (Lvl2PtEntry[Index2].Uint64 == 0) {\r
406 continue;\r
407 }\r
408 if (Lvl2PtEntry[Index2].Bits.PageSize == 0) {\r
409 Lvl1PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl2PtEntry[Index2].Bits.AddressLo, Lvl2PtEntry[Index2].Bits.AddressHi);\r
410 for (Index1 = 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index1++) {\r
411 if (Lvl1PtEntry[Index1].Uint64 != 0) {\r
412 DEBUG ((DEBUG_VERBOSE," Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1, Lvl1PtEntry[Index1].Uint64));\r
413 }\r
414 }\r
415 }\r
416 }\r
417 }\r
418 }\r
419 DEBUG ((DEBUG_VERBOSE,"================\n"));\r
420}\r
421\r
422/**\r
423 Invalid page entry.\r
424\r
425 @param VtdIndex The VTd engine index.\r
426**/\r
427VOID\r
428InvalidatePageEntry (\r
429 IN UINTN VtdIndex\r
430 )\r
431{\r
432 if (mVtdUnitInformation[VtdIndex].HasDirtyPages) {\r
433 InvalidateVtdIOTLBGlobal (VtdIndex);\r
434 }\r
435 mVtdUnitInformation[VtdIndex].HasDirtyPages = FALSE;\r
436}\r
437\r
438#define VTD_PG_R BIT0\r
439#define VTD_PG_W BIT1\r
440#define VTD_PG_X BIT2\r
441#define VTD_PG_EMT (BIT3 | BIT4 | BIT5)\r
442#define VTD_PG_TM (BIT62)\r
443\r
444#define VTD_PG_PS BIT7\r
445\r
446#define PAGE_PROGATE_BITS (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VTD_PG_R)\r
447\r
448#define PAGING_4K_MASK 0xFFF\r
449#define PAGING_2M_MASK 0x1FFFFF\r
450#define PAGING_1G_MASK 0x3FFFFFFF\r
451\r
452#define PAGING_VTD_INDEX_MASK 0x1FF\r
453\r
454#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull\r
455#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull\r
456#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull\r
457\r
458typedef enum {\r
459 PageNone,\r
460 Page4K,\r
461 Page2M,\r
462 Page1G,\r
463} PAGE_ATTRIBUTE;\r
464\r
465typedef struct {\r
466 PAGE_ATTRIBUTE Attribute;\r
467 UINT64 Length;\r
468 UINT64 AddressMask;\r
469} PAGE_ATTRIBUTE_TABLE;\r
470\r
471PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {\r
472 {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},\r
473 {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},\r
474 {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},\r
475};\r
476\r
477/**\r
478 Return length according to page attributes.\r
479\r
480 @param[in] PageAttributes The page attribute of the page entry.\r
481\r
482 @return The length of page entry.\r
483**/\r
484UINTN\r
485PageAttributeToLength (\r
486 IN PAGE_ATTRIBUTE PageAttribute\r
487 )\r
488{\r
489 UINTN Index;\r
490 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {\r
491 if (PageAttribute == mPageAttributeTable[Index].Attribute) {\r
492 return (UINTN)mPageAttributeTable[Index].Length;\r
493 }\r
494 }\r
495 return 0;\r
496}\r
497\r
498/**\r
499 Return page table entry to match the address.\r
500\r
501 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.\r
502 @param[in] Address The address to be checked.\r
503 @param[out] PageAttributes The page attribute of the page entry.\r
504\r
505 @return The page entry.\r
506**/\r
507VOID *\r
508GetSecondLevelPageTableEntry (\r
509 IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
510 IN PHYSICAL_ADDRESS Address,\r
511 OUT PAGE_ATTRIBUTE *PageAttribute\r
512 )\r
513{\r
514 UINTN Index1;\r
515 UINTN Index2;\r
516 UINTN Index3;\r
517 UINTN Index4;\r
518 UINT64 *L1PageTable;\r
519 UINT64 *L2PageTable;\r
520 UINT64 *L3PageTable;\r
521 UINT64 *L4PageTable;\r
522\r
523 Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_VTD_INDEX_MASK;\r
524 Index3 = ((UINTN)Address >> 30) & PAGING_VTD_INDEX_MASK;\r
525 Index2 = ((UINTN)Address >> 21) & PAGING_VTD_INDEX_MASK;\r
526 Index1 = ((UINTN)Address >> 12) & PAGING_VTD_INDEX_MASK;\r
527\r
528 L4PageTable = (UINT64 *)SecondLevelPagingEntry;\r
529 if (L4PageTable[Index4] == 0) {\r
530 L4PageTable[Index4] = (UINT64)(UINTN)AllocateZeroPages (1);\r
531 if (L4PageTable[Index4] == 0) {\r
532 DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));\r
533 ASSERT(FALSE);\r
534 *PageAttribute = PageNone;\r
535 return NULL;\r
536 }\r
537 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
538 }\r
539\r
540 L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);\r
541 if (L3PageTable[Index3] == 0) {\r
542 L3PageTable[Index3] = (UINT64)(UINTN)AllocateZeroPages (1);\r
543 if (L3PageTable[Index3] == 0) {\r
544 DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));\r
545 ASSERT(FALSE);\r
546 *PageAttribute = PageNone;\r
547 return NULL;\r
548 }\r
549 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
550 }\r
551 if ((L3PageTable[Index3] & VTD_PG_PS) != 0) {\r
552 // 1G\r
553 *PageAttribute = Page1G;\r
554 return &L3PageTable[Index3];\r
555 }\r
556\r
557 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);\r
558 if (L2PageTable[Index2] == 0) {\r
559 L2PageTable[Index2] = Address & PAGING_2M_ADDRESS_MASK_64;\r
560 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L2PageTable[Index2], 0);\r
561 L2PageTable[Index2] |= VTD_PG_PS;\r
562 }\r
563 if ((L2PageTable[Index2] & VTD_PG_PS) != 0) {\r
564 // 2M\r
565 *PageAttribute = Page2M;\r
566 return &L2PageTable[Index2];\r
567 }\r
568\r
569 // 4k\r
570 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);\r
571 if ((L1PageTable[Index1] == 0) && (Address != 0)) {\r
572 *PageAttribute = PageNone;\r
573 return NULL;\r
574 }\r
575 *PageAttribute = Page4K;\r
576 return &L1PageTable[Index1];\r
577}\r
578\r
579/**\r
580 Modify memory attributes of page entry.\r
581\r
582 @param[in] PageEntry The page entry.\r
583 @param[in] IoMmuAccess The IOMMU access.\r
584 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.\r
585**/\r
586VOID\r
587ConvertSecondLevelPageEntryAttribute (\r
588 IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,\r
589 IN UINT64 IoMmuAccess,\r
590 OUT BOOLEAN *IsModified\r
591 )\r
592{\r
593 UINT64 CurrentPageEntry;\r
594 UINT64 NewPageEntry;\r
595\r
596 CurrentPageEntry = PageEntry->Uint64;\r
597 SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);\r
598 NewPageEntry = PageEntry->Uint64;\r
599 if (CurrentPageEntry != NewPageEntry) {\r
600 *IsModified = TRUE;\r
601 DEBUG ((DEBUG_VERBOSE, "ConvertSecondLevelPageEntryAttribute 0x%lx", CurrentPageEntry));\r
602 DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
603 } else {\r
604 *IsModified = FALSE;\r
605 }\r
606}\r
607\r
608/**\r
609 This function returns if there is need to split page entry.\r
610\r
611 @param[in] BaseAddress The base address to be checked.\r
612 @param[in] Length The length to be checked.\r
613 @param[in] PageAttribute The page attribute of the page entry.\r
614\r
615 @retval SplitAttributes on if there is need to split page entry.\r
616**/\r
617PAGE_ATTRIBUTE\r
618NeedSplitPage (\r
619 IN PHYSICAL_ADDRESS BaseAddress,\r
620 IN UINT64 Length,\r
621 IN PAGE_ATTRIBUTE PageAttribute\r
622 )\r
623{\r
624 UINT64 PageEntryLength;\r
625\r
626 PageEntryLength = PageAttributeToLength (PageAttribute);\r
627\r
628 if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {\r
629 return PageNone;\r
630 }\r
631\r
632 if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {\r
633 return Page4K;\r
634 }\r
635\r
636 return Page2M;\r
637}\r
638\r
639/**\r
640 This function splits one page entry to small page entries.\r
641\r
642 @param[in] PageEntry The page entry to be splitted.\r
643 @param[in] PageAttribute The page attribute of the page entry.\r
644 @param[in] SplitAttribute How to split the page entry.\r
645\r
646 @retval RETURN_SUCCESS The page entry is splitted.\r
647 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.\r
648 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.\r
649**/\r
650RETURN_STATUS\r
651SplitSecondLevelPage (\r
652 IN VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry,\r
653 IN PAGE_ATTRIBUTE PageAttribute,\r
654 IN PAGE_ATTRIBUTE SplitAttribute\r
655 )\r
656{\r
657 UINT64 BaseAddress;\r
658 UINT64 *NewPageEntry;\r
659 UINTN Index;\r
660\r
661 ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);\r
662\r
663 if (PageAttribute == Page2M) {\r
664 //\r
665 // Split 2M to 4K\r
666 //\r
667 ASSERT (SplitAttribute == Page4K);\r
668 if (SplitAttribute == Page4K) {\r
669 NewPageEntry = AllocateZeroPages (1);\r
670 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
671 if (NewPageEntry == NULL) {\r
672 return RETURN_OUT_OF_RESOURCES;\r
673 }\r
674 BaseAddress = PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_64;\r
675 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
676 NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | (PageEntry->Uint64 & PAGE_PROGATE_BITS);\r
677 }\r
678 PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;\r
679 SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
680 return RETURN_SUCCESS;\r
681 } else {\r
682 return RETURN_UNSUPPORTED;\r
683 }\r
684 } else if (PageAttribute == Page1G) {\r
685 //\r
686 // Split 1G to 2M\r
687 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.\r
688 //\r
689 ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);\r
690 if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {\r
691 NewPageEntry = AllocateZeroPages (1);\r
692 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));\r
693 if (NewPageEntry == NULL) {\r
694 return RETURN_OUT_OF_RESOURCES;\r
695 }\r
696 BaseAddress = PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_64;\r
697 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {\r
698 NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | VTD_PG_PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);\r
699 }\r
700 PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;\r
701 SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
702 return RETURN_SUCCESS;\r
703 } else {\r
704 return RETURN_UNSUPPORTED;\r
705 }\r
706 } else {\r
707 return RETURN_UNSUPPORTED;\r
708 }\r
709}\r
710\r
711/**\r
712 Set VTd attribute for a system memory on second level page entry\r
713\r
714 @param[in] VtdIndex The index used to identify a VTd engine.\r
715 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.\r
716 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.\r
717 @param[in] Length The length of device memory address to be used as the DMA memory.\r
718 @param[in] IoMmuAccess The IOMMU access.\r
719\r
720 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
721 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
722 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
723 @retval EFI_INVALID_PARAMETER Length is 0.\r
724 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
725 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
726 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.\r
727 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
728 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
729**/\r
730EFI_STATUS\r
731SetSecondLevelPagingAttribute (\r
732 IN UINTN VtdIndex,\r
733 IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
734 IN UINT64 BaseAddress,\r
735 IN UINT64 Length,\r
736 IN UINT64 IoMmuAccess\r
737 )\r
738{\r
739 VTD_SECOND_LEVEL_PAGING_ENTRY *PageEntry;\r
740 PAGE_ATTRIBUTE PageAttribute;\r
741 UINTN PageEntryLength;\r
742 PAGE_ATTRIBUTE SplitAttribute;\r
743 EFI_STATUS Status;\r
744 BOOLEAN IsEntryModified;\r
745\r
746 DEBUG ((DEBUG_VERBOSE,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x%016lx : %x) \n", VtdIndex, BaseAddress, Length, IoMmuAccess));\r
747 DEBUG ((DEBUG_VERBOSE," SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));\r
748\r
749 if (BaseAddress != ALIGN_VALUE(BaseAddress, SIZE_4KB)) {\r
750 DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));\r
751 return EFI_UNSUPPORTED;\r
752 }\r
753 if (Length != ALIGN_VALUE(Length, SIZE_4KB)) {\r
754 DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));\r
755 return EFI_UNSUPPORTED;\r
756 }\r
757\r
758 while (Length != 0) {\r
759 PageEntry = GetSecondLevelPageTableEntry (SecondLevelPagingEntry, BaseAddress, &PageAttribute);\r
760 if (PageEntry == NULL) {\r
761 DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));\r
762 return RETURN_UNSUPPORTED;\r
763 }\r
764 PageEntryLength = PageAttributeToLength (PageAttribute);\r
765 SplitAttribute = NeedSplitPage (BaseAddress, Length, PageAttribute);\r
766 if (SplitAttribute == PageNone) {\r
767 ConvertSecondLevelPageEntryAttribute (PageEntry, IoMmuAccess, &IsEntryModified);\r
768 if (IsEntryModified) {\r
769 mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;\r
770 }\r
771 //\r
772 // Convert success, move to next\r
773 //\r
774 BaseAddress += PageEntryLength;\r
775 Length -= PageEntryLength;\r
776 } else {\r
777 Status = SplitSecondLevelPage (PageEntry, PageAttribute, SplitAttribute);\r
778 if (RETURN_ERROR (Status)) {\r
779 DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));\r
780 return RETURN_UNSUPPORTED;\r
781 }\r
782 mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;\r
783 //\r
784 // Just split current page\r
785 // Convert success in next around\r
786 //\r
787 }\r
788 }\r
789\r
790 InvalidatePageEntry (VtdIndex);\r
791\r
792 return EFI_SUCCESS;\r
793}\r
794\r
795/**\r
796 Set VTd attribute for a system memory.\r
797\r
798 @param[in] VtdIndex The index used to identify a VTd engine.\r
799 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.\r
800 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.\r
801 @param[in] Length The length of device memory address to be used as the DMA memory.\r
802 @param[in] IoMmuAccess The IOMMU access.\r
803\r
804 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
805 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
806 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
807 @retval EFI_INVALID_PARAMETER Length is 0.\r
808 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
809 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
810 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.\r
811 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
812 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
813**/\r
814EFI_STATUS\r
815SetPageAttribute (\r
816 IN UINTN VtdIndex,\r
817 IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,\r
818 IN UINT64 BaseAddress,\r
819 IN UINT64 Length,\r
820 IN UINT64 IoMmuAccess\r
821 )\r
822{\r
823 EFI_STATUS Status;\r
824 Status = EFI_NOT_FOUND;\r
825 if (SecondLevelPagingEntry != NULL) {\r
826 Status = SetSecondLevelPagingAttribute (VtdIndex, SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);\r
827 }\r
828 return Status;\r
829}\r
830\r
831/**\r
832 Set VTd attribute for a system memory.\r
833\r
834 @param[in] Segment The Segment used to identify a VTd engine.\r
835 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
836 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.\r
837 @param[in] Length The length of device memory address to be used as the DMA memory.\r
838 @param[in] IoMmuAccess The IOMMU access.\r
839\r
840 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
841 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
842 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
843 @retval EFI_INVALID_PARAMETER Length is 0.\r
844 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
845 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
846 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.\r
847 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
848 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
849**/\r
850EFI_STATUS\r
851SetAccessAttribute (\r
852 IN UINT16 Segment,\r
853 IN VTD_SOURCE_ID SourceId,\r
854 IN UINT64 BaseAddress,\r
855 IN UINT64 Length,\r
856 IN UINT64 IoMmuAccess\r
857 )\r
858{\r
859 UINTN VtdIndex;\r
860 EFI_STATUS Status;\r
861 VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;\r
862 VTD_CONTEXT_ENTRY *ContextEntry;\r
863 VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
864 UINT64 Pt;\r
865\r
866 SecondLevelPagingEntry = NULL;\r
867\r
868 DEBUG ((DEBUG_INFO,"SetAccessAttribute (S%04x B%02x D%02x F%02x) (0x%016lx - 0x%08x, %x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, BaseAddress, (UINTN)Length, IoMmuAccess));\r
869\r
870 VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);\r
871 if (VtdIndex == (UINTN)-1) {\r
872 DEBUG ((DEBUG_ERROR,"SetAccessAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
873 return EFI_DEVICE_ERROR;\r
874 }\r
875\r
876 if (ExtContextEntry != NULL) {\r
877 if (ExtContextEntry->Bits.Present == 0) {\r
878 SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);\r
879 DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
880 Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);\r
881\r
882 ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
883 ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
884 ExtContextEntry->Bits.DomainIdentifier = (UINT16) GetPciDescriptor (VtdIndex, Segment, SourceId);\r
885 ExtContextEntry->Bits.Present = 1;\r
886 DumpDmarExtContextEntryTable (mVtdUnitInformation[VtdIndex].ExtRootEntryTable);\r
887 } else {\r
888 SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi);\r
889 DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
890 }\r
891 } else if (ContextEntry != NULL) {\r
892 if (ContextEntry->Bits.Present == 0) {\r
893 SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);\r
894 DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
895 Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);\r
896\r
897 ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
898 ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
899 ContextEntry->Bits.DomainIdentifier = (UINT16) GetPciDescriptor (VtdIndex, Segment, SourceId);\r
900 ContextEntry->Bits.Present = 1;\r
901 DumpDmarContextEntryTable (mVtdUnitInformation[VtdIndex].RootEntryTable);\r
902 } else {\r
903 SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry->Bits.SecondLevelPageTranslationPointerLo, ContextEntry->Bits.SecondLevelPageTranslationPointerHi);\r
904 DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
905 }\r
906 }\r
907\r
908 //\r
909 // Do not update FixedSecondLevelPagingEntry\r
910 //\r
911 if (SecondLevelPagingEntry != mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry) {\r
912 Status = SetPageAttribute (\r
913 VtdIndex,\r
914 SecondLevelPagingEntry,\r
915 BaseAddress,\r
916 Length,\r
917 IoMmuAccess\r
918 );\r
919 if (EFI_ERROR (Status)) {\r
920 DEBUG ((DEBUG_ERROR,"SetPageAttribute - %r\n", Status));\r
921 return Status;\r
922 }\r
923 }\r
924\r
925 return EFI_SUCCESS;\r
926}\r
927\r
928/**\r
929 Always enable the VTd page attribute for the device.\r
930\r
931 @param[in] Segment The Segment used to identify a VTd engine.\r
932 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
933\r
934 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.\r
935**/\r
936EFI_STATUS\r
937AlwaysEnablePageAttribute (\r
938 IN UINT16 Segment,\r
939 IN VTD_SOURCE_ID SourceId\r
940 )\r
941{\r
942 UINTN VtdIndex;\r
943 VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;\r
944 VTD_CONTEXT_ENTRY *ContextEntry;\r
945 VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;\r
946 UINT64 Pt;\r
947\r
948 DEBUG ((DEBUG_INFO,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
949\r
950 VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);\r
951 if (VtdIndex == (UINTN)-1) {\r
952 DEBUG ((DEBUG_ERROR,"AlwaysEnablePageAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));\r
953 return EFI_DEVICE_ERROR;\r
954 }\r
955\r
956 if (mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry == 0) {\r
957 DEBUG((DEBUG_INFO, "CreateSecondLevelPagingEntry - %d\n", VtdIndex));\r
958 mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);\r
959 }\r
960\r
961 SecondLevelPagingEntry = mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry;\r
962 Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);\r
963 if (ExtContextEntry != NULL) {\r
964 ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
965 ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
966 ExtContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);\r
967 ExtContextEntry->Bits.Present = 1;\r
968 } else if (ContextEntry != NULL) {\r
969 ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;\r
970 ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);\r
971 ContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);\r
972 ContextEntry->Bits.Present = 1;\r
973 }\r
974\r
975 return EFI_SUCCESS;\r
976}\r