3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "DmaProtection.h"
11 Create extended context entry.
13 @param[in] VtdIndex The index of the VTd engine.
15 @retval EFI_SUCCESS The extended context entry is created.
16 @retval EFI_OUT_OF_RESOURCE No enough resource to create extended context entry.
19 CreateExtContextEntry (
26 @param[in] Pages the number of pages.
28 @return the page address.
29 @retval NULL No resource to allocate pages.
39 Addr
= AllocatePages (Pages
);
43 ZeroMem (Addr
, EFI_PAGES_TO_SIZE(Pages
));
48 Set second level paging entry attribute based upon IoMmuAccess.
50 @param[in] PtEntry The paging entry.
51 @param[in] IoMmuAccess The IOMMU access.
54 SetSecondLevelPagingEntryAttribute (
55 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*PtEntry
,
59 PtEntry
->Bits
.Read
= ((IoMmuAccess
& EDKII_IOMMU_ACCESS_READ
) != 0);
60 PtEntry
->Bits
.Write
= ((IoMmuAccess
& EDKII_IOMMU_ACCESS_WRITE
) != 0);
66 @param[in] VtdIndex The index of the VTd engine.
68 @retval EFI_SUCCESS The context entry is created.
69 @retval EFI_OUT_OF_RESOURCE No enough resource to create context entry.
80 VTD_ROOT_ENTRY
*RootEntry
;
81 VTD_CONTEXT_ENTRY
*ContextEntryTable
;
82 VTD_CONTEXT_ENTRY
*ContextEntry
;
83 VTD_SOURCE_ID
*PciSourceId
;
84 VTD_SOURCE_ID SourceId
;
86 UINTN EntryTablePages
;
89 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
90 PciSourceId
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
;
91 if (PciSourceId
->Bits
.Bus
> MaxBusNumber
) {
92 MaxBusNumber
= PciSourceId
->Bits
.Bus
;
95 DEBUG ((DEBUG_INFO
," MaxBusNumber - 0x%x\n", MaxBusNumber
));
97 RootPages
= EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY
) * VTD_ROOT_ENTRY_NUMBER
);
98 ContextPages
= EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY
) * VTD_CONTEXT_ENTRY_NUMBER
);
99 EntryTablePages
= RootPages
+ ContextPages
* (MaxBusNumber
+ 1);
100 Buffer
= AllocateZeroPages (EntryTablePages
);
101 if (Buffer
== NULL
) {
102 DEBUG ((DEBUG_INFO
,"Could not Alloc Root Entry Table.. \n"));
103 return EFI_OUT_OF_RESOURCES
;
105 mVtdUnitInformation
[VtdIndex
].RootEntryTable
= (VTD_ROOT_ENTRY
*)Buffer
;
106 Buffer
= (UINT8
*)Buffer
+ EFI_PAGES_TO_SIZE (RootPages
);
108 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
109 PciSourceId
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
;
111 SourceId
.Bits
.Bus
= PciSourceId
->Bits
.Bus
;
112 SourceId
.Bits
.Device
= PciSourceId
->Bits
.Device
;
113 SourceId
.Bits
.Function
= PciSourceId
->Bits
.Function
;
115 RootEntry
= &mVtdUnitInformation
[VtdIndex
].RootEntryTable
[SourceId
.Index
.RootIndex
];
116 if (RootEntry
->Bits
.Present
== 0) {
117 RootEntry
->Bits
.ContextTablePointerLo
= (UINT32
) RShiftU64 ((UINT64
)(UINTN
)Buffer
, 12);
118 RootEntry
->Bits
.ContextTablePointerHi
= (UINT32
) RShiftU64 ((UINT64
)(UINTN
)Buffer
, 32);
119 RootEntry
->Bits
.Present
= 1;
120 Buffer
= (UINT8
*)Buffer
+ EFI_PAGES_TO_SIZE (ContextPages
);
123 ContextEntryTable
= (VTD_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(RootEntry
->Bits
.ContextTablePointerLo
, RootEntry
->Bits
.ContextTablePointerHi
) ;
124 ContextEntry
= &ContextEntryTable
[SourceId
.Index
.ContextIndex
];
125 ContextEntry
->Bits
.TranslationType
= 0;
126 ContextEntry
->Bits
.FaultProcessingDisable
= 0;
127 ContextEntry
->Bits
.Present
= 0;
129 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
));
131 switch (mVtdUnitInformation
[VtdIndex
].CapReg
.Bits
.SAGAW
) {
133 ContextEntry
->Bits
.AddressWidth
= 0x1;
136 ContextEntry
->Bits
.AddressWidth
= 0x2;
141 FlushPageTableMemory (VtdIndex
, (UINTN
)mVtdUnitInformation
[VtdIndex
].RootEntryTable
, EFI_PAGES_TO_SIZE(EntryTablePages
));
147 Create second level paging entry table.
149 @param[in] VtdIndex The index of the VTd engine.
150 @param[in] SecondLevelPagingEntry The second level paging entry.
151 @param[in] MemoryBase The base of the memory.
152 @param[in] MemoryLimit The limit of the memory.
153 @param[in] IoMmuAccess The IOMMU access.
155 @return The second level paging entry.
157 VTD_SECOND_LEVEL_PAGING_ENTRY
*
158 CreateSecondLevelPagingEntryTable (
160 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
161 IN UINT64 MemoryBase
,
162 IN UINT64 MemoryLimit
,
163 IN UINT64 IoMmuAccess
173 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl4PtEntry
;
174 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl3PtEntry
;
175 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl2PtEntry
;
179 if (MemoryLimit
== 0) {
183 BaseAddress
= ALIGN_VALUE_LOW(MemoryBase
, SIZE_2MB
);
184 EndAddress
= ALIGN_VALUE_UP(MemoryLimit
, SIZE_2MB
);
185 DEBUG ((DEBUG_INFO
,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%016lx, EndAddress - 0x%016lx\n", BaseAddress
, EndAddress
));
187 if (SecondLevelPagingEntry
== NULL
) {
188 SecondLevelPagingEntry
= AllocateZeroPages (1);
189 if (SecondLevelPagingEntry
== NULL
) {
190 DEBUG ((DEBUG_ERROR
,"Could not Alloc LVL4 PT. \n"));
193 FlushPageTableMemory (VtdIndex
, (UINTN
)SecondLevelPagingEntry
, EFI_PAGES_TO_SIZE(1));
197 // If no access is needed, just create not present entry.
199 if (IoMmuAccess
== 0) {
200 return SecondLevelPagingEntry
;
203 Lvl4Start
= RShiftU64 (BaseAddress
, 39) & 0x1FF;
204 Lvl4End
= RShiftU64 (EndAddress
- 1, 39) & 0x1FF;
206 DEBUG ((DEBUG_INFO
," Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start
, Lvl4End
));
208 Lvl4PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)SecondLevelPagingEntry
;
209 for (Index4
= Lvl4Start
; Index4
<= Lvl4End
; Index4
++) {
210 if (Lvl4PtEntry
[Index4
].Uint64
== 0) {
211 Lvl4PtEntry
[Index4
].Uint64
= (UINT64
)(UINTN
)AllocateZeroPages (1);
212 if (Lvl4PtEntry
[Index4
].Uint64
== 0) {
213 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4
));
217 FlushPageTableMemory (VtdIndex
, (UINTN
)Lvl4PtEntry
[Index4
].Uint64
, SIZE_4KB
);
218 SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry
[Index4
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
221 Lvl3Start
= RShiftU64 (BaseAddress
, 30) & 0x1FF;
222 if (ALIGN_VALUE_LOW(BaseAddress
+ SIZE_1GB
, SIZE_1GB
) <= EndAddress
) {
223 Lvl3End
= SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
) - 1;
225 Lvl3End
= RShiftU64 (EndAddress
- 1, 30) & 0x1FF;
227 DEBUG ((DEBUG_INFO
," Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n", Index4
, Lvl3Start
, Lvl3End
));
229 Lvl3PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl4PtEntry
[Index4
].Bits
.AddressLo
, Lvl4PtEntry
[Index4
].Bits
.AddressHi
);
230 for (Index3
= Lvl3Start
; Index3
<= Lvl3End
; Index3
++) {
231 if (Lvl3PtEntry
[Index3
].Uint64
== 0) {
232 Lvl3PtEntry
[Index3
].Uint64
= (UINT64
)(UINTN
)AllocateZeroPages (1);
233 if (Lvl3PtEntry
[Index3
].Uint64
== 0) {
234 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4
, Index3
));
238 FlushPageTableMemory (VtdIndex
, (UINTN
)Lvl3PtEntry
[Index3
].Uint64
, SIZE_4KB
);
239 SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry
[Index3
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
242 Lvl2PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl3PtEntry
[Index3
].Bits
.AddressLo
, Lvl3PtEntry
[Index3
].Bits
.AddressHi
);
243 for (Index2
= 0; Index2
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index2
++) {
244 Lvl2PtEntry
[Index2
].Uint64
= BaseAddress
;
245 SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry
[Index2
], IoMmuAccess
);
246 Lvl2PtEntry
[Index2
].Bits
.PageSize
= 1;
247 BaseAddress
+= SIZE_2MB
;
248 if (BaseAddress
>= MemoryLimit
) {
252 FlushPageTableMemory (VtdIndex
, (UINTN
)Lvl2PtEntry
, SIZE_4KB
);
253 if (BaseAddress
>= MemoryLimit
) {
257 FlushPageTableMemory (VtdIndex
, (UINTN
)&Lvl3PtEntry
[Lvl3Start
], (UINTN
)&Lvl3PtEntry
[Lvl3End
+ 1] - (UINTN
)&Lvl3PtEntry
[Lvl3Start
]);
258 if (BaseAddress
>= MemoryLimit
) {
262 FlushPageTableMemory (VtdIndex
, (UINTN
)&Lvl4PtEntry
[Lvl4Start
], (UINTN
)&Lvl4PtEntry
[Lvl4End
+ 1] - (UINTN
)&Lvl4PtEntry
[Lvl4Start
]);
264 return SecondLevelPagingEntry
;
268 Create second level paging entry.
270 @param[in] VtdIndex The index of the VTd engine.
271 @param[in] IoMmuAccess The IOMMU access.
273 @return The second level paging entry.
275 VTD_SECOND_LEVEL_PAGING_ENTRY
*
276 CreateSecondLevelPagingEntry (
278 IN UINT64 IoMmuAccess
281 VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
;
283 SecondLevelPagingEntry
= NULL
;
284 SecondLevelPagingEntry
= CreateSecondLevelPagingEntryTable (VtdIndex
, SecondLevelPagingEntry
, 0, mBelow4GMemoryLimit
, IoMmuAccess
);
285 if (SecondLevelPagingEntry
== NULL
) {
289 if (mAbove4GMemoryLimit
!= 0) {
290 ASSERT (mAbove4GMemoryLimit
> BASE_4GB
);
291 SecondLevelPagingEntry
= CreateSecondLevelPagingEntryTable (VtdIndex
, SecondLevelPagingEntry
, SIZE_4GB
, mAbove4GMemoryLimit
, IoMmuAccess
);
292 if (SecondLevelPagingEntry
== NULL
) {
297 return SecondLevelPagingEntry
;
301 Setup VTd translation table.
303 @retval EFI_SUCCESS Setup translation table successfully.
304 @retval EFI_OUT_OF_RESOURCE Setup translation table fail.
307 SetupTranslationTable (
314 for (Index
= 0; Index
< mVtdUnitNumber
; Index
++) {
315 DEBUG((DEBUG_INFO
, "CreateContextEntry - %d\n", Index
));
316 if (mVtdUnitInformation
[Index
].ECapReg
.Bits
.ECS
) {
317 Status
= CreateExtContextEntry (Index
);
319 Status
= CreateContextEntry (Index
);
321 if (EFI_ERROR (Status
)) {
330 Dump DMAR context entry table.
332 @param[in] RootEntry DMAR root entry.
335 DumpDmarContextEntryTable (
336 IN VTD_ROOT_ENTRY
*RootEntry
341 VTD_CONTEXT_ENTRY
*ContextEntry
;
343 DEBUG ((DEBUG_INFO
,"=========================\n"));
344 DEBUG ((DEBUG_INFO
,"DMAR Context Entry Table:\n"));
346 DEBUG ((DEBUG_INFO
,"RootEntry Address - 0x%x\n", RootEntry
));
348 for (Index
= 0; Index
< VTD_ROOT_ENTRY_NUMBER
; Index
++) {
349 if ((RootEntry
[Index
].Uint128
.Uint64Lo
!= 0) || (RootEntry
[Index
].Uint128
.Uint64Hi
!= 0)) {
350 DEBUG ((DEBUG_INFO
," RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",
351 Index
, Index
, RootEntry
[Index
].Uint128
.Uint64Hi
, RootEntry
[Index
].Uint128
.Uint64Lo
));
353 if (RootEntry
[Index
].Bits
.Present
== 0) {
356 ContextEntry
= (VTD_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(RootEntry
[Index
].Bits
.ContextTablePointerLo
, RootEntry
[Index
].Bits
.ContextTablePointerHi
);
357 for (Index2
= 0; Index2
< VTD_CONTEXT_ENTRY_NUMBER
; Index2
++) {
358 if ((ContextEntry
[Index2
].Uint128
.Uint64Lo
!= 0) || (ContextEntry
[Index2
].Uint128
.Uint64Hi
!= 0)) {
359 DEBUG ((DEBUG_INFO
," ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n",
360 Index2
, Index2
>> 3, Index2
& 0x7, ContextEntry
[Index2
].Uint128
.Uint64Hi
, ContextEntry
[Index2
].Uint128
.Uint64Lo
));
362 if (ContextEntry
[Index2
].Bits
.Present
== 0) {
365 DumpSecondLevelPagingEntry ((VOID
*)(UINTN
)VTD_64BITS_ADDRESS(ContextEntry
[Index2
].Bits
.SecondLevelPageTranslationPointerLo
, ContextEntry
[Index2
].Bits
.SecondLevelPageTranslationPointerHi
));
368 DEBUG ((DEBUG_INFO
,"=========================\n"));
372 Dump DMAR second level paging entry.
374 @param[in] SecondLevelPagingEntry The second level paging entry.
377 DumpSecondLevelPagingEntry (
378 IN VOID
*SecondLevelPagingEntry
385 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl4PtEntry
;
386 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl3PtEntry
;
387 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl2PtEntry
;
388 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl1PtEntry
;
390 DEBUG ((DEBUG_VERBOSE
,"================\n"));
391 DEBUG ((DEBUG_VERBOSE
,"DMAR Second Level Page Table:\n"));
393 DEBUG ((DEBUG_VERBOSE
,"SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry
));
394 Lvl4PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)SecondLevelPagingEntry
;
395 for (Index4
= 0; Index4
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index4
++) {
396 if (Lvl4PtEntry
[Index4
].Uint64
!= 0) {
397 DEBUG ((DEBUG_VERBOSE
," Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4
, Lvl4PtEntry
[Index4
].Uint64
));
399 if (Lvl4PtEntry
[Index4
].Uint64
== 0) {
402 Lvl3PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl4PtEntry
[Index4
].Bits
.AddressLo
, Lvl4PtEntry
[Index4
].Bits
.AddressHi
);
403 for (Index3
= 0; Index3
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index3
++) {
404 if (Lvl3PtEntry
[Index3
].Uint64
!= 0) {
405 DEBUG ((DEBUG_VERBOSE
," Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3
, Lvl3PtEntry
[Index3
].Uint64
));
407 if (Lvl3PtEntry
[Index3
].Uint64
== 0) {
411 Lvl2PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl3PtEntry
[Index3
].Bits
.AddressLo
, Lvl3PtEntry
[Index3
].Bits
.AddressHi
);
412 for (Index2
= 0; Index2
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index2
++) {
413 if (Lvl2PtEntry
[Index2
].Uint64
!= 0) {
414 DEBUG ((DEBUG_VERBOSE
," Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2
, Lvl2PtEntry
[Index2
].Uint64
));
416 if (Lvl2PtEntry
[Index2
].Uint64
== 0) {
419 if (Lvl2PtEntry
[Index2
].Bits
.PageSize
== 0) {
420 Lvl1PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl2PtEntry
[Index2
].Bits
.AddressLo
, Lvl2PtEntry
[Index2
].Bits
.AddressHi
);
421 for (Index1
= 0; Index1
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index1
++) {
422 if (Lvl1PtEntry
[Index1
].Uint64
!= 0) {
423 DEBUG ((DEBUG_VERBOSE
," Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1
, Lvl1PtEntry
[Index1
].Uint64
));
430 DEBUG ((DEBUG_VERBOSE
,"================\n"));
436 @param VtdIndex The VTd engine index.
439 InvalidatePageEntry (
443 if (mVtdUnitInformation
[VtdIndex
].HasDirtyContext
|| mVtdUnitInformation
[VtdIndex
].HasDirtyPages
) {
444 InvalidateVtdIOTLBGlobal (VtdIndex
);
446 mVtdUnitInformation
[VtdIndex
].HasDirtyContext
= FALSE
;
447 mVtdUnitInformation
[VtdIndex
].HasDirtyPages
= FALSE
;
450 #define VTD_PG_R BIT0
451 #define VTD_PG_W BIT1
452 #define VTD_PG_X BIT2
453 #define VTD_PG_EMT (BIT3 | BIT4 | BIT5)
454 #define VTD_PG_TM (BIT62)
456 #define VTD_PG_PS BIT7
458 #define PAGE_PROGATE_BITS (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VTD_PG_R)
460 #define PAGING_4K_MASK 0xFFF
461 #define PAGING_2M_MASK 0x1FFFFF
462 #define PAGING_1G_MASK 0x3FFFFFFF
464 #define PAGING_VTD_INDEX_MASK 0x1FF
466 #define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
467 #define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
468 #define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
478 PAGE_ATTRIBUTE Attribute
;
481 } PAGE_ATTRIBUTE_TABLE
;
483 PAGE_ATTRIBUTE_TABLE mPageAttributeTable
[] = {
484 {Page4K
, SIZE_4KB
, PAGING_4K_ADDRESS_MASK_64
},
485 {Page2M
, SIZE_2MB
, PAGING_2M_ADDRESS_MASK_64
},
486 {Page1G
, SIZE_1GB
, PAGING_1G_ADDRESS_MASK_64
},
490 Return length according to page attributes.
492 @param[in] PageAttributes The page attribute of the page entry.
494 @return The length of page entry.
497 PageAttributeToLength (
498 IN PAGE_ATTRIBUTE PageAttribute
502 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
503 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
504 return (UINTN
)mPageAttributeTable
[Index
].Length
;
511 Return page table entry to match the address.
513 @param[in] VtdIndex The index used to identify a VTd engine.
514 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.
515 @param[in] Address The address to be checked.
516 @param[out] PageAttributes The page attribute of the page entry.
518 @return The page entry.
521 GetSecondLevelPageTableEntry (
523 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
524 IN PHYSICAL_ADDRESS Address
,
525 OUT PAGE_ATTRIBUTE
*PageAttribute
537 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_VTD_INDEX_MASK
;
538 Index3
= ((UINTN
)Address
>> 30) & PAGING_VTD_INDEX_MASK
;
539 Index2
= ((UINTN
)Address
>> 21) & PAGING_VTD_INDEX_MASK
;
540 Index1
= ((UINTN
)Address
>> 12) & PAGING_VTD_INDEX_MASK
;
542 L4PageTable
= (UINT64
*)SecondLevelPagingEntry
;
543 if (L4PageTable
[Index4
] == 0) {
544 L4PageTable
[Index4
] = (UINT64
)(UINTN
)AllocateZeroPages (1);
545 if (L4PageTable
[Index4
] == 0) {
546 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4
));
548 *PageAttribute
= PageNone
;
551 FlushPageTableMemory (VtdIndex
, (UINTN
)L4PageTable
[Index4
], SIZE_4KB
);
552 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY
*)&L4PageTable
[Index4
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
553 FlushPageTableMemory (VtdIndex
, (UINTN
)&L4PageTable
[Index4
], sizeof(L4PageTable
[Index4
]));
556 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & PAGING_4K_ADDRESS_MASK_64
);
557 if (L3PageTable
[Index3
] == 0) {
558 L3PageTable
[Index3
] = (UINT64
)(UINTN
)AllocateZeroPages (1);
559 if (L3PageTable
[Index3
] == 0) {
560 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4
, Index3
));
562 *PageAttribute
= PageNone
;
565 FlushPageTableMemory (VtdIndex
, (UINTN
)L3PageTable
[Index3
], SIZE_4KB
);
566 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY
*)&L3PageTable
[Index3
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
567 FlushPageTableMemory (VtdIndex
, (UINTN
)&L3PageTable
[Index3
], sizeof(L3PageTable
[Index3
]));
569 if ((L3PageTable
[Index3
] & VTD_PG_PS
) != 0) {
571 *PageAttribute
= Page1G
;
572 return &L3PageTable
[Index3
];
575 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & PAGING_4K_ADDRESS_MASK_64
);
576 if (L2PageTable
[Index2
] == 0) {
577 L2PageTable
[Index2
] = Address
& PAGING_2M_ADDRESS_MASK_64
;
578 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY
*)&L2PageTable
[Index2
], 0);
579 L2PageTable
[Index2
] |= VTD_PG_PS
;
580 FlushPageTableMemory (VtdIndex
, (UINTN
)&L2PageTable
[Index2
], sizeof(L2PageTable
[Index2
]));
582 if ((L2PageTable
[Index2
] & VTD_PG_PS
) != 0) {
584 *PageAttribute
= Page2M
;
585 return &L2PageTable
[Index2
];
589 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & PAGING_4K_ADDRESS_MASK_64
);
590 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
591 *PageAttribute
= PageNone
;
594 *PageAttribute
= Page4K
;
595 return &L1PageTable
[Index1
];
599 Modify memory attributes of page entry.
601 @param[in] VtdIndex The index used to identify a VTd engine.
602 @param[in] PageEntry The page entry.
603 @param[in] IoMmuAccess The IOMMU access.
604 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
607 ConvertSecondLevelPageEntryAttribute (
609 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*PageEntry
,
610 IN UINT64 IoMmuAccess
,
611 OUT BOOLEAN
*IsModified
614 UINT64 CurrentPageEntry
;
617 CurrentPageEntry
= PageEntry
->Uint64
;
618 SetSecondLevelPagingEntryAttribute (PageEntry
, IoMmuAccess
);
619 FlushPageTableMemory (VtdIndex
, (UINTN
)PageEntry
, sizeof(*PageEntry
));
620 NewPageEntry
= PageEntry
->Uint64
;
621 if (CurrentPageEntry
!= NewPageEntry
) {
623 DEBUG ((DEBUG_VERBOSE
, "ConvertSecondLevelPageEntryAttribute 0x%lx", CurrentPageEntry
));
624 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
631 This function returns if there is need to split page entry.
633 @param[in] BaseAddress The base address to be checked.
634 @param[in] Length The length to be checked.
635 @param[in] PageAttribute The page attribute of the page entry.
637 @retval SplitAttributes on if there is need to split page entry.
641 IN PHYSICAL_ADDRESS BaseAddress
,
643 IN PAGE_ATTRIBUTE PageAttribute
646 UINT64 PageEntryLength
;
648 PageEntryLength
= PageAttributeToLength (PageAttribute
);
650 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
654 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
662 This function splits one page entry to small page entries.
664 @param[in] VtdIndex The index used to identify a VTd engine.
665 @param[in] PageEntry The page entry to be splitted.
666 @param[in] PageAttribute The page attribute of the page entry.
667 @param[in] SplitAttribute How to split the page entry.
669 @retval RETURN_SUCCESS The page entry is splitted.
670 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
671 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
674 SplitSecondLevelPage (
676 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*PageEntry
,
677 IN PAGE_ATTRIBUTE PageAttribute
,
678 IN PAGE_ATTRIBUTE SplitAttribute
682 UINT64
*NewPageEntry
;
685 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
687 if (PageAttribute
== Page2M
) {
691 ASSERT (SplitAttribute
== Page4K
);
692 if (SplitAttribute
== Page4K
) {
693 NewPageEntry
= AllocateZeroPages (1);
694 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
695 if (NewPageEntry
== NULL
) {
696 return RETURN_OUT_OF_RESOURCES
;
698 BaseAddress
= PageEntry
->Uint64
& PAGING_2M_ADDRESS_MASK_64
;
699 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
700 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | (PageEntry
->Uint64
& PAGE_PROGATE_BITS
);
702 FlushPageTableMemory (VtdIndex
, (UINTN
)NewPageEntry
, SIZE_4KB
);
704 PageEntry
->Uint64
= (UINT64
)(UINTN
)NewPageEntry
;
705 SetSecondLevelPagingEntryAttribute (PageEntry
, EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
706 FlushPageTableMemory (VtdIndex
, (UINTN
)PageEntry
, sizeof(*PageEntry
));
707 return RETURN_SUCCESS
;
709 return RETURN_UNSUPPORTED
;
711 } else if (PageAttribute
== Page1G
) {
714 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
716 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
717 if ((SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
)) {
718 NewPageEntry
= AllocateZeroPages (1);
719 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
720 if (NewPageEntry
== NULL
) {
721 return RETURN_OUT_OF_RESOURCES
;
723 BaseAddress
= PageEntry
->Uint64
& PAGING_1G_ADDRESS_MASK_64
;
724 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
725 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_2MB
* Index
) | VTD_PG_PS
| (PageEntry
->Uint64
& PAGE_PROGATE_BITS
);
727 FlushPageTableMemory (VtdIndex
, (UINTN
)NewPageEntry
, SIZE_4KB
);
729 PageEntry
->Uint64
= (UINT64
)(UINTN
)NewPageEntry
;
730 SetSecondLevelPagingEntryAttribute (PageEntry
, EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
731 FlushPageTableMemory (VtdIndex
, (UINTN
)PageEntry
, sizeof(*PageEntry
));
732 return RETURN_SUCCESS
;
734 return RETURN_UNSUPPORTED
;
737 return RETURN_UNSUPPORTED
;
742 Set VTd attribute for a system memory on second level page entry
744 @param[in] VtdIndex The index used to identify a VTd engine.
745 @param[in] DomainIdentifier The domain ID of the source.
746 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.
747 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
748 @param[in] Length The length of device memory address to be used as the DMA memory.
749 @param[in] IoMmuAccess The IOMMU access.
751 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
752 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
753 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
754 @retval EFI_INVALID_PARAMETER Length is 0.
755 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
756 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
757 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
758 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
759 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
762 SetSecondLevelPagingAttribute (
764 IN UINT16 DomainIdentifier
,
765 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
766 IN UINT64 BaseAddress
,
768 IN UINT64 IoMmuAccess
771 VTD_SECOND_LEVEL_PAGING_ENTRY
*PageEntry
;
772 PAGE_ATTRIBUTE PageAttribute
;
773 UINTN PageEntryLength
;
774 PAGE_ATTRIBUTE SplitAttribute
;
776 BOOLEAN IsEntryModified
;
778 DEBUG ((DEBUG_VERBOSE
,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x%016lx : %x) \n", VtdIndex
, BaseAddress
, Length
, IoMmuAccess
));
779 DEBUG ((DEBUG_VERBOSE
," SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry
));
781 if (BaseAddress
!= ALIGN_VALUE(BaseAddress
, SIZE_4KB
)) {
782 DEBUG ((DEBUG_ERROR
, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
783 return EFI_UNSUPPORTED
;
785 if (Length
!= ALIGN_VALUE(Length
, SIZE_4KB
)) {
786 DEBUG ((DEBUG_ERROR
, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
787 return EFI_UNSUPPORTED
;
790 while (Length
!= 0) {
791 PageEntry
= GetSecondLevelPageTableEntry (VtdIndex
, SecondLevelPagingEntry
, BaseAddress
, &PageAttribute
);
792 if (PageEntry
== NULL
) {
793 DEBUG ((DEBUG_ERROR
, "PageEntry - NULL\n"));
794 return RETURN_UNSUPPORTED
;
796 PageEntryLength
= PageAttributeToLength (PageAttribute
);
797 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageAttribute
);
798 if (SplitAttribute
== PageNone
) {
799 ConvertSecondLevelPageEntryAttribute (VtdIndex
, PageEntry
, IoMmuAccess
, &IsEntryModified
);
800 if (IsEntryModified
) {
801 mVtdUnitInformation
[VtdIndex
].HasDirtyPages
= TRUE
;
804 // Convert success, move to next
806 BaseAddress
+= PageEntryLength
;
807 Length
-= PageEntryLength
;
809 Status
= SplitSecondLevelPage (VtdIndex
, PageEntry
, PageAttribute
, SplitAttribute
);
810 if (RETURN_ERROR (Status
)) {
811 DEBUG ((DEBUG_ERROR
, "SplitSecondLevelPage - %r\n", Status
));
812 return RETURN_UNSUPPORTED
;
814 mVtdUnitInformation
[VtdIndex
].HasDirtyPages
= TRUE
;
816 // Just split current page
817 // Convert success in next around
826 Set VTd attribute for a system memory.
828 @param[in] VtdIndex The index used to identify a VTd engine.
829 @param[in] DomainIdentifier The domain ID of the source.
830 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.
831 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
832 @param[in] Length The length of device memory address to be used as the DMA memory.
833 @param[in] IoMmuAccess The IOMMU access.
835 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
836 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
837 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
838 @retval EFI_INVALID_PARAMETER Length is 0.
839 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
840 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
841 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
842 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
843 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
848 IN UINT16 DomainIdentifier
,
849 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
850 IN UINT64 BaseAddress
,
852 IN UINT64 IoMmuAccess
856 Status
= EFI_NOT_FOUND
;
857 if (SecondLevelPagingEntry
!= NULL
) {
858 Status
= SetSecondLevelPagingAttribute (VtdIndex
, DomainIdentifier
, SecondLevelPagingEntry
, BaseAddress
, Length
, IoMmuAccess
);
864 Set VTd attribute for a system memory.
866 @param[in] Segment The Segment used to identify a VTd engine.
867 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
868 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
869 @param[in] Length The length of device memory address to be used as the DMA memory.
870 @param[in] IoMmuAccess The IOMMU access.
872 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
873 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
874 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
875 @retval EFI_INVALID_PARAMETER Length is 0.
876 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
877 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
878 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
879 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
880 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
885 IN VTD_SOURCE_ID SourceId
,
886 IN UINT64 BaseAddress
,
888 IN UINT64 IoMmuAccess
893 VTD_EXT_CONTEXT_ENTRY
*ExtContextEntry
;
894 VTD_CONTEXT_ENTRY
*ContextEntry
;
895 VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
;
898 UINT16 DomainIdentifier
;
900 SecondLevelPagingEntry
= NULL
;
902 DEBUG ((DEBUG_VERBOSE
,"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
));
904 VtdIndex
= FindVtdIndexByPciDevice (Segment
, SourceId
, &ExtContextEntry
, &ContextEntry
);
905 if (VtdIndex
== (UINTN
)-1) {
906 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
));
907 return EFI_DEVICE_ERROR
;
910 PciDataIndex
= GetPciDataIndex (VtdIndex
, Segment
, SourceId
);
911 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[PciDataIndex
].AccessCount
++;
913 // DomainId should not be 0.
915 DomainIdentifier
= (UINT16
)(PciDataIndex
+ 1);
917 if (ExtContextEntry
!= NULL
) {
918 if (ExtContextEntry
->Bits
.Present
== 0) {
919 SecondLevelPagingEntry
= CreateSecondLevelPagingEntry (VtdIndex
, 0);
920 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
));
921 Pt
= (UINT64
)RShiftU64 ((UINT64
)(UINTN
)SecondLevelPagingEntry
, 12);
923 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
924 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
925 ExtContextEntry
->Bits
.DomainIdentifier
= DomainIdentifier
;
926 ExtContextEntry
->Bits
.Present
= 1;
927 FlushPageTableMemory (VtdIndex
, (UINTN
)ExtContextEntry
, sizeof(*ExtContextEntry
));
928 DumpDmarExtContextEntryTable (mVtdUnitInformation
[VtdIndex
].ExtRootEntryTable
);
929 mVtdUnitInformation
[VtdIndex
].HasDirtyContext
= TRUE
;
931 SecondLevelPagingEntry
= (VOID
*)(UINTN
)VTD_64BITS_ADDRESS(ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
, ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
);
932 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
));
934 } else if (ContextEntry
!= NULL
) {
935 if (ContextEntry
->Bits
.Present
== 0) {
936 SecondLevelPagingEntry
= CreateSecondLevelPagingEntry (VtdIndex
, 0);
937 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
));
938 Pt
= (UINT64
)RShiftU64 ((UINT64
)(UINTN
)SecondLevelPagingEntry
, 12);
940 ContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
941 ContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
942 ContextEntry
->Bits
.DomainIdentifier
= DomainIdentifier
;
943 ContextEntry
->Bits
.Present
= 1;
944 FlushPageTableMemory (VtdIndex
, (UINTN
)ContextEntry
, sizeof(*ContextEntry
));
945 DumpDmarContextEntryTable (mVtdUnitInformation
[VtdIndex
].RootEntryTable
);
946 mVtdUnitInformation
[VtdIndex
].HasDirtyContext
= TRUE
;
948 SecondLevelPagingEntry
= (VOID
*)(UINTN
)VTD_64BITS_ADDRESS(ContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
, ContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
);
949 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
));
954 // Do not update FixedSecondLevelPagingEntry
956 if (SecondLevelPagingEntry
!= mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
) {
957 Status
= SetPageAttribute (
960 SecondLevelPagingEntry
,
965 if (EFI_ERROR (Status
)) {
966 DEBUG ((DEBUG_ERROR
,"SetPageAttribute - %r\n", Status
));
971 InvalidatePageEntry (VtdIndex
);
977 Always enable the VTd page attribute for the device.
979 @param[in] Segment The Segment used to identify a VTd engine.
980 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
982 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.
985 AlwaysEnablePageAttribute (
987 IN VTD_SOURCE_ID SourceId
991 VTD_EXT_CONTEXT_ENTRY
*ExtContextEntry
;
992 VTD_CONTEXT_ENTRY
*ContextEntry
;
993 VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
;
996 DEBUG ((DEBUG_INFO
,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\n", Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
));
998 VtdIndex
= FindVtdIndexByPciDevice (Segment
, SourceId
, &ExtContextEntry
, &ContextEntry
);
999 if (VtdIndex
== (UINTN
)-1) {
1000 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
));
1001 return EFI_DEVICE_ERROR
;
1004 if (mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
== 0) {
1005 DEBUG((DEBUG_INFO
, "CreateSecondLevelPagingEntry - %d\n", VtdIndex
));
1006 mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
= CreateSecondLevelPagingEntry (VtdIndex
, EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
1009 SecondLevelPagingEntry
= mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
;
1010 Pt
= (UINT64
)RShiftU64 ((UINT64
)(UINTN
)SecondLevelPagingEntry
, 12);
1011 if (ExtContextEntry
!= NULL
) {
1012 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
1013 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
1014 ExtContextEntry
->Bits
.DomainIdentifier
= ((1 << (UINT8
)((UINTN
)mVtdUnitInformation
[VtdIndex
].CapReg
.Bits
.ND
* 2 + 4)) - 1);
1015 ExtContextEntry
->Bits
.Present
= 1;
1016 FlushPageTableMemory (VtdIndex
, (UINTN
)ExtContextEntry
, sizeof(*ExtContextEntry
));
1017 } else if (ContextEntry
!= NULL
) {
1018 ContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
1019 ContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
1020 ContextEntry
->Bits
.DomainIdentifier
= ((1 << (UINT8
)((UINTN
)mVtdUnitInformation
[VtdIndex
].CapReg
.Bits
.ND
* 2 + 4)) - 1);
1021 ContextEntry
->Bits
.Present
= 1;
1022 FlushPageTableMemory (VtdIndex
, (UINTN
)ContextEntry
, sizeof(*ContextEntry
));