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