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