1 /** @file
2 
3   Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #include <Uefi.h>
9 #include <PiPei.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/HobLib.h>
14 #include <IndustryStandard/Vtd.h>
15 #include <Ppi/VtdInfo.h>
16 
17 #include "IntelVTdPmrPei.h"
18 
19 /**
20   Dump DMAR DeviceScopeEntry.
21 
22   @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
23 **/
24 VOID
DumpDmarDeviceScopeEntry(IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER * DmarDeviceScopeEntry)25 DumpDmarDeviceScopeEntry (
26   IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
27   )
28 {
29   UINTN   PciPathNumber;
30   UINTN   PciPathIndex;
31   EFI_ACPI_DMAR_PCI_PATH  *PciPath;
32 
33   if (DmarDeviceScopeEntry == NULL) {
34     return;
35   }
36 
37   DEBUG ((DEBUG_INFO,
38     "    *************************************************************************\n"
39     ));
40   DEBUG ((DEBUG_INFO,
41     "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
42     ));
43   DEBUG ((DEBUG_INFO,
44     "    *************************************************************************\n"
45     ));
46   DEBUG ((DEBUG_INFO,
47     (sizeof(UINTN) == sizeof(UINT64)) ?
48     "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
49     "    DMAR Device Scope Entry address ...................... 0x%08x\n",
50     DmarDeviceScopeEntry
51     ));
52   DEBUG ((DEBUG_INFO,
53     "      Device Scope Entry Type ............................ 0x%02x\n",
54     DmarDeviceScopeEntry->Type
55     ));
56   switch (DmarDeviceScopeEntry->Type) {
57   case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
58     DEBUG ((DEBUG_INFO,
59       "        PCI Endpoint Device\n"
60       ));
61     break;
62   case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
63     DEBUG ((DEBUG_INFO,
64       "        PCI Sub-hierachy\n"
65       ));
66     break;
67   default:
68     break;
69   }
70   DEBUG ((DEBUG_INFO,
71     "      Length ............................................. 0x%02x\n",
72     DmarDeviceScopeEntry->Length
73     ));
74   DEBUG ((DEBUG_INFO,
75     "      Enumeration ID ..................................... 0x%02x\n",
76     DmarDeviceScopeEntry->EnumerationId
77     ));
78   DEBUG ((DEBUG_INFO,
79     "      Starting Bus Number ................................ 0x%02x\n",
80     DmarDeviceScopeEntry->StartBusNumber
81     ));
82 
83   PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
84   PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
85   for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
86     DEBUG ((DEBUG_INFO,
87       "      Device ............................................. 0x%02x\n",
88       PciPath[PciPathIndex].Device
89       ));
90     DEBUG ((DEBUG_INFO,
91       "      Function ........................................... 0x%02x\n",
92       PciPath[PciPathIndex].Function
93       ));
94   }
95 
96   DEBUG ((DEBUG_INFO,
97     "    *************************************************************************\n\n"
98     ));
99 
100   return;
101 }
102 
103 /**
104   Dump DMAR RMRR table.
105 
106   @param[in]  Rmrr  DMAR RMRR table
107 **/
108 VOID
DumpDmarRmrr(IN EFI_ACPI_DMAR_RMRR_HEADER * Rmrr)109 DumpDmarRmrr (
110   IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
111   )
112 {
113   EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
114   INTN                                    RmrrLen;
115 
116   if (Rmrr == NULL) {
117     return;
118   }
119 
120   DEBUG ((DEBUG_INFO,
121     "  ***************************************************************************\n"
122     ));
123   DEBUG ((DEBUG_INFO,
124     "  *       Reserved Memory Region Reporting Structure                        *\n"
125     ));
126   DEBUG ((DEBUG_INFO,
127     "  ***************************************************************************\n"
128     ));
129   DEBUG ((DEBUG_INFO,
130     (sizeof(UINTN) == sizeof(UINT64)) ?
131     "  RMRR address ........................................... 0x%016lx\n" :
132     "  RMRR address ........................................... 0x%08x\n",
133     Rmrr
134     ));
135   DEBUG ((DEBUG_INFO,
136     "    Type ................................................. 0x%04x\n",
137     Rmrr->Header.Type
138     ));
139   DEBUG ((DEBUG_INFO,
140     "    Length ............................................... 0x%04x\n",
141     Rmrr->Header.Length
142     ));
143   DEBUG ((DEBUG_INFO,
144     "    Segment Number ....................................... 0x%04x\n",
145     Rmrr->SegmentNumber
146     ));
147   DEBUG ((DEBUG_INFO,
148     "    Reserved Memory Region Base Address .................. 0x%016lx\n",
149     Rmrr->ReservedMemoryRegionBaseAddress
150     ));
151   DEBUG ((DEBUG_INFO,
152     "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
153     Rmrr->ReservedMemoryRegionLimitAddress
154     ));
155 
156   RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
157   DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
158   while (RmrrLen > 0) {
159     DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
160     RmrrLen -= DmarDeviceScopeEntry->Length;
161     DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
162   }
163 
164   DEBUG ((DEBUG_INFO,
165     "  ***************************************************************************\n\n"
166     ));
167 
168   return;
169 }
170 
171 /**
172   Dump DMAR DRHD table.
173 
174   @param[in]  Drhd  DMAR DRHD table
175 **/
176 VOID
DumpDmarDrhd(IN EFI_ACPI_DMAR_DRHD_HEADER * Drhd)177 DumpDmarDrhd (
178   IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
179   )
180 {
181   EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
182   INTN                                    DrhdLen;
183 
184   if (Drhd == NULL) {
185     return;
186   }
187 
188   DEBUG ((DEBUG_INFO,
189     "  ***************************************************************************\n"
190     ));
191   DEBUG ((DEBUG_INFO,
192     "  *       DMA-Remapping Hardware Definition Structure                       *\n"
193     ));
194   DEBUG ((DEBUG_INFO,
195     "  ***************************************************************************\n"
196     ));
197   DEBUG ((DEBUG_INFO,
198     (sizeof(UINTN) == sizeof(UINT64)) ?
199     "  DRHD address ........................................... 0x%016lx\n" :
200     "  DRHD address ........................................... 0x%08x\n",
201     Drhd
202     ));
203   DEBUG ((DEBUG_INFO,
204     "    Type ................................................. 0x%04x\n",
205     Drhd->Header.Type
206     ));
207   DEBUG ((DEBUG_INFO,
208     "    Length ............................................... 0x%04x\n",
209     Drhd->Header.Length
210     ));
211   DEBUG ((DEBUG_INFO,
212     "    Flags ................................................ 0x%02x\n",
213     Drhd->Flags
214     ));
215   DEBUG ((DEBUG_INFO,
216     "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
217     Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
218     ));
219   DEBUG ((DEBUG_INFO,
220     "    Segment Number ....................................... 0x%04x\n",
221     Drhd->SegmentNumber
222     ));
223   DEBUG ((DEBUG_INFO,
224     "    Register Base Address ................................ 0x%016lx\n",
225     Drhd->RegisterBaseAddress
226     ));
227 
228   DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
229   DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
230   while (DrhdLen > 0) {
231     DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
232     DrhdLen -= DmarDeviceScopeEntry->Length;
233     DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
234   }
235 
236   DEBUG ((DEBUG_INFO,
237     "  ***************************************************************************\n\n"
238     ));
239 
240   return;
241 }
242 
243 /**
244   Dump DMAR ACPI table.
245 
246   @param[in]  Dmar  DMAR ACPI table
247 **/
248 VOID
DumpAcpiDMAR(IN EFI_ACPI_DMAR_HEADER * Dmar)249 DumpAcpiDMAR (
250   IN EFI_ACPI_DMAR_HEADER  *Dmar
251   )
252 {
253   EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
254   INTN                  DmarLen;
255 
256   if (Dmar == NULL) {
257     return;
258   }
259 
260   //
261   // Dump Dmar table
262   //
263   DEBUG ((DEBUG_INFO,
264     "*****************************************************************************\n"
265     ));
266   DEBUG ((DEBUG_INFO,
267     "*         DMAR Table                                                        *\n"
268     ));
269   DEBUG ((DEBUG_INFO,
270     "*****************************************************************************\n"
271     ));
272 
273   DEBUG ((DEBUG_INFO,
274     (sizeof(UINTN) == sizeof(UINT64)) ?
275     "DMAR address ............................................. 0x%016lx\n" :
276     "DMAR address ............................................. 0x%08x\n",
277     Dmar
278     ));
279 
280   DEBUG ((DEBUG_INFO,
281     "  Table Contents:\n"
282     ));
283   DEBUG ((DEBUG_INFO,
284     "    Host Address Width ................................... 0x%02x\n",
285     Dmar->HostAddressWidth
286     ));
287   DEBUG ((DEBUG_INFO,
288     "    Flags ................................................ 0x%02x\n",
289     Dmar->Flags
290     ));
291   DEBUG ((DEBUG_INFO,
292     "      INTR_REMAP ......................................... 0x%02x\n",
293     Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
294     ));
295   DEBUG ((DEBUG_INFO,
296     "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
297     Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
298     ));
299   DEBUG ((DEBUG_INFO,
300     "      DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",
301     Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG
302     ));
303 
304   DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
305   DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
306   while (DmarLen > 0) {
307     switch (DmarHeader->Type) {
308     case EFI_ACPI_DMAR_TYPE_DRHD:
309       DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
310       break;
311     case EFI_ACPI_DMAR_TYPE_RMRR:
312       DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
313       break;
314     default:
315       break;
316     }
317     DmarLen -= DmarHeader->Length;
318     DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
319   }
320 
321   DEBUG ((DEBUG_INFO,
322     "*****************************************************************************\n\n"
323     ));
324 
325   return;
326 }
327 
328 /**
329   Get VTd engine number.
330 
331   @param[in]  AcpiDmarTable  DMAR ACPI table
332 
333   @return the VTd engine number.
334 **/
335 UINTN
GetVtdEngineNumber(IN EFI_ACPI_DMAR_HEADER * AcpiDmarTable)336 GetVtdEngineNumber (
337   IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
338   )
339 {
340   EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
341   UINTN                                             VtdIndex;
342 
343   VtdIndex = 0;
344   DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
345   while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
346     switch (DmarHeader->Type) {
347     case EFI_ACPI_DMAR_TYPE_DRHD:
348       VtdIndex++;
349       break;
350     default:
351       break;
352     }
353     DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
354   }
355   return VtdIndex ;
356 }
357 
358 /**
359   Process DMAR DHRD table.
360 
361   @param[in]  VTdInfo   The VTd engine context information.
362   @param[in]  VtdIndex  The index of VTd engine.
363   @param[in]  DmarDrhd  The DRHD table.
364 **/
365 VOID
ProcessDhrd(IN VTD_INFO * VTdInfo,IN UINTN VtdIndex,IN EFI_ACPI_DMAR_DRHD_HEADER * DmarDrhd)366 ProcessDhrd (
367   IN VTD_INFO                   *VTdInfo,
368   IN UINTN                      VtdIndex,
369   IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
370   )
371 {
372   DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
373   VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
374 }
375 
376 /**
377   Parse DMAR DRHD table.
378 
379   @param[in]  AcpiDmarTable  DMAR ACPI table
380 
381   @return EFI_SUCCESS  The DMAR DRHD table is parsed.
382 **/
383 EFI_STATUS
ParseDmarAcpiTableDrhd(IN EFI_ACPI_DMAR_HEADER * AcpiDmarTable)384 ParseDmarAcpiTableDrhd (
385   IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
386   )
387 {
388   EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
389   UINTN                                             VtdUnitNumber;
390   UINTN                                             VtdIndex;
391   VTD_INFO                                          *VTdInfo;
392 
393   VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);
394   if (VtdUnitNumber == 0) {
395     return EFI_UNSUPPORTED;
396   }
397 
398   VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
399   ASSERT(VTdInfo != NULL);
400   if (VTdInfo == NULL) {
401     return EFI_OUT_OF_RESOURCES;
402   }
403 
404   //
405   // Initialize the engine mask to all.
406   //
407   VTdInfo->AcpiDmarTable    = AcpiDmarTable;
408   VTdInfo->EngineMask       = LShiftU64 (1, VtdUnitNumber) - 1;
409   VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
410   VTdInfo->VTdEngineCount   = VtdUnitNumber;
411 
412   VtdIndex = 0;
413   DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
414   while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
415     switch (DmarHeader->Type) {
416     case EFI_ACPI_DMAR_TYPE_DRHD:
417       ASSERT (VtdIndex < VtdUnitNumber);
418       ProcessDhrd (VTdInfo, VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
419       VtdIndex++;
420 
421       break;
422 
423     default:
424       break;
425     }
426     DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
427   }
428   ASSERT (VtdIndex == VtdUnitNumber);
429 
430   return EFI_SUCCESS;
431 }
432 
433 /**
434   Return the VTd engine index according to the Segment and DevScopeEntry.
435 
436   @param AcpiDmarTable   DMAR ACPI table
437   @param Segment         The segment of the VTd engine
438   @param DevScopeEntry   The DevScopeEntry of the VTd engine
439 
440   @return The VTd engine index according to the Segment and DevScopeEntry.
441   @retval -1  The VTd engine is not found.
442 **/
443 UINTN
GetVTdEngineFromDevScopeEntry(IN EFI_ACPI_DMAR_HEADER * AcpiDmarTable,IN UINT16 Segment,IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER * DevScopeEntry)444 GetVTdEngineFromDevScopeEntry (
445   IN  EFI_ACPI_DMAR_HEADER                        *AcpiDmarTable,
446   IN  UINT16                                      Segment,
447   IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
448   )
449 {
450   EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
451   UINTN                                             VtdIndex;
452   EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;
453   EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;
454 
455   VtdIndex = 0;
456   DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
457   while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
458     switch (DmarHeader->Type) {
459     case EFI_ACPI_DMAR_TYPE_DRHD:
460       DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
461       if (DmarDrhd->SegmentNumber != Segment) {
462         // Mismatch
463         break;
464       }
465       if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
466           ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
467         // No DevScopeEntry
468         // Do not handle PCI_ALL
469         break;
470       }
471       ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
472       while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
473         if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
474             (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
475           return VtdIndex;
476         }
477         ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
478       }
479       break;
480     default:
481       break;
482     }
483     DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
484   }
485   return (UINTN)-1;
486 }
487 
488 /**
489   Process DMAR RMRR table.
490 
491   @param[in]  VTdInfo   The VTd engine context information.
492   @param[in]  DmarRmrr  The RMRR table.
493 **/
494 VOID
ProcessRmrr(IN VTD_INFO * VTdInfo,IN EFI_ACPI_DMAR_RMRR_HEADER * DmarRmrr)495 ProcessRmrr (
496   IN VTD_INFO                   *VTdInfo,
497   IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
498   )
499 {
500   EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
501   UINTN                                             VTdIndex;
502   UINT64                                            RmrrMask;
503   UINTN                                             LowBottom;
504   UINTN                                             LowTop;
505   UINTN                                             HighBottom;
506   UINT64                                            HighTop;
507   EFI_ACPI_DMAR_HEADER                              *AcpiDmarTable;
508 
509   AcpiDmarTable = VTdInfo->AcpiDmarTable;
510 
511   DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
512 
513   if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
514       (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
515     return ;
516   }
517 
518   DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
519   while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
520     ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
521 
522     VTdIndex = GetVTdEngineFromDevScopeEntry (AcpiDmarTable, DmarRmrr->SegmentNumber, DmarDevScopeEntry);
523     if (VTdIndex != (UINTN)-1) {
524       RmrrMask = LShiftU64 (1, VTdIndex);
525 
526       LowBottom = 0;
527       LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
528       HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
529       HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
530 
531       SetDmaProtectedRange (
532         VTdInfo,
533         RmrrMask,
534         0,
535         (UINT32)(LowTop - LowBottom),
536         HighBottom,
537         HighTop - HighBottom
538         );
539 
540       //
541       // Remove the engine from the engine mask.
542       // The assumption is that any other PEI driver does not access
543       // the device covered by this engine.
544       //
545       VTdInfo->EngineMask = VTdInfo->EngineMask & (~RmrrMask);
546     }
547 
548     DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
549   }
550 }
551 
552 /**
553   Parse DMAR DRHD table.
554 
555   @param[in]  VTdInfo   The VTd engine context information.
556 **/
557 VOID
ParseDmarAcpiTableRmrr(IN VTD_INFO * VTdInfo)558 ParseDmarAcpiTableRmrr (
559   IN VTD_INFO                    *VTdInfo
560   )
561 {
562   EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
563   EFI_ACPI_DMAR_STRUCTURE_HEADER          *DmarHeader;
564 
565   AcpiDmarTable = VTdInfo->AcpiDmarTable;
566 
567   DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
568   while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
569     switch (DmarHeader->Type) {
570     case EFI_ACPI_DMAR_TYPE_RMRR:
571       ProcessRmrr (VTdInfo, (EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
572       break;
573     default:
574       break;
575     }
576     DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
577   }
578 }
579