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.
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.
14 #include "DmaProtection.h"
17 Create extended context entry.
19 @param[in] VtdIndex The index of the VTd engine.
21 @retval EFI_SUCCESS The extended context entry is created.
22 @retval EFI_OUT_OF_RESOURCE No enough resource to create extended context entry.
25 CreateExtContextEntry (
32 @param[in] Pages the number of pages.
34 @return the page address.
35 @retval NULL No resource to allocate pages.
45 Addr
= AllocatePages (Pages
);
49 ZeroMem (Addr
, EFI_PAGES_TO_SIZE(Pages
));
54 Set second level paging entry attribute based upon IoMmuAccess.
56 @param[in] PtEntry The paging entry.
57 @param[in] IoMmuAccess The IOMMU access.
60 SetSecondLevelPagingEntryAttribute (
61 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*PtEntry
,
65 PtEntry
->Bits
.Read
= ((IoMmuAccess
& EDKII_IOMMU_ACCESS_READ
) != 0);
66 PtEntry
->Bits
.Write
= ((IoMmuAccess
& EDKII_IOMMU_ACCESS_WRITE
) != 0);
72 @param[in] VtdIndex The index of the VTd engine.
74 @retval EFI_SUCCESS The context entry is created.
75 @retval EFI_OUT_OF_RESOURCE No enough resource to create context entry.
86 VTD_ROOT_ENTRY
*RootEntry
;
87 VTD_CONTEXT_ENTRY
*ContextEntryTable
;
88 VTD_CONTEXT_ENTRY
*ContextEntry
;
89 VTD_SOURCE_ID
*PciSourceId
;
90 VTD_SOURCE_ID SourceId
;
92 UINTN EntryTablePages
;
95 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
96 PciSourceId
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
;
97 if (PciSourceId
->Bits
.Bus
> MaxBusNumber
) {
98 MaxBusNumber
= PciSourceId
->Bits
.Bus
;
101 DEBUG ((DEBUG_INFO
," MaxBusNumber - 0x%x\n", MaxBusNumber
));
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
;
111 mVtdUnitInformation
[VtdIndex
].RootEntryTable
= (VTD_ROOT_ENTRY
*)Buffer
;
112 Buffer
= (UINT8
*)Buffer
+ EFI_PAGES_TO_SIZE (RootPages
);
114 for (Index
= 0; Index
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; Index
++) {
115 PciSourceId
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[Index
].PciSourceId
;
117 SourceId
.Bits
.Bus
= PciSourceId
->Bits
.Bus
;
118 SourceId
.Bits
.Device
= PciSourceId
->Bits
.Device
;
119 SourceId
.Bits
.Function
= PciSourceId
->Bits
.Function
;
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 FlushPageTableMemory (VtdIndex
, (UINTN
)RootEntry
, sizeof(*RootEntry
));
130 ContextEntryTable
= (VTD_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(RootEntry
->Bits
.ContextTablePointerLo
, RootEntry
->Bits
.ContextTablePointerHi
) ;
131 ContextEntry
= &ContextEntryTable
[SourceId
.Index
.ContextIndex
];
132 ContextEntry
->Bits
.TranslationType
= 0;
133 ContextEntry
->Bits
.FaultProcessingDisable
= 0;
134 ContextEntry
->Bits
.Present
= 0;
136 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
));
138 switch (mVtdUnitInformation
[VtdIndex
].CapReg
.Bits
.SAGAW
) {
140 ContextEntry
->Bits
.AddressWidth
= 0x1;
143 ContextEntry
->Bits
.AddressWidth
= 0x2;
146 FlushPageTableMemory (VtdIndex
, (UINTN
)ContextEntry
, sizeof(*ContextEntry
));
153 Create second level paging entry table.
155 @param[in] VtdIndex The index of the VTd engine.
156 @param[in] SecondLevelPagingEntry The second level paging entry.
157 @param[in] MemoryBase The base of the memory.
158 @param[in] MemoryLimit The limit of the memory.
159 @param[in] IoMmuAccess The IOMMU access.
161 @return The second level paging entry.
163 VTD_SECOND_LEVEL_PAGING_ENTRY
*
164 CreateSecondLevelPagingEntryTable (
166 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
167 IN UINT64 MemoryBase
,
168 IN UINT64 MemoryLimit
,
169 IN UINT64 IoMmuAccess
179 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl4PtEntry
;
180 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl3PtEntry
;
181 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl2PtEntry
;
185 if (MemoryLimit
== 0) {
189 BaseAddress
= ALIGN_VALUE_LOW(MemoryBase
, SIZE_2MB
);
190 EndAddress
= ALIGN_VALUE_UP(MemoryLimit
, SIZE_2MB
);
191 DEBUG ((DEBUG_INFO
,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%016lx, EndAddress - 0x%016lx\n", BaseAddress
, EndAddress
));
193 if (SecondLevelPagingEntry
== NULL
) {
194 SecondLevelPagingEntry
= AllocateZeroPages (1);
195 if (SecondLevelPagingEntry
== NULL
) {
196 DEBUG ((DEBUG_ERROR
,"Could not Alloc LVL4 PT. \n"));
202 // If no access is needed, just create not present entry.
204 if (IoMmuAccess
== 0) {
205 return SecondLevelPagingEntry
;
208 Lvl4Start
= RShiftU64 (BaseAddress
, 39) & 0x1FF;
209 Lvl4End
= RShiftU64 (EndAddress
- 1, 39) & 0x1FF;
211 DEBUG ((DEBUG_INFO
," Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start
, Lvl4End
));
213 Lvl4PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)SecondLevelPagingEntry
;
214 for (Index4
= Lvl4Start
; Index4
<= Lvl4End
; Index4
++) {
215 if (Lvl4PtEntry
[Index4
].Uint64
== 0) {
216 Lvl4PtEntry
[Index4
].Uint64
= (UINT64
)(UINTN
)AllocateZeroPages (1);
217 if (Lvl4PtEntry
[Index4
].Uint64
== 0) {
218 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4
));
222 SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry
[Index4
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
225 Lvl3Start
= RShiftU64 (BaseAddress
, 30) & 0x1FF;
226 if (ALIGN_VALUE_LOW(BaseAddress
+ SIZE_1GB
, SIZE_1GB
) <= EndAddress
) {
227 Lvl3End
= SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
);
229 Lvl3End
= RShiftU64 (EndAddress
- 1, 30) & 0x1FF;
231 DEBUG ((DEBUG_INFO
," Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n", Index4
, Lvl3Start
, Lvl3End
));
233 Lvl3PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl4PtEntry
[Index4
].Bits
.AddressLo
, Lvl4PtEntry
[Index4
].Bits
.AddressHi
);
234 for (Index3
= Lvl3Start
; Index3
<= Lvl3End
; Index3
++) {
235 if (Lvl3PtEntry
[Index3
].Uint64
== 0) {
236 Lvl3PtEntry
[Index3
].Uint64
= (UINT64
)(UINTN
)AllocateZeroPages (1);
237 if (Lvl3PtEntry
[Index3
].Uint64
== 0) {
238 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4
, Index3
));
242 SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry
[Index3
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
245 Lvl2PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl3PtEntry
[Index3
].Bits
.AddressLo
, Lvl3PtEntry
[Index3
].Bits
.AddressHi
);
246 for (Index2
= 0; Index2
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index2
++) {
247 Lvl2PtEntry
[Index2
].Uint64
= BaseAddress
;
248 SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry
[Index2
], IoMmuAccess
);
249 Lvl2PtEntry
[Index2
].Bits
.PageSize
= 1;
250 BaseAddress
+= SIZE_2MB
;
251 if (BaseAddress
>= MemoryLimit
) {
255 FlushPageTableMemory (VtdIndex
, (UINTN
)Lvl2PtEntry
, SIZE_4KB
);
257 FlushPageTableMemory (VtdIndex
, (UINTN
)&Lvl3PtEntry
[Lvl3Start
], (UINTN
)&Lvl3PtEntry
[Lvl3End
+ 1] - (UINTN
)&Lvl3PtEntry
[Lvl3Start
]);
259 FlushPageTableMemory (VtdIndex
, (UINTN
)&Lvl4PtEntry
[Lvl4Start
], (UINTN
)&Lvl4PtEntry
[Lvl4End
+ 1] - (UINTN
)&Lvl4PtEntry
[Lvl4Start
]);
262 return SecondLevelPagingEntry
;
266 Create second level paging entry.
268 @param[in] VtdIndex The index of the VTd engine.
269 @param[in] IoMmuAccess The IOMMU access.
271 @return The second level paging entry.
273 VTD_SECOND_LEVEL_PAGING_ENTRY
*
274 CreateSecondLevelPagingEntry (
276 IN UINT64 IoMmuAccess
279 VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
;
281 SecondLevelPagingEntry
= NULL
;
282 SecondLevelPagingEntry
= CreateSecondLevelPagingEntryTable (VtdIndex
, SecondLevelPagingEntry
, 0, mBelow4GMemoryLimit
, IoMmuAccess
);
283 if (SecondLevelPagingEntry
== NULL
) {
286 SecondLevelPagingEntry
= CreateSecondLevelPagingEntryTable (VtdIndex
, SecondLevelPagingEntry
, SIZE_4GB
, mAbove4GMemoryLimit
, IoMmuAccess
);
287 if (SecondLevelPagingEntry
== NULL
) {
291 return SecondLevelPagingEntry
;
295 Setup VTd translation table.
297 @retval EFI_SUCCESS Setup translation table successfully.
298 @retval EFI_OUT_OF_RESOURCE Setup translation table fail.
301 SetupTranslationTable (
308 for (Index
= 0; Index
< mVtdUnitNumber
; Index
++) {
309 DEBUG((DEBUG_INFO
, "CreateContextEntry - %d\n", Index
));
310 if (mVtdUnitInformation
[Index
].ECapReg
.Bits
.ECS
) {
311 Status
= CreateExtContextEntry (Index
);
313 Status
= CreateContextEntry (Index
);
315 if (EFI_ERROR (Status
)) {
324 Dump DMAR context entry table.
326 @param[in] RootEntry DMAR root entry.
329 DumpDmarContextEntryTable (
330 IN VTD_ROOT_ENTRY
*RootEntry
335 VTD_CONTEXT_ENTRY
*ContextEntry
;
337 DEBUG ((DEBUG_INFO
,"=========================\n"));
338 DEBUG ((DEBUG_INFO
,"DMAR Context Entry Table:\n"));
340 DEBUG ((DEBUG_INFO
,"RootEntry Address - 0x%x\n", RootEntry
));
342 for (Index
= 0; Index
< VTD_ROOT_ENTRY_NUMBER
; Index
++) {
343 if ((RootEntry
[Index
].Uint128
.Uint64Lo
!= 0) || (RootEntry
[Index
].Uint128
.Uint64Hi
!= 0)) {
344 DEBUG ((DEBUG_INFO
," RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",
345 Index
, Index
, RootEntry
[Index
].Uint128
.Uint64Hi
, RootEntry
[Index
].Uint128
.Uint64Lo
));
347 if (RootEntry
[Index
].Bits
.Present
== 0) {
350 ContextEntry
= (VTD_CONTEXT_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(RootEntry
[Index
].Bits
.ContextTablePointerLo
, RootEntry
[Index
].Bits
.ContextTablePointerHi
);
351 for (Index2
= 0; Index2
< VTD_CONTEXT_ENTRY_NUMBER
; Index2
++) {
352 if ((ContextEntry
[Index2
].Uint128
.Uint64Lo
!= 0) || (ContextEntry
[Index2
].Uint128
.Uint64Hi
!= 0)) {
353 DEBUG ((DEBUG_INFO
," ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n",
354 Index2
, Index2
>> 3, Index2
& 0x7, ContextEntry
[Index2
].Uint128
.Uint64Hi
, ContextEntry
[Index2
].Uint128
.Uint64Lo
));
356 if (ContextEntry
[Index2
].Bits
.Present
== 0) {
359 DumpSecondLevelPagingEntry ((VOID
*)(UINTN
)VTD_64BITS_ADDRESS(ContextEntry
[Index2
].Bits
.SecondLevelPageTranslationPointerLo
, ContextEntry
[Index2
].Bits
.SecondLevelPageTranslationPointerHi
));
362 DEBUG ((DEBUG_INFO
,"=========================\n"));
366 Dump DMAR second level paging entry.
368 @param[in] SecondLevelPagingEntry The second level paging entry.
371 DumpSecondLevelPagingEntry (
372 IN VOID
*SecondLevelPagingEntry
379 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl4PtEntry
;
380 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl3PtEntry
;
381 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl2PtEntry
;
382 VTD_SECOND_LEVEL_PAGING_ENTRY
*Lvl1PtEntry
;
384 DEBUG ((DEBUG_VERBOSE
,"================\n"));
385 DEBUG ((DEBUG_VERBOSE
,"DMAR Second Level Page Table:\n"));
387 DEBUG ((DEBUG_VERBOSE
,"SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry
));
388 Lvl4PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)SecondLevelPagingEntry
;
389 for (Index4
= 0; Index4
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index4
++) {
390 if (Lvl4PtEntry
[Index4
].Uint64
!= 0) {
391 DEBUG ((DEBUG_VERBOSE
," Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4
, Lvl4PtEntry
[Index4
].Uint64
));
393 if (Lvl4PtEntry
[Index4
].Uint64
== 0) {
396 Lvl3PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl4PtEntry
[Index4
].Bits
.AddressLo
, Lvl4PtEntry
[Index4
].Bits
.AddressHi
);
397 for (Index3
= 0; Index3
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index3
++) {
398 if (Lvl3PtEntry
[Index3
].Uint64
!= 0) {
399 DEBUG ((DEBUG_VERBOSE
," Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3
, Lvl3PtEntry
[Index3
].Uint64
));
401 if (Lvl3PtEntry
[Index3
].Uint64
== 0) {
405 Lvl2PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl3PtEntry
[Index3
].Bits
.AddressLo
, Lvl3PtEntry
[Index3
].Bits
.AddressHi
);
406 for (Index2
= 0; Index2
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index2
++) {
407 if (Lvl2PtEntry
[Index2
].Uint64
!= 0) {
408 DEBUG ((DEBUG_VERBOSE
," Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2
, Lvl2PtEntry
[Index2
].Uint64
));
410 if (Lvl2PtEntry
[Index2
].Uint64
== 0) {
413 if (Lvl2PtEntry
[Index2
].Bits
.PageSize
== 0) {
414 Lvl1PtEntry
= (VTD_SECOND_LEVEL_PAGING_ENTRY
*)(UINTN
)VTD_64BITS_ADDRESS(Lvl2PtEntry
[Index2
].Bits
.AddressLo
, Lvl2PtEntry
[Index2
].Bits
.AddressHi
);
415 for (Index1
= 0; Index1
< SIZE_4KB
/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY
); Index1
++) {
416 if (Lvl1PtEntry
[Index1
].Uint64
!= 0) {
417 DEBUG ((DEBUG_VERBOSE
," Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1
, Lvl1PtEntry
[Index1
].Uint64
));
424 DEBUG ((DEBUG_VERBOSE
,"================\n"));
430 @param VtdIndex The VTd engine index.
433 InvalidatePageEntry (
437 if (mVtdUnitInformation
[VtdIndex
].HasDirtyContext
|| mVtdUnitInformation
[VtdIndex
].HasDirtyPages
) {
438 InvalidateVtdIOTLBGlobal (VtdIndex
);
440 mVtdUnitInformation
[VtdIndex
].HasDirtyContext
= FALSE
;
441 mVtdUnitInformation
[VtdIndex
].HasDirtyPages
= FALSE
;
444 #define VTD_PG_R BIT0
445 #define VTD_PG_W BIT1
446 #define VTD_PG_X BIT2
447 #define VTD_PG_EMT (BIT3 | BIT4 | BIT5)
448 #define VTD_PG_TM (BIT62)
450 #define VTD_PG_PS BIT7
452 #define PAGE_PROGATE_BITS (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VTD_PG_R)
454 #define PAGING_4K_MASK 0xFFF
455 #define PAGING_2M_MASK 0x1FFFFF
456 #define PAGING_1G_MASK 0x3FFFFFFF
458 #define PAGING_VTD_INDEX_MASK 0x1FF
460 #define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
461 #define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
462 #define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
472 PAGE_ATTRIBUTE Attribute
;
475 } PAGE_ATTRIBUTE_TABLE
;
477 PAGE_ATTRIBUTE_TABLE mPageAttributeTable
[] = {
478 {Page4K
, SIZE_4KB
, PAGING_4K_ADDRESS_MASK_64
},
479 {Page2M
, SIZE_2MB
, PAGING_2M_ADDRESS_MASK_64
},
480 {Page1G
, SIZE_1GB
, PAGING_1G_ADDRESS_MASK_64
},
484 Return length according to page attributes.
486 @param[in] PageAttributes The page attribute of the page entry.
488 @return The length of page entry.
491 PageAttributeToLength (
492 IN PAGE_ATTRIBUTE PageAttribute
496 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
497 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
498 return (UINTN
)mPageAttributeTable
[Index
].Length
;
505 Return page table entry to match the address.
507 @param[in] VtdIndex The index used to identify a VTd engine.
508 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.
509 @param[in] Address The address to be checked.
510 @param[out] PageAttributes The page attribute of the page entry.
512 @return The page entry.
515 GetSecondLevelPageTableEntry (
517 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
518 IN PHYSICAL_ADDRESS Address
,
519 OUT PAGE_ATTRIBUTE
*PageAttribute
531 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_VTD_INDEX_MASK
;
532 Index3
= ((UINTN
)Address
>> 30) & PAGING_VTD_INDEX_MASK
;
533 Index2
= ((UINTN
)Address
>> 21) & PAGING_VTD_INDEX_MASK
;
534 Index1
= ((UINTN
)Address
>> 12) & PAGING_VTD_INDEX_MASK
;
536 L4PageTable
= (UINT64
*)SecondLevelPagingEntry
;
537 if (L4PageTable
[Index4
] == 0) {
538 L4PageTable
[Index4
] = (UINT64
)(UINTN
)AllocateZeroPages (1);
539 if (L4PageTable
[Index4
] == 0) {
540 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4
));
542 *PageAttribute
= PageNone
;
545 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY
*)&L4PageTable
[Index4
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
546 FlushPageTableMemory (VtdIndex
, (UINTN
)&L4PageTable
[Index4
], sizeof(L4PageTable
[Index4
]));
549 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & PAGING_4K_ADDRESS_MASK_64
);
550 if (L3PageTable
[Index3
] == 0) {
551 L3PageTable
[Index3
] = (UINT64
)(UINTN
)AllocateZeroPages (1);
552 if (L3PageTable
[Index3
] == 0) {
553 DEBUG ((DEBUG_ERROR
,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4
, Index3
));
555 *PageAttribute
= PageNone
;
558 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY
*)&L3PageTable
[Index3
], EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
559 FlushPageTableMemory (VtdIndex
, (UINTN
)&L3PageTable
[Index3
], sizeof(L3PageTable
[Index3
]));
561 if ((L3PageTable
[Index3
] & VTD_PG_PS
) != 0) {
563 *PageAttribute
= Page1G
;
564 return &L3PageTable
[Index3
];
567 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & PAGING_4K_ADDRESS_MASK_64
);
568 if (L2PageTable
[Index2
] == 0) {
569 L2PageTable
[Index2
] = Address
& PAGING_2M_ADDRESS_MASK_64
;
570 SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY
*)&L2PageTable
[Index2
], 0);
571 L2PageTable
[Index2
] |= VTD_PG_PS
;
572 FlushPageTableMemory (VtdIndex
, (UINTN
)&L2PageTable
[Index2
], sizeof(L2PageTable
[Index2
]));
574 if ((L2PageTable
[Index2
] & VTD_PG_PS
) != 0) {
576 *PageAttribute
= Page2M
;
577 return &L2PageTable
[Index2
];
581 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & PAGING_4K_ADDRESS_MASK_64
);
582 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
583 *PageAttribute
= PageNone
;
586 *PageAttribute
= Page4K
;
587 return &L1PageTable
[Index1
];
591 Modify memory attributes of page entry.
593 @param[in] VtdIndex The index used to identify a VTd engine.
594 @param[in] PageEntry The page entry.
595 @param[in] IoMmuAccess The IOMMU access.
596 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
599 ConvertSecondLevelPageEntryAttribute (
601 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*PageEntry
,
602 IN UINT64 IoMmuAccess
,
603 OUT BOOLEAN
*IsModified
606 UINT64 CurrentPageEntry
;
609 CurrentPageEntry
= PageEntry
->Uint64
;
610 SetSecondLevelPagingEntryAttribute (PageEntry
, IoMmuAccess
);
611 FlushPageTableMemory (VtdIndex
, (UINTN
)PageEntry
, sizeof(*PageEntry
));
612 NewPageEntry
= PageEntry
->Uint64
;
613 if (CurrentPageEntry
!= NewPageEntry
) {
615 DEBUG ((DEBUG_VERBOSE
, "ConvertSecondLevelPageEntryAttribute 0x%lx", CurrentPageEntry
));
616 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
623 This function returns if there is need to split page entry.
625 @param[in] BaseAddress The base address to be checked.
626 @param[in] Length The length to be checked.
627 @param[in] PageAttribute The page attribute of the page entry.
629 @retval SplitAttributes on if there is need to split page entry.
633 IN PHYSICAL_ADDRESS BaseAddress
,
635 IN PAGE_ATTRIBUTE PageAttribute
638 UINT64 PageEntryLength
;
640 PageEntryLength
= PageAttributeToLength (PageAttribute
);
642 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
646 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
654 This function splits one page entry to small page entries.
656 @param[in] VtdIndex The index used to identify a VTd engine.
657 @param[in] PageEntry The page entry to be splitted.
658 @param[in] PageAttribute The page attribute of the page entry.
659 @param[in] SplitAttribute How to split the page entry.
661 @retval RETURN_SUCCESS The page entry is splitted.
662 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
663 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
666 SplitSecondLevelPage (
668 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*PageEntry
,
669 IN PAGE_ATTRIBUTE PageAttribute
,
670 IN PAGE_ATTRIBUTE SplitAttribute
674 UINT64
*NewPageEntry
;
677 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
679 if (PageAttribute
== Page2M
) {
683 ASSERT (SplitAttribute
== Page4K
);
684 if (SplitAttribute
== Page4K
) {
685 NewPageEntry
= AllocateZeroPages (1);
686 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
687 if (NewPageEntry
== NULL
) {
688 return RETURN_OUT_OF_RESOURCES
;
690 BaseAddress
= PageEntry
->Uint64
& PAGING_2M_ADDRESS_MASK_64
;
691 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
692 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | (PageEntry
->Uint64
& PAGE_PROGATE_BITS
);
694 FlushPageTableMemory (VtdIndex
, (UINTN
)NewPageEntry
, SIZE_4KB
);
696 PageEntry
->Uint64
= (UINT64
)(UINTN
)NewPageEntry
;
697 SetSecondLevelPagingEntryAttribute (PageEntry
, EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
698 FlushPageTableMemory (VtdIndex
, (UINTN
)PageEntry
, sizeof(*PageEntry
));
699 return RETURN_SUCCESS
;
701 return RETURN_UNSUPPORTED
;
703 } else if (PageAttribute
== Page1G
) {
706 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
708 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
709 if ((SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
)) {
710 NewPageEntry
= AllocateZeroPages (1);
711 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
712 if (NewPageEntry
== NULL
) {
713 return RETURN_OUT_OF_RESOURCES
;
715 BaseAddress
= PageEntry
->Uint64
& PAGING_1G_ADDRESS_MASK_64
;
716 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
717 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_2MB
* Index
) | VTD_PG_PS
| (PageEntry
->Uint64
& PAGE_PROGATE_BITS
);
719 FlushPageTableMemory (VtdIndex
, (UINTN
)NewPageEntry
, SIZE_4KB
);
721 PageEntry
->Uint64
= (UINT64
)(UINTN
)NewPageEntry
;
722 SetSecondLevelPagingEntryAttribute (PageEntry
, EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
723 FlushPageTableMemory (VtdIndex
, (UINTN
)PageEntry
, sizeof(*PageEntry
));
724 return RETURN_SUCCESS
;
726 return RETURN_UNSUPPORTED
;
729 return RETURN_UNSUPPORTED
;
734 Set VTd attribute for a system memory on second level page entry
736 @param[in] VtdIndex The index used to identify a VTd engine.
737 @param[in] DomainIdentifier The domain ID of the source.
738 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.
739 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
740 @param[in] Length The length of device memory address to be used as the DMA memory.
741 @param[in] IoMmuAccess The IOMMU access.
743 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
744 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
745 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
746 @retval EFI_INVALID_PARAMETER Length is 0.
747 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
748 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
749 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
750 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
751 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
754 SetSecondLevelPagingAttribute (
756 IN UINT16 DomainIdentifier
,
757 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
758 IN UINT64 BaseAddress
,
760 IN UINT64 IoMmuAccess
763 VTD_SECOND_LEVEL_PAGING_ENTRY
*PageEntry
;
764 PAGE_ATTRIBUTE PageAttribute
;
765 UINTN PageEntryLength
;
766 PAGE_ATTRIBUTE SplitAttribute
;
768 BOOLEAN IsEntryModified
;
770 DEBUG ((DEBUG_VERBOSE
,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x%016lx : %x) \n", VtdIndex
, BaseAddress
, Length
, IoMmuAccess
));
771 DEBUG ((DEBUG_VERBOSE
," SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry
));
773 if (BaseAddress
!= ALIGN_VALUE(BaseAddress
, SIZE_4KB
)) {
774 DEBUG ((DEBUG_ERROR
, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
775 return EFI_UNSUPPORTED
;
777 if (Length
!= ALIGN_VALUE(Length
, SIZE_4KB
)) {
778 DEBUG ((DEBUG_ERROR
, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
779 return EFI_UNSUPPORTED
;
782 while (Length
!= 0) {
783 PageEntry
= GetSecondLevelPageTableEntry (VtdIndex
, SecondLevelPagingEntry
, BaseAddress
, &PageAttribute
);
784 if (PageEntry
== NULL
) {
785 DEBUG ((DEBUG_ERROR
, "PageEntry - NULL\n"));
786 return RETURN_UNSUPPORTED
;
788 PageEntryLength
= PageAttributeToLength (PageAttribute
);
789 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageAttribute
);
790 if (SplitAttribute
== PageNone
) {
791 ConvertSecondLevelPageEntryAttribute (VtdIndex
, PageEntry
, IoMmuAccess
, &IsEntryModified
);
792 if (IsEntryModified
) {
793 mVtdUnitInformation
[VtdIndex
].HasDirtyPages
= TRUE
;
796 // Convert success, move to next
798 BaseAddress
+= PageEntryLength
;
799 Length
-= PageEntryLength
;
801 Status
= SplitSecondLevelPage (VtdIndex
, PageEntry
, PageAttribute
, SplitAttribute
);
802 if (RETURN_ERROR (Status
)) {
803 DEBUG ((DEBUG_ERROR
, "SplitSecondLevelPage - %r\n", Status
));
804 return RETURN_UNSUPPORTED
;
806 mVtdUnitInformation
[VtdIndex
].HasDirtyPages
= TRUE
;
808 // Just split current page
809 // Convert success in next around
818 Set VTd attribute for a system memory.
820 @param[in] VtdIndex The index used to identify a VTd engine.
821 @param[in] DomainIdentifier The domain ID of the source.
822 @param[in] SecondLevelPagingEntry The second level paging entry in VTd table for the device.
823 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
824 @param[in] Length The length of device memory address to be used as the DMA memory.
825 @param[in] IoMmuAccess The IOMMU access.
827 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
828 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
829 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
830 @retval EFI_INVALID_PARAMETER Length is 0.
831 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
832 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
833 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
834 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
835 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
840 IN UINT16 DomainIdentifier
,
841 IN VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
,
842 IN UINT64 BaseAddress
,
844 IN UINT64 IoMmuAccess
848 Status
= EFI_NOT_FOUND
;
849 if (SecondLevelPagingEntry
!= NULL
) {
850 Status
= SetSecondLevelPagingAttribute (VtdIndex
, DomainIdentifier
, SecondLevelPagingEntry
, BaseAddress
, Length
, IoMmuAccess
);
856 Set VTd attribute for a system memory.
858 @param[in] Segment The Segment used to identify a VTd engine.
859 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
860 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
861 @param[in] Length The length of device memory address to be used as the DMA memory.
862 @param[in] IoMmuAccess The IOMMU access.
864 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
865 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
866 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
867 @retval EFI_INVALID_PARAMETER Length is 0.
868 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
869 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
870 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
871 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
872 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
877 IN VTD_SOURCE_ID SourceId
,
878 IN UINT64 BaseAddress
,
880 IN UINT64 IoMmuAccess
885 VTD_EXT_CONTEXT_ENTRY
*ExtContextEntry
;
886 VTD_CONTEXT_ENTRY
*ContextEntry
;
887 VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
;
890 UINT16 DomainIdentifier
;
892 SecondLevelPagingEntry
= NULL
;
894 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
));
896 VtdIndex
= FindVtdIndexByPciDevice (Segment
, SourceId
, &ExtContextEntry
, &ContextEntry
);
897 if (VtdIndex
== (UINTN
)-1) {
898 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
));
899 return EFI_DEVICE_ERROR
;
902 PciDataIndex
= GetPciDataIndex (VtdIndex
, Segment
, SourceId
);
903 mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[PciDataIndex
].AccessCount
++;
905 // DomainId should not be 0.
907 DomainIdentifier
= (UINT16
)(PciDataIndex
+ 1);
909 if (ExtContextEntry
!= NULL
) {
910 if (ExtContextEntry
->Bits
.Present
== 0) {
911 SecondLevelPagingEntry
= CreateSecondLevelPagingEntry (VtdIndex
, 0);
912 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
));
913 Pt
= (UINT64
)RShiftU64 ((UINT64
)(UINTN
)SecondLevelPagingEntry
, 12);
915 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
916 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
917 ExtContextEntry
->Bits
.DomainIdentifier
= DomainIdentifier
;
918 ExtContextEntry
->Bits
.Present
= 1;
919 FlushPageTableMemory (VtdIndex
, (UINTN
)ExtContextEntry
, sizeof(*ExtContextEntry
));
920 DumpDmarExtContextEntryTable (mVtdUnitInformation
[VtdIndex
].ExtRootEntryTable
);
921 mVtdUnitInformation
[VtdIndex
].HasDirtyContext
= TRUE
;
923 SecondLevelPagingEntry
= (VOID
*)(UINTN
)VTD_64BITS_ADDRESS(ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
, ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
);
924 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
));
926 } else if (ContextEntry
!= NULL
) {
927 if (ContextEntry
->Bits
.Present
== 0) {
928 SecondLevelPagingEntry
= CreateSecondLevelPagingEntry (VtdIndex
, 0);
929 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
));
930 Pt
= (UINT64
)RShiftU64 ((UINT64
)(UINTN
)SecondLevelPagingEntry
, 12);
932 ContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
933 ContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
934 ContextEntry
->Bits
.DomainIdentifier
= DomainIdentifier
;
935 ContextEntry
->Bits
.Present
= 1;
936 FlushPageTableMemory (VtdIndex
, (UINTN
)ContextEntry
, sizeof(*ContextEntry
));
937 DumpDmarContextEntryTable (mVtdUnitInformation
[VtdIndex
].RootEntryTable
);
938 mVtdUnitInformation
[VtdIndex
].HasDirtyContext
= TRUE
;
940 SecondLevelPagingEntry
= (VOID
*)(UINTN
)VTD_64BITS_ADDRESS(ContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
, ContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
);
941 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
));
946 // Do not update FixedSecondLevelPagingEntry
948 if (SecondLevelPagingEntry
!= mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
) {
949 Status
= SetPageAttribute (
952 SecondLevelPagingEntry
,
957 if (EFI_ERROR (Status
)) {
958 DEBUG ((DEBUG_ERROR
,"SetPageAttribute - %r\n", Status
));
963 InvalidatePageEntry (VtdIndex
);
969 Always enable the VTd page attribute for the device.
971 @param[in] Segment The Segment used to identify a VTd engine.
972 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
974 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.
977 AlwaysEnablePageAttribute (
979 IN VTD_SOURCE_ID SourceId
983 VTD_EXT_CONTEXT_ENTRY
*ExtContextEntry
;
984 VTD_CONTEXT_ENTRY
*ContextEntry
;
985 VTD_SECOND_LEVEL_PAGING_ENTRY
*SecondLevelPagingEntry
;
988 DEBUG ((DEBUG_INFO
,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\n", Segment
, SourceId
.Bits
.Bus
, SourceId
.Bits
.Device
, SourceId
.Bits
.Function
));
990 VtdIndex
= FindVtdIndexByPciDevice (Segment
, SourceId
, &ExtContextEntry
, &ContextEntry
);
991 if (VtdIndex
== (UINTN
)-1) {
992 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
));
993 return EFI_DEVICE_ERROR
;
996 if (mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
== 0) {
997 DEBUG((DEBUG_INFO
, "CreateSecondLevelPagingEntry - %d\n", VtdIndex
));
998 mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
= CreateSecondLevelPagingEntry (VtdIndex
, EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
);
1001 SecondLevelPagingEntry
= mVtdUnitInformation
[VtdIndex
].FixedSecondLevelPagingEntry
;
1002 Pt
= (UINT64
)RShiftU64 ((UINT64
)(UINTN
)SecondLevelPagingEntry
, 12);
1003 if (ExtContextEntry
!= NULL
) {
1004 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
1005 ExtContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
1006 ExtContextEntry
->Bits
.DomainIdentifier
= ((1 << (UINT8
)((UINTN
)mVtdUnitInformation
[VtdIndex
].CapReg
.Bits
.ND
* 2 + 4)) - 1);
1007 ExtContextEntry
->Bits
.Present
= 1;
1008 FlushPageTableMemory (VtdIndex
, (UINTN
)ExtContextEntry
, sizeof(*ExtContextEntry
));
1009 } else if (ContextEntry
!= NULL
) {
1010 ContextEntry
->Bits
.SecondLevelPageTranslationPointerLo
= (UINT32
) Pt
;
1011 ContextEntry
->Bits
.SecondLevelPageTranslationPointerHi
= (UINT32
) RShiftU64(Pt
, 20);
1012 ContextEntry
->Bits
.DomainIdentifier
= ((1 << (UINT8
)((UINTN
)mVtdUnitInformation
[VtdIndex
].CapReg
.Bits
.ND
* 2 + 4)) - 1);
1013 ContextEntry
->Bits
.Present
= 1;
1014 FlushPageTableMemory (VtdIndex
, (UINTN
)ContextEntry
, sizeof(*ContextEntry
));