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