[edk2] [PATCH V2 1/2] IntelSiliconPkg/VtdPmrPei: Add premem support.

Jiewen Yao posted 2 patches 7 years, 1 month ago
There is a newer version of this series
[edk2] [PATCH V2 1/2] IntelSiliconPkg/VtdPmrPei: Add premem support.
Posted by Jiewen Yao 7 years, 1 month ago
Remove memory discovered dependency to support both premem
VTD_INFO_PPI and postmem VTD_INFO_PPI.

If VTD_INFO_PPI is installed before memory is ready, this
driver protects all memory region.
If VTD_INFO_PPI is installed or reinstalled after memory
is ready, this driver allocates DMA buffer and protect rest.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c        | 580 ++++++++++++++
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c      | 130 ++-
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c   | 846 +++++++-------------
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h   |  93 +++
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf |  11 +-
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c           | 293 +++++++
 6 files changed, 1356 insertions(+), 597 deletions(-)

diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
new file mode 100644
index 0000000..891efa6
--- /dev/null
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
@@ -0,0 +1,580 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Dump DMAR DeviceScopeEntry.
+
+  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
+**/
+VOID
+DumpDmarDeviceScopeEntry (
+  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
+  )
+{
+  UINTN   PciPathNumber;
+  UINTN   PciPathIndex;
+  EFI_ACPI_DMAR_PCI_PATH  *PciPath;
+
+  if (DmarDeviceScopeEntry == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
+    "    DMAR Device Scope Entry address ...................... 0x%08x\n",
+    DmarDeviceScopeEntry
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Device Scope Entry Type ............................ 0x%02x\n",
+    DmarDeviceScopeEntry->Type
+    ));
+  switch (DmarDeviceScopeEntry->Type) {
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Endpoint Device\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Sub-hierachy\n"
+      ));
+    break;
+  default:
+    break;
+  }
+  DEBUG ((DEBUG_INFO,
+    "      Length ............................................. 0x%02x\n",
+    DmarDeviceScopeEntry->Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Enumeration ID ..................................... 0x%02x\n",
+    DmarDeviceScopeEntry->EnumerationId
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Starting Bus Number ................................ 0x%02x\n",
+    DmarDeviceScopeEntry->StartBusNumber
+    ));
+
+  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
+  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
+  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
+    DEBUG ((DEBUG_INFO,
+      "      Device ............................................. 0x%02x\n",
+      PciPath[PciPathIndex].Device
+      ));
+    DEBUG ((DEBUG_INFO,
+      "      Function ........................................... 0x%02x\n",
+      PciPath[PciPathIndex].Function
+      ));
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR RMRR table.
+
+  @param[in]  Rmrr  DMAR RMRR table
+**/
+VOID
+DumpDmarRmrr (
+  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    RmrrLen;
+
+  if (Rmrr == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       Reserved Memory Region Reporting Structure                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  RMRR address ........................................... 0x%016lx\n" :
+    "  RMRR address ........................................... 0x%08x\n",
+    Rmrr
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Rmrr->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Rmrr->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Rmrr->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Base Address .................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionBaseAddress
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionLimitAddress
+    ));
+
+  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
+  while (RmrrLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    RmrrLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR DRHD table.
+
+  @param[in]  Drhd  DMAR DRHD table
+**/
+VOID
+DumpDmarDrhd (
+  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    DrhdLen;
+
+  if (Drhd == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  DRHD address ........................................... 0x%016lx\n" :
+    "  DRHD address ........................................... 0x%08x\n",
+    Drhd
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Drhd->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Drhd->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Drhd->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
+    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Drhd->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Register Base Address ................................ 0x%016lx\n",
+    Drhd->RegisterBaseAddress
+    ));
+
+  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
+  while (DrhdLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    DrhdLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+  INTN                  DmarLen;
+
+  if (Dmar == NULL) {
+    return;
+  }
+
+  //
+  // Dump Dmar table
+  //
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*         DMAR Table                                                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "DMAR address ............................................. 0x%016lx\n" :
+    "DMAR address ............................................. 0x%08x\n",
+    Dmar
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  Table Contents:\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Host Address Width ................................... 0x%02x\n",
+    Dmar->HostAddressWidth
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Dmar->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INTR_REMAP ......................................... 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
+    ));
+
+  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
+  while (DmarLen > 0) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarLen -= DmarHeader->Length;
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Get VTd engine number.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return the VTd engine number.
+**/
+UINTN
+GetVtdEngineNumber (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      VtdIndex++;
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return VtdIndex ;
+}
+
+/**
+  Process DMAR DHRD table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+  @param[in]  VtdIndex  The index of VTd engine.
+  @param[in]  DmarDrhd  The DRHD table.
+**/
+VOID
+ProcessDhrd (
+  IN VTD_INFO                   *VTdInfo,
+  IN UINTN                      VtdIndex,
+  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
+  )
+{
+  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
+  VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdUnitNumber;
+  UINTN                                             VtdIndex;
+  VTD_INFO                                          *VTdInfo;
+
+  VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);
+  if (VtdUnitNumber == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
+  ASSERT(VTdInfo != NULL);
+  if (VTdInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the engine mask to all.
+  //
+  VTdInfo->AcpiDmarTable    = AcpiDmarTable;
+  VTdInfo->EngineMask       = LShiftU64 (1, VtdUnitNumber) - 1;
+  VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
+  VTdInfo->VTdEngineCount   = VtdUnitNumber;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      ASSERT (VtdIndex < VtdUnitNumber);
+      ProcessDhrd (VTdInfo, VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      VtdIndex++;
+
+      break;
+
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  ASSERT (VtdIndex == VtdUnitNumber);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Return the VTd engine index according to the Segment and DevScopeEntry.
+
+  @param AcpiDmarTable   DMAR ACPI table
+  @param Segment         The segment of the VTd engine
+  @param DevScopeEntry   The DevScopeEntry of the VTd engine
+
+  @return The VTd engine index according to the Segment and DevScopeEntry.
+  @retval -1  The VTd engine is not found.
+**/
+UINTN
+GetVTdEngineFromDevScopeEntry (
+  IN  EFI_ACPI_DMAR_HEADER                        *AcpiDmarTable,
+  IN  UINT16                                      Segment,
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+  EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
+      if (DmarDrhd->SegmentNumber != Segment) {
+        // Mismatch
+        break;
+      }
+      if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
+          ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
+        // No DevScopeEntry
+        // Do not handle PCI_ALL
+        break;
+      }
+      ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
+      while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
+        if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
+            (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
+          return VtdIndex;
+        }
+        ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
+      }
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return (UINTN)-1;
+}
+
+/**
+  Process DMAR RMRR table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+  @param[in]  DmarRmrr  The RMRR table.
+**/
+VOID
+ProcessRmrr (
+  IN VTD_INFO                   *VTdInfo,
+  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINTN                                             VTdIndex;
+  UINT64                                            RmrrMask;
+  UINTN                                             LowBottom;
+  UINTN                                             LowTop;
+  UINTN                                             HighBottom;
+  UINT64                                            HighTop;
+  EFI_ACPI_DMAR_HEADER                              *AcpiDmarTable;
+
+  AcpiDmarTable = VTdInfo->AcpiDmarTable;
+
+  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
+
+  if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
+      (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
+    return ;
+  }
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
+    ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
+
+    VTdIndex = GetVTdEngineFromDevScopeEntry (AcpiDmarTable, DmarRmrr->SegmentNumber, DmarDevScopeEntry);
+    if (VTdIndex != (UINTN)-1) {
+      RmrrMask = LShiftU64 (1, VTdIndex);
+
+      LowBottom = 0;
+      LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
+      HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
+      HighTop = GetTopMemory ();
+
+      SetDmaProtectedRange (
+        VTdInfo,
+        RmrrMask,
+        0,
+        (UINT32)(LowTop - LowBottom),
+        HighBottom,
+        HighTop - HighBottom
+        );
+
+      //
+      // Remove the engine from the engine mask.
+      // The assumption is that any other PEI driver does not access
+      // the device covered by this engine.
+      //
+      VTdInfo->EngineMask = VTdInfo->EngineMask & (~RmrrMask);
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+  IN VTD_INFO                    *VTdInfo
+  )
+{
+  EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
+  EFI_ACPI_DMAR_STRUCTURE_HEADER          *DmarHeader;
+
+  AcpiDmarTable = VTdInfo->AcpiDmarTable;
+
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      ProcessRmrr (VTdInfo, (EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+}
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
index 6179dfe..000a81b 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
@@ -22,17 +22,17 @@
 
 #include "IntelVTdPmrPei.h"
 
-extern VTD_INFO                *mVTdInfo;
-
 /**
   Get protected low memory alignment.
 
+  @param HostAddressWidth   The host address width.
   @param VtdUnitBaseAddress The base address of the VTd engine.
 
   @return protected low memory alignment.
 **/
 UINT32
 GetPlmrAlignment (
+  IN UINT8         HostAddressWidth,
   IN UINTN         VtdUnitBaseAddress
   )
 {
@@ -48,19 +48,18 @@ GetPlmrAlignment (
 /**
   Get protected high memory alignment.
 
+  @param HostAddressWidth   The host address width.
   @param VtdUnitBaseAddress The base address of the VTd engine.
 
   @return protected high memory alignment.
 **/
 UINT64
 GetPhmrAlignment (
+  IN UINT8         HostAddressWidth,
   IN UINTN         VtdUnitBaseAddress
   )
 {
   UINT64        Data64;
-  UINT8         HostAddressWidth;
-
-  HostAddressWidth = mVTdInfo->HostAddressWidth;
 
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
   Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
@@ -73,12 +72,14 @@ GetPhmrAlignment (
 /**
   Get protected low memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected low memory alignment.
 **/
 UINT32
 GetLowMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   )
 {
@@ -87,11 +88,11 @@ GetLowMemoryAlignment (
   UINT32        FinalAlignment;
 
   FinalAlignment = 0;
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (FinalAlignment < Alignment) {
       FinalAlignment = Alignment;
     }
@@ -102,12 +103,14 @@ GetLowMemoryAlignment (
 /**
   Get protected high memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected high memory alignment.
 **/
 UINT64
 GetHighMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   )
 {
@@ -116,11 +119,11 @@ GetHighMemoryAlignment (
   UINT64        FinalAlignment;
 
   FinalAlignment = 0;
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (FinalAlignment < Alignment) {
       FinalAlignment = Alignment;
     }
@@ -144,12 +147,19 @@ EnablePmr (
   UINT32        Reg32;
   VTD_CAP_REG   CapReg;
 
+  DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));
+
   CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
   if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
     return EFI_UNSUPPORTED;
   }
 
   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if (Reg32 == 0xFFFFFFFF) {
+    DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
+    ASSERT(FALSE);
+  }
+
   if ((Reg32 & BIT0) == 0) {
     MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
     do {
@@ -157,6 +167,8 @@ EnablePmr (
     } while((Reg32 & BIT0) == 0);
   }
 
+  DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));
+
   return EFI_SUCCESS;
 }
 
@@ -182,6 +194,11 @@ DisablePmr (
   }
 
   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if (Reg32 == 0xFFFFFFFF) {
+    DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
+    ASSERT(FALSE);
+  }
+
   if ((Reg32 & BIT0) != 0) {
     MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
     do {
@@ -195,6 +212,7 @@ DisablePmr (
 /**
   Set PMR region in the VTd engine.
 
+  @param HostAddressWidth   The host address width.
   @param VtdUnitBaseAddress The base address of the VTd engine.
   @param LowMemoryBase      The protected low memory region base.
   @param LowMemoryLength    The protected low memory region length.
@@ -206,6 +224,7 @@ DisablePmr (
 **/
 EFI_STATUS
 SetPmrRegion (
+  IN UINT8         HostAddressWidth,
   IN UINTN         VtdUnitBaseAddress,
   IN UINT32        LowMemoryBase,
   IN UINT32        LowMemoryLength,
@@ -225,9 +244,9 @@ SetPmrRegion (
     return EFI_UNSUPPORTED;
   }
 
-  PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);
+  PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
   DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
-  PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);
+  PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
   DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
 
   if ((LowMemoryBase    != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
@@ -247,8 +266,10 @@ SetPmrRegion (
 
   MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG,    LowMemoryBase);
   MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG,  LowMemoryBase + LowMemoryLength - 1);
+  DEBUG ((DEBUG_INFO, "PLMR set done\n"));
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG,   HighMemoryBase);
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
+  DEBUG ((DEBUG_INFO, "PHMR set done\n"));
 
   return EFI_SUCCESS;
 }
@@ -256,6 +277,7 @@ SetPmrRegion (
 /**
   Set DMA protected region.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
   @param LowMemoryBase      The protected low memory region base.
   @param LowMemoryLength    The protected low memory region length.
@@ -267,6 +289,7 @@ SetPmrRegion (
 **/
 EFI_STATUS
 SetDmaProtectedRange (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask,
   IN UINT32        LowMemoryBase,
   IN UINT32        LowMemoryLength,
@@ -279,13 +302,14 @@ SetDmaProtectedRange (
 
   DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
 
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
     Status = SetPmrRegion (
-               (UINTN)mVTdInfo->VTdEngineAddress[Index],
+               VTdInfo->HostAddressWidth,
+               (UINTN)VTdInfo->VTdEngineAddress[Index],
                LowMemoryBase,
                LowMemoryLength,
                HighMemoryBase,
@@ -294,7 +318,7 @@ SetDmaProtectedRange (
     if (EFI_ERROR(Status)) {
       return Status;
     }
-    Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (EFI_ERROR(Status)) {
       return Status;
     }
@@ -306,25 +330,29 @@ SetDmaProtectedRange (
 /**
   Diable DMA protection.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
-  @retval DMA protection is disabled.
+  @retval EFI_SUCCESS DMA protection is disabled.
 **/
 EFI_STATUS
 DisableDmaProtection (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   )
 {
   UINTN       Index;
   EFI_STATUS  Status;
 
-  DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));
+  DEBUG ((DEBUG_INFO, "DisableDmaProtection - 0x%lx\n", EngineMask));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    DEBUG ((DEBUG_INFO, "Disabling...%d\n", Index));
 
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (EFI_ERROR(Status)) {
       return Status;
     }
@@ -332,3 +360,67 @@ DisableDmaProtection (
 
   return EFI_SUCCESS;
 }
+
+/**
+  Return if the PMR is enabled.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval TRUE  PMR is enabled.
+  @retval FALSE PMR is disabled or unsupported.
+**/
+BOOLEAN
+IsPmrEnabled (
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT32        Reg32;
+  VTD_CAP_REG   CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+    return FALSE;
+  }
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if ((Reg32 & BIT0) == 0) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Return the mask of the VTd engine which is enabled.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return the mask of the VTd engine which is enabled.
+**/
+UINT64
+GetDmaProtectionEnabledEngineMask (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  BOOLEAN     Result;
+  UINT64      EnabledEngineMask;
+
+  DEBUG ((DEBUG_INFO, "GetDmaProtectionEnabledEngineMask - 0x%lx\n", EngineMask));
+
+  EnabledEngineMask = 0;
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    Result = IsPmrEnabled ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (Result) {
+      EnabledEngineMask |= LShiftU64(1, Index);
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "EnabledEngineMask - 0x%lx\n", EnabledEngineMask));
+  return EnabledEngineMask;
+}
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
index 3fe6d65..b6ff799 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
@@ -24,6 +24,7 @@
 #include <IndustryStandard/Vtd.h>
 #include <Ppi/IoMmu.h>
 #include <Ppi/VtdInfo.h>
+#include <Ppi/MemoryDiscovered.h>
 #include <Ppi/EndOfPeiPhase.h>
 
 #include "IntelVTdPmrPei.h"
@@ -31,13 +32,20 @@
 #define  TOTAL_DMA_BUFFER_SIZE    SIZE_4MB
 #define  TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB
 
-EFI_ACPI_DMAR_HEADER              *mAcpiDmarTable;
-VTD_INFO                          *mVTdInfo;
-UINT64                            mEngineMask;
-UINTN                             mDmaBufferBase;
-UINTN                             mDmaBufferSize;
-UINTN                             mDmaBufferCurrentTop;
-UINTN                             mDmaBufferCurrentBottom;
+EFI_GUID mVTdInfoGuid = {
+  0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }
+};
+
+EFI_GUID mDmaBufferInfoGuid = {
+  0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }
+};
+
+typedef struct {
+  UINTN                             DmaBufferBase;
+  UINTN                             DmaBufferSize;
+  UINTN                             DmaBufferCurrentTop;
+  UINTN                             DmaBufferCurrentBottom;
+} DMA_BUFFER_INFO;
 
 #define MAP_INFO_SIGNATURE  SIGNATURE_32 ('D', 'M', 'A', 'P')
 typedef struct {
@@ -83,7 +91,6 @@ typedef struct {
               +------------------+ <=============== PLMR.Base (0)
 **/
 
-
 /**
   Set IOMMU attribute for a system memory.
 
@@ -149,8 +156,13 @@ PeiIoMmuMap (
   OUT    VOID                                       **Mapping
   )
 {
-  MAP_INFO   *MapInfo;
-  UINTN      Length;
+  MAP_INFO                    *MapInfo;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
       Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
@@ -160,18 +172,18 @@ PeiIoMmuMap (
   }
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   Length = *NumberOfBytes + sizeof(MAP_INFO);
-  if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {
+  if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
     DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
     ASSERT (FALSE);
     return EFI_OUT_OF_RESOURCES;
   }
 
-  *DeviceAddress = mDmaBufferCurrentBottom;
-  mDmaBufferCurrentBottom += Length;
+  *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;
+  DmaBufferInfo->DmaBufferCurrentBottom += Length;
 
   MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);
   MapInfo->Signature     = MAP_INFO_SIGNATURE;
@@ -216,16 +228,21 @@ PeiIoMmuUnmap (
   IN  VOID                                     *Mapping
   )
 {
-  MAP_INFO   *MapInfo;
-  UINTN      Length;
+  MAP_INFO                    *MapInfo;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   if (Mapping == NULL) {
     return EFI_SUCCESS;
   }
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   MapInfo = Mapping;
   ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);
@@ -246,8 +263,8 @@ PeiIoMmuUnmap (
   }
 
   Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);
-  if (mDmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
-    mDmaBufferCurrentBottom -= Length;
+  if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
+    DmaBufferInfo->DmaBufferCurrentBottom -= Length;
   }
 
   return EFI_SUCCESS;
@@ -282,20 +299,25 @@ PeiIoMmuAllocateBuffer (
   IN     UINT64                                   Attributes
   )
 {
-  UINTN  Length;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   Length = EFI_PAGES_TO_SIZE(Pages);
-  if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {
+  if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
     DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
     ASSERT (FALSE);
     return EFI_OUT_OF_RESOURCES;
   }
-  *HostAddress = (VOID *)(UINTN)(mDmaBufferCurrentTop - Length);
-  mDmaBufferCurrentTop -= Length;
+  *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);
+  DmaBufferInfo->DmaBufferCurrentTop -= Length;
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));
   return EFI_SUCCESS;
@@ -321,15 +343,20 @@ PeiIoMmuFreeBuffer (
   IN  VOID                                     *HostAddress
   )
 {
-  UINTN  Length;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   Length = EFI_PAGES_TO_SIZE(Pages);
-  if ((UINTN)HostAddress == mDmaBufferCurrentTop) {
-    mDmaBufferCurrentTop += Length;
+  if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {
+    DmaBufferInfo->DmaBufferCurrentTop += Length;
   }
 
   return EFI_SUCCESS;
@@ -506,6 +533,7 @@ GetTopMemory (
 /**
   Initialize DMA protection.
 
+  @param VTdInfo        The VTd engine context information.
   @param DmaBufferSize  the DMA buffer size
   @param DmaBufferBase  the DMA buffer base
 
@@ -514,8 +542,9 @@ GetTopMemory (
 **/
 EFI_STATUS
 InitDmaProtection (
-  IN   UINTN  DmaBufferSize,
-  OUT  UINTN  *DmaBufferBase
+  IN   VTD_INFO                    *VTdInfo,
+  IN   UINTN                       DmaBufferSize,
+  OUT  UINTN                       *DmaBufferBase
   )
 {
   EFI_STATUS                  Status;
@@ -537,8 +566,8 @@ InitDmaProtection (
 
   ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);
 
-  LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask);
-  HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask);
+  LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
+  HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
   if (LowMemoryAlignment < HighMemoryAlignment) {
     MemoryAlignment = (UINTN)HighMemoryAlignment;
   } else {
@@ -558,12 +587,13 @@ InitDmaProtection (
   HighTop = GetTopMemory ();
 
   Status = SetDmaProtectedRange (
-               mEngineMask,
-               (UINT32)LowBottom,
-               (UINT32)(LowTop - LowBottom),
-               HighBottom,
-               HighTop - HighBottom
-               );
+             VTdInfo,
+             VTdInfo->EngineMask,
+             (UINT32)LowBottom,
+             (UINT32)(LowTop - LowBottom),
+             HighBottom,
+             HighTop - HighBottom
+             );
 
   if (EFI_ERROR(Status)) {
     FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));
@@ -573,542 +603,188 @@ InitDmaProtection (
 }
 
 /**
-  Dump DMAR DeviceScopeEntry.
+  Initializes the Intel VTd Info.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
 
-  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
 **/
-VOID
-DumpDmarDeviceScopeEntry (
-  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
+EFI_STATUS
+InitVTdInfo (
+  VOID
   )
 {
-  UINTN   PciPathNumber;
-  UINTN   PciPathIndex;
-  EFI_ACPI_DMAR_PCI_PATH  *PciPath;
-
-  if (DmarDeviceScopeEntry == NULL) {
-    return;
-  }
-
-  DEBUG ((DEBUG_INFO,
-    "    *************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    *************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
-    "    DMAR Device Scope Entry address ...................... 0x%08x\n",
-    DmarDeviceScopeEntry
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      Device Scope Entry Type ............................ 0x%02x\n",
-    DmarDeviceScopeEntry->Type
-    ));
-  switch (DmarDeviceScopeEntry->Type) {
-  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
-    DEBUG ((DEBUG_INFO,
-      "        PCI Endpoint Device\n"
-      ));
-    break;
-  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
-    DEBUG ((DEBUG_INFO,
-      "        PCI Sub-hierachy\n"
-      ));
-    break;
-  default:
-    break;
-  }
-  DEBUG ((DEBUG_INFO,
-    "      Length ............................................. 0x%02x\n",
-    DmarDeviceScopeEntry->Length
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      Enumeration ID ..................................... 0x%02x\n",
-    DmarDeviceScopeEntry->EnumerationId
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      Starting Bus Number ................................ 0x%02x\n",
-    DmarDeviceScopeEntry->StartBusNumber
-    ));
-
-  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
-  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
-  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
-    DEBUG ((DEBUG_INFO,
-      "      Device ............................................. 0x%02x\n",
-      PciPath[PciPathIndex].Device
-      ));
-    DEBUG ((DEBUG_INFO,
-      "      Function ........................................... 0x%02x\n",
-      PciPath[PciPathIndex].Function
-      ));
-  }
-
-  DEBUG ((DEBUG_INFO,
-    "    *************************************************************************\n\n"
-    ));
-
-  return;
-}
+  EFI_STATUS                  Status;
+  EFI_ACPI_DMAR_HEADER        *AcpiDmarTable;
+  VOID                        *Hob;
 
-/**
-  Dump DMAR RMRR table.
+  Status = PeiServicesLocatePpi (
+             &gEdkiiVTdInfoPpiGuid,
+             0,
+             NULL,
+             (VOID **)&AcpiDmarTable
+             );
+  ASSERT_EFI_ERROR(Status);
 
-  @param[in]  Rmrr  DMAR RMRR table
-**/
-VOID
-DumpDmarRmrr (
-  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
-  )
-{
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
-  INTN                                    RmrrLen;
+  DumpAcpiDMAR (AcpiDmarTable);
 
-  if (Rmrr == NULL) {
-    return;
+  //
+  // Clear old VTdInfo Hob.
+  //
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  if (Hob != NULL) {
+    ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));
   }
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  *       Reserved Memory Region Reporting Structure                        *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "  RMRR address ........................................... 0x%016lx\n" :
-    "  RMRR address ........................................... 0x%08x\n",
-    Rmrr
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Type ................................................. 0x%04x\n",
-    Rmrr->Header.Type
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Length ............................................... 0x%04x\n",
-    Rmrr->Header.Length
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Segment Number ....................................... 0x%04x\n",
-    Rmrr->SegmentNumber
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Reserved Memory Region Base Address .................. 0x%016lx\n",
-    Rmrr->ReservedMemoryRegionBaseAddress
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
-    Rmrr->ReservedMemoryRegionLimitAddress
-    ));
-
-  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
-  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
-  while (RmrrLen > 0) {
-    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
-    RmrrLen -= DmarDeviceScopeEntry->Length;
-    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  //
+  // Get DMAR information to local VTdInfo
+  //
+  Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);
+  if (EFI_ERROR(Status)) {
+    return Status;
   }
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n\n"
-    ));
+  //
+  // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.
+  //
 
-  return;
+  return EFI_SUCCESS;
 }
 
 /**
-  Dump DMAR DRHD table.
+  Initializes the Intel VTd PMR for all memory.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
 
-  @param[in]  Drhd  DMAR DRHD table
 **/
-VOID
-DumpDmarDrhd (
-  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+EFI_STATUS
+InitVTdPmrForAll (
+  VOID
   )
 {
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
-  INTN                                    DrhdLen;
+  EFI_STATUS                  Status;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  UINTN                       LowBottom;
+  UINTN                       LowTop;
+  UINTN                       HighBottom;
+  UINT64                      HighTop;
 
-  if (Drhd == NULL) {
-    return;
-  }
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  VTdInfo = GET_GUID_HOB_DATA(Hob);
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "  DRHD address ........................................... 0x%016lx\n" :
-    "  DRHD address ........................................... 0x%08x\n",
-    Drhd
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Type ................................................. 0x%04x\n",
-    Drhd->Header.Type
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Length ............................................... 0x%04x\n",
-    Drhd->Header.Length
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Flags ................................................ 0x%02x\n",
-    Drhd->Flags
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
-    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Segment Number ....................................... 0x%04x\n",
-    Drhd->SegmentNumber
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Register Base Address ................................ 0x%016lx\n",
-    Drhd->RegisterBaseAddress
-    ));
-
-  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
-  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
-  while (DrhdLen > 0) {
-    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
-    DrhdLen -= DmarDeviceScopeEntry->Length;
-    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
-  }
+  LowBottom = 0;
+  LowTop = 0;
+  HighBottom = 0;
+  HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth);
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n\n"
-    ));
+  Status = SetDmaProtectedRange (
+             VTdInfo,
+             VTdInfo->EngineMask,
+             (UINT32)LowBottom,
+             (UINT32)(LowTop - LowBottom),
+             HighBottom,
+             HighTop - HighBottom
+             );
 
-  return;
+  return Status;
 }
 
 /**
-  Dump DMAR ACPI table.
+  Initializes the Intel VTd PMR for DMA buffer.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
 
-  @param[in]  Dmar  DMAR ACPI table
 **/
-VOID
-DumpAcpiDMAR (
-  IN EFI_ACPI_DMAR_HEADER  *Dmar
+EFI_STATUS
+InitVTdPmrForDma (
+  VOID
   )
 {
-  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
-  INTN                  DmarLen;
+  EFI_STATUS                  Status;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
 
-  if (Dmar == NULL) {
-    return;
-  }
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  VTdInfo = GET_GUID_HOB_DATA(Hob);
 
   //
-  // Dump Dmar table
+  // If there is RMRR memory, parse it here.
   //
-  DEBUG ((DEBUG_INFO,
-    "*****************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "*         DMAR Table                                                        *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "*****************************************************************************\n"
-    ));
-
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "DMAR address ............................................. 0x%016lx\n" :
-    "DMAR address ............................................. 0x%08x\n",
-    Dmar
-    ));
-
-  DEBUG ((DEBUG_INFO,
-    "  Table Contents:\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Host Address Width ................................... 0x%02x\n",
-    Dmar->HostAddressWidth
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Flags ................................................ 0x%02x\n",
-    Dmar->Flags
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      INTR_REMAP ......................................... 0x%02x\n",
-    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
-    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
-    ));
-
-  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
-  while (DmarLen > 0) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
-      break;
-    case EFI_ACPI_DMAR_TYPE_RMRR:
-      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
-      break;
-    default:
-      break;
-    }
-    DmarLen -= DmarHeader->Length;
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-
-  DEBUG ((DEBUG_INFO,
-    "*****************************************************************************\n\n"
-    ));
-
-  return;
-}
+  ParseDmarAcpiTableRmrr (VTdInfo);
 
-/**
-  Get VTd engine number.
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
-  @return the VTd engine number.
-**/
-UINTN
-GetVtdEngineNumber (
-  VOID
-  )
-{
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-  UINTN                                             VtdIndex;
-
-  VtdIndex = 0;
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      VtdIndex++;
-      break;
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));
+  //
+  // Find a pre-memory in resource hob as DMA buffer
+  // Mark PEI memory to be DMA protected.
+  //
+  Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase);
+  if (EFI_ERROR(Status)) {
+    return Status;
   }
-  return VtdIndex ;
-}
-
-/**
-  Process DMAR DHRD table.
-
-  @param[in]  VtdIndex  The index of VTd engine.
-  @param[in]  DmarDrhd  The DRHD table.
-**/
-VOID
-ProcessDhrd (
-  IN UINTN                      VtdIndex,
-  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
-  )
-{
-  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
-  mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
-}
 
-/**
-  Parse DMAR DRHD table.
-
-  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
-**/
-EFI_STATUS
-ParseDmarAcpiTableDrhd (
-  VOID
-  )
-{
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-  UINTN                                             VtdUnitNumber;
-  UINTN                                             VtdIndex;
+  DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));
 
-  VtdUnitNumber = GetVtdEngineNumber ();
-  if (VtdUnitNumber == 0) {
-    return EFI_UNSUPPORTED;
-  }
-
-  mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
-  if (mVTdInfo == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth;
-  mVTdInfo->VTdEngineCount   = VtdUnitNumber;
-
-  VtdIndex = 0;
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      ASSERT (VtdIndex < VtdUnitNumber);
-      ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
-      VtdIndex++;
-
-      break;
-
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-  ASSERT (VtdIndex == VtdUnitNumber);
+  DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
+  DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;
 
   //
-  // Initialize the engine mask to all.
+  // Install PPI.
   //
-  mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1;
+  Status = PeiServicesInstallPpi (&mIoMmuPpiList);
+  ASSERT_EFI_ERROR(Status);
 
-  return EFI_SUCCESS;
+  return Status;
 }
 
 /**
-  Return the VTd engine index according to the Segment and DevScopeEntry.
+  This function handles S3 resume task at the end of PEI
 
-  @param Segment         The segment of the VTd engine
-  @param DevScopeEntry   The DevScopeEntry of the VTd engine
+  @param[in] PeiServices    Pointer to PEI Services Table.
+  @param[in] NotifyDesc     Pointer to the descriptor for the Notification event that
+                            caused this function to execute.
+  @param[in] Ppi            Pointer to the PPI data associated with this function.
 
-  @return The VTd engine index according to the Segment and DevScopeEntry.
-  @retval -1  The VTd engine is not found.
+  @retval EFI_STATUS        Always return EFI_SUCCESS
 **/
-UINTN
-GetVTdEngineFromDevScopeEntry (
-  IN  UINT16                                      Segment,
-  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
+EFI_STATUS
+EFIAPI
+S3EndOfPeiNotify(
+  IN EFI_PEI_SERVICES          **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+  IN VOID                      *Ppi
   )
 {
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-  UINTN                                             VtdIndex;
-  EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;
-
-  VtdIndex = 0;
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
-      if (DmarDrhd->SegmentNumber != Segment) {
-        // Mismatch
-        break;
-      }
-      if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
-          ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
-        // No DevScopeEntry
-        // Do not handle PCI_ALL
-        break;
-      }
-      ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
-      while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
-        if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
-            (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
-          return VtdIndex;
-        }
-        ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
-      }
-      break;
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-  return (UINTN)-1;
-}
-
-/**
-  Process DMAR RMRR table.
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  UINT64                      EngineMask;
 
-  @param[in]  DmarRmrr  The RMRR table.
-**/
-VOID
-ProcessRmrr (
-  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
-  )
-{
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
-  UINTN                                             VTdIndex;
-  UINT64                                            RmrrMask;
-  UINTN                                             LowBottom;
-  UINTN                                             LowTop;
-  UINTN                                             HighBottom;
-  UINT64                                            HighTop;
-
-  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
-
-  if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
-      (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
-    return ;
-  }
+  DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
 
-  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
-  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
-    ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
-
-    VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry);
-    if (VTdIndex != (UINTN)-1) {
-      RmrrMask = LShiftU64 (1, VTdIndex);
-
-      LowBottom = 0;
-      LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
-      HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
-      HighTop = GetTopMemory ();
-
-      SetDmaProtectedRange (
-        RmrrMask,
-        0,
-        (UINT32)(LowTop - LowBottom),
-        HighBottom,
-        HighTop - HighBottom
-        );
-
-      //
-      // Remove the engine from the engine mask.
-      // The assumption is that any other PEI driver does not access
-      // the device covered by this engine.
-      //
-      mEngineMask = mEngineMask & (~RmrrMask);
-    }
+  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
+    Hob = GetFirstGuidHob (&mVTdInfoGuid);
+    VTdInfo = GET_GUID_HOB_DATA(Hob);
 
-    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+    EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;
+    DisableDmaProtection (VTdInfo, EngineMask);
   }
+  return EFI_SUCCESS;
 }
 
-/**
-  Parse DMAR DRHD table.
-**/
-VOID
-ParseDmarAcpiTableRmrr (
-  VOID
-  )
-{
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_RMRR:
-      ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
-      break;
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-}
+EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiEndOfPeiSignalPpiGuid,
+  S3EndOfPeiNotify
+};
 
 /**
-  This function handles S3 resume task at the end of PEI
+  This function handles VTd engine setup
 
   @param[in] PeiServices    Pointer to PEI Services Table.
   @param[in] NotifyDesc     Pointer to the descriptor for the Notification event that
@@ -1119,27 +795,80 @@ ParseDmarAcpiTableRmrr (
 **/
 EFI_STATUS
 EFIAPI
-S3EndOfPeiNotify(
+VTdInfoNotify (
   IN EFI_PEI_SERVICES          **PeiServices,
   IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
   IN VOID                      *Ppi
   )
 {
-  UINT64                      EngineMask;
+  EFI_STATUS                  Status;
+  VOID                        *MemoryDiscovered;
+  UINT64                      EnabledEngineMask;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  BOOLEAN                     MemoryInitialized;
 
-  DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
+  DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));
+
+  //
+  // Check if memory is initialized.
+  //
+  MemoryInitialized = FALSE;
+  Status = PeiServicesLocatePpi (
+             &gEfiPeiMemoryDiscoveredPpiGuid,
+             0,
+             NULL,
+             &MemoryDiscovered
+             );
+  if (!EFI_ERROR(Status)) {
+    MemoryInitialized = TRUE;
+  }
+
+  DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));
+
+  if (!MemoryInitialized) {
+    //
+    // If the memory is not initialized,
+    // Protect all system memory
+    //
+    InitVTdInfo ();
+    InitVTdPmrForAll ();
+  } else {
+    //
+    // If the memory is initialized,
+    // Allocate DMA buffer and protect rest system memory
+    //
+
+    //
+    // NOTE: We need reinit VTdInfo because previous information might be overriden.
+    //
+    InitVTdInfo ();
+
+    Hob = GetFirstGuidHob (&mVTdInfoGuid);
+    VTdInfo = GET_GUID_HOB_DATA(Hob);
+
+    //
+    // NOTE: We need check if PMR is enabled or not.
+    //
+    EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);
+    if (EnabledEngineMask != 0) {
+      EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
+      DisableDmaProtection (VTdInfo, EnabledEngineMask);
+    }
+    InitVTdPmrForDma ();
+    if (EnabledEngineMask != 0) {
+      DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
+    }
 
-  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
-    EngineMask = LShiftU64 (1, mVTdInfo->VTdEngineCount) - 1;
-    DisableDmaProtection (EngineMask);
   }
+
   return EFI_SUCCESS;
 }
 
-EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
+EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {
   (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
-  &gEfiEndOfPeiSignalPpiGuid,
-  S3EndOfPeiNotify
+  &gEdkiiVTdInfoPpiGuid,
+  VTdInfoNotify
 };
 
 /**
@@ -1161,71 +890,40 @@ IntelVTdPmrInitialize (
 {
   EFI_STATUS                  Status;
   EFI_BOOT_MODE               BootMode;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));
 
   if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
     return EFI_UNSUPPORTED;
   }
 
-  PeiServicesGetBootMode (&BootMode);
-
-  Status = PeiServicesLocatePpi (
-             &gEdkiiVTdInfoPpiGuid,
-             0,
-             NULL,
-             (VOID **)&mAcpiDmarTable
-             );
-  ASSERT_EFI_ERROR(Status);
-
-  DumpAcpiDMAR (mAcpiDmarTable);
-
-  //
-  // Get DMAR information to local VTdInfo
-  //
-  Status = ParseDmarAcpiTableDrhd ();
-  if (EFI_ERROR(Status)) {
-    return Status;
+  DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));
+  ASSERT(DmaBufferInfo != NULL);
+  if (DmaBufferInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
   }
+  ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));
 
-  //
-  // If there is RMRR memory, parse it here.
-  //
-  ParseDmarAcpiTableRmrr ();
+  PeiServicesGetBootMode (&BootMode);
 
   if (BootMode == BOOT_ON_S3_RESUME) {
-    mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;
+    DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;
   } else {
-    mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
-  }
-  DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize));
-
-  //
-  // Find a pre-memory in resource hob as DMA buffer
-  // Mark PEI memory to be DMA protected.
-  //
-  Status = InitDmaProtection (mDmaBufferSize, &mDmaBufferBase);
-  if (EFI_ERROR(Status)) {
-    return Status;
+    DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
   }
 
-  DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase));
-
-  mDmaBufferCurrentTop = mDmaBufferBase + mDmaBufferSize;
-  mDmaBufferCurrentBottom = mDmaBufferBase;
-
-  //
-  // Install PPI.
-  //
-  Status = PeiServicesInstallPpi (&mIoMmuPpiList);
-  ASSERT_EFI_ERROR(Status);
+  Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);
+  ASSERT_EFI_ERROR (Status);
 
   //
-  // Register EndOfPei Notify for S3 to run FSP NotifyPhase
+  // Register EndOfPei Notify for S3
   //
   if (BootMode == BOOT_ON_S3_RESUME) {
     Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);
     ASSERT_EFI_ERROR (Status);
   }
 
-  return Status;
+  return EFI_SUCCESS;
 }
 
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
index 720f5d4..499119d 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
@@ -16,6 +16,8 @@
 #define __DMA_ACCESS_LIB_H__
 
 typedef struct {
+  EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
+  UINT64                                  EngineMask;
   UINT8                                   HostAddressWidth;
   UINTN                                   VTdEngineCount;
   UINT64                                  VTdEngineAddress[1];
@@ -24,6 +26,7 @@ typedef struct {
 /**
   Set DMA protected region.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
   @param LowMemoryBase      The protected low memory region base.
   @param LowMemoryLength    The protected low memory region length.
@@ -35,6 +38,7 @@ typedef struct {
 **/
 EFI_STATUS
 SetDmaProtectedRange (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask,
   IN UINT32        LowMemoryBase,
   IN UINT32        LowMemoryLength,
@@ -45,38 +49,127 @@ SetDmaProtectedRange (
 /**
   Diable DMA protection.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @retval DMA protection is disabled.
 **/
 EFI_STATUS
 DisableDmaProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Return if the DMA protection is enabled.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @retval TRUE  DMA protection is enabled in at least one VTd engine.
+  @retval FALSE DMA protection is disabled in all VTd engines.
+**/
+UINT64
+GetDmaProtectionEnabledEngineMask (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   );
 
 /**
   Get protected low memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected low memory alignment.
 **/
 UINT32
 GetLowMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   );
 
 /**
   Get protected high memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected high memory alignment.
 **/
 UINT64
 GetHighMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Enable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+EnableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Disable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+DisableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   );
 
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  );
+
+/**
+  Parse DMAR DRHD table.
+
+  @param VTdInfo            The VTd engine context information.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+  IN VTD_INFO                    *VTdInfo
+  );
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  );
+
+/**
+  Get the highest memory.
+
+  @return the highest memory.
+**/
+UINT64
+GetTopMemory (
+  VOID
+  );
+
+extern EFI_GUID mVTdInfoGuid;
+
 #endif
 
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
index 4d0e187..e6d0323 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
@@ -33,6 +33,8 @@
   IntelVTdPmrPei.c
   IntelVTdPmrPei.h
   IntelVTdPmr.c
+  DmarTable.c
+  VtdReg.c
 
 [LibraryClasses]
   DebugLib
@@ -42,17 +44,18 @@
   PeiServicesLib
   HobLib
   IoLib
+  CacheMaintenanceLib
 
 [Ppis]
-  gEdkiiIoMmuPpiGuid            ## PRODUCES
-  gEdkiiVTdInfoPpiGuid          ## CONSUMES
-  gEfiEndOfPeiSignalPpiGuid     ## CONSUMES
+  gEdkiiIoMmuPpiGuid                  ## PRODUCES
+  gEdkiiVTdInfoPpiGuid                ## CONSUMES
+  gEfiPeiMemoryDiscoveredPpiGuid      ## CONSUMES
+  gEfiEndOfPeiSignalPpiGuid           ## CONSUMES
 
 [Pcd]
   gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask   ## CONSUMES
 
 [Depex]
-  gEfiPeiMemoryDiscoveredPpiGuid AND
   gEfiPeiMasterBootModePpiGuid AND
   gEdkiiVTdInfoPpiGuid
 
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
new file mode 100644
index 0000000..888905d
--- /dev/null
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
@@ -0,0 +1,293 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available under
+  the terms and conditions of the BSD License which accompanies this distribution.
+  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Flush VTD page table and context table memory.
+
+  This action is to make sure the IOMMU engine can get final data in memory.
+
+  @param[in]  Base              The base address of memory to be flushed.
+  @param[in]  Size              The size of memory in bytes to be flushed.
+**/
+VOID
+FlushPageTableMemory (
+  IN UINTN  Base,
+  IN UINTN  Size
+  )
+{
+  WriteBackDataCacheRange ((VOID *)Base, Size);
+}
+
+/**
+  Flush VTd engine write buffer.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+VOID
+FlushWriteBuffer (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT32      Reg32;
+  VTD_CAP_REG CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+
+  if (CapReg.Bits.RWBF != 0) {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+    MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
+    do {
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+    } while ((Reg32 & B_GSTS_REG_WBF) != 0);
+  }
+}
+
+/**
+  Invalidate VTd context cache.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+EFI_STATUS
+InvalidateContextCache (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT64  Reg64;
+
+  Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
+  if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+  Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
+  MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
+  } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalidate VTd IOTLB.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+EFI_STATUS
+InvalidateIOTLB (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT64       Reg64;
+  VTD_ECAP_REG ECapReg;
+
+  ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
+
+  Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+  Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
+  MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable DMAR translation.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+  @param RootEntryTable     The address of the VTd RootEntryTable.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  IN UINTN  VtdUnitBaseAddress,
+  IN UINTN  RootEntryTable
+  )
+{
+  UINT32    Reg32;
+
+  DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+
+  DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
+  MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)RootEntryTable);
+
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+
+  DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  //
+  // Init DMAr Fault Event and Data registers
+  //
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdUnitBaseAddress);
+
+  //
+  // Invalidate the context cache
+  //
+  InvalidateContextCache (VtdUnitBaseAddress);
+
+  //
+  // Invalidate the IOTLB cache
+  //
+  InvalidateIOTLB (VtdUnitBaseAddress);
+
+  //
+  // Enable VTd
+  //
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+  DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+  DEBUG ((DEBUG_INFO,"VTD () enabled!<<<<<<\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable DMAR translation.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT32    Reg32;
+
+  DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdUnitBaseAddress);
+
+  //
+  // Disable VTd
+  //
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
+
+  MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);
+
+  DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+EnableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  VOID        *RootEntryTable;
+
+  DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask));
+
+  RootEntryTable = AllocatePages (1);
+  ASSERT (RootEntryTable != NULL);
+  if (RootEntryTable == NULL) {
+    DEBUG ((DEBUG_INFO, " EnableVTdTranslationProtection : OutOfResource\n"));
+    return ;
+  }
+
+  ZeroMem (RootEntryTable, EFI_PAGES_TO_SIZE(1));
+  FlushPageTableMemory ((UINTN)RootEntryTable, EFI_PAGES_TO_SIZE(1));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    EnableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index], (UINTN)RootEntryTable);
+  }
+
+  return ;
+}
+
+/**
+  Disable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+DisableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+
+  DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    DisableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+  }
+
+  return ;
+}
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH V2 1/2] IntelSiliconPkg/VtdPmrPei: Add premem support.
Posted by Zeng, Star 7 years, 1 month ago
Reviewed-by: Star Zeng <star.zeng@intel.com>

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Jiewen Yao
Sent: Friday, October 27, 2017 1:40 PM
To: edk2-devel@lists.01.org
Cc: Zeng, Star <star.zeng@intel.com>
Subject: [edk2] [PATCH V2 1/2] IntelSiliconPkg/VtdPmrPei: Add premem support.

Remove memory discovered dependency to support both premem
VTD_INFO_PPI and postmem VTD_INFO_PPI.

If VTD_INFO_PPI is installed before memory is ready, this
driver protects all memory region.
If VTD_INFO_PPI is installed or reinstalled after memory
is ready, this driver allocates DMA buffer and protect rest.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c        | 580 ++++++++++++++
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c      | 130 ++-
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c   | 846 +++++++-------------
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h   |  93 +++
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf |  11 +-
 IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c           | 293 +++++++
 6 files changed, 1356 insertions(+), 597 deletions(-)

diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
new file mode 100644
index 0000000..891efa6
--- /dev/null
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
@@ -0,0 +1,580 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Dump DMAR DeviceScopeEntry.
+
+  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
+**/
+VOID
+DumpDmarDeviceScopeEntry (
+  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
+  )
+{
+  UINTN   PciPathNumber;
+  UINTN   PciPathIndex;
+  EFI_ACPI_DMAR_PCI_PATH  *PciPath;
+
+  if (DmarDeviceScopeEntry == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
+    "    DMAR Device Scope Entry address ...................... 0x%08x\n",
+    DmarDeviceScopeEntry
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Device Scope Entry Type ............................ 0x%02x\n",
+    DmarDeviceScopeEntry->Type
+    ));
+  switch (DmarDeviceScopeEntry->Type) {
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Endpoint Device\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Sub-hierachy\n"
+      ));
+    break;
+  default:
+    break;
+  }
+  DEBUG ((DEBUG_INFO,
+    "      Length ............................................. 0x%02x\n",
+    DmarDeviceScopeEntry->Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Enumeration ID ..................................... 0x%02x\n",
+    DmarDeviceScopeEntry->EnumerationId
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Starting Bus Number ................................ 0x%02x\n",
+    DmarDeviceScopeEntry->StartBusNumber
+    ));
+
+  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
+  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
+  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
+    DEBUG ((DEBUG_INFO,
+      "      Device ............................................. 0x%02x\n",
+      PciPath[PciPathIndex].Device
+      ));
+    DEBUG ((DEBUG_INFO,
+      "      Function ........................................... 0x%02x\n",
+      PciPath[PciPathIndex].Function
+      ));
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR RMRR table.
+
+  @param[in]  Rmrr  DMAR RMRR table
+**/
+VOID
+DumpDmarRmrr (
+  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    RmrrLen;
+
+  if (Rmrr == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       Reserved Memory Region Reporting Structure                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  RMRR address ........................................... 0x%016lx\n" :
+    "  RMRR address ........................................... 0x%08x\n",
+    Rmrr
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Rmrr->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Rmrr->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Rmrr->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Base Address .................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionBaseAddress
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionLimitAddress
+    ));
+
+  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
+  while (RmrrLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    RmrrLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR DRHD table.
+
+  @param[in]  Drhd  DMAR DRHD table
+**/
+VOID
+DumpDmarDrhd (
+  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    DrhdLen;
+
+  if (Drhd == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  DRHD address ........................................... 0x%016lx\n" :
+    "  DRHD address ........................................... 0x%08x\n",
+    Drhd
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Drhd->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Drhd->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Drhd->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
+    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Drhd->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Register Base Address ................................ 0x%016lx\n",
+    Drhd->RegisterBaseAddress
+    ));
+
+  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
+  while (DrhdLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    DrhdLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+  INTN                  DmarLen;
+
+  if (Dmar == NULL) {
+    return;
+  }
+
+  //
+  // Dump Dmar table
+  //
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*         DMAR Table                                                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "DMAR address ............................................. 0x%016lx\n" :
+    "DMAR address ............................................. 0x%08x\n",
+    Dmar
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  Table Contents:\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Host Address Width ................................... 0x%02x\n",
+    Dmar->HostAddressWidth
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Dmar->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INTR_REMAP ......................................... 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
+    ));
+
+  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
+  while (DmarLen > 0) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarLen -= DmarHeader->Length;
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Get VTd engine number.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return the VTd engine number.
+**/
+UINTN
+GetVtdEngineNumber (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      VtdIndex++;
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return VtdIndex ;
+}
+
+/**
+  Process DMAR DHRD table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+  @param[in]  VtdIndex  The index of VTd engine.
+  @param[in]  DmarDrhd  The DRHD table.
+**/
+VOID
+ProcessDhrd (
+  IN VTD_INFO                   *VTdInfo,
+  IN UINTN                      VtdIndex,
+  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
+  )
+{
+  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
+  VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdUnitNumber;
+  UINTN                                             VtdIndex;
+  VTD_INFO                                          *VTdInfo;
+
+  VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);
+  if (VtdUnitNumber == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
+  ASSERT(VTdInfo != NULL);
+  if (VTdInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the engine mask to all.
+  //
+  VTdInfo->AcpiDmarTable    = AcpiDmarTable;
+  VTdInfo->EngineMask       = LShiftU64 (1, VtdUnitNumber) - 1;
+  VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
+  VTdInfo->VTdEngineCount   = VtdUnitNumber;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      ASSERT (VtdIndex < VtdUnitNumber);
+      ProcessDhrd (VTdInfo, VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      VtdIndex++;
+
+      break;
+
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  ASSERT (VtdIndex == VtdUnitNumber);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Return the VTd engine index according to the Segment and DevScopeEntry.
+
+  @param AcpiDmarTable   DMAR ACPI table
+  @param Segment         The segment of the VTd engine
+  @param DevScopeEntry   The DevScopeEntry of the VTd engine
+
+  @return The VTd engine index according to the Segment and DevScopeEntry.
+  @retval -1  The VTd engine is not found.
+**/
+UINTN
+GetVTdEngineFromDevScopeEntry (
+  IN  EFI_ACPI_DMAR_HEADER                        *AcpiDmarTable,
+  IN  UINT16                                      Segment,
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+  EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
+      if (DmarDrhd->SegmentNumber != Segment) {
+        // Mismatch
+        break;
+      }
+      if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
+          ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
+        // No DevScopeEntry
+        // Do not handle PCI_ALL
+        break;
+      }
+      ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
+      while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
+        if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
+            (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
+          return VtdIndex;
+        }
+        ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
+      }
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return (UINTN)-1;
+}
+
+/**
+  Process DMAR RMRR table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+  @param[in]  DmarRmrr  The RMRR table.
+**/
+VOID
+ProcessRmrr (
+  IN VTD_INFO                   *VTdInfo,
+  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINTN                                             VTdIndex;
+  UINT64                                            RmrrMask;
+  UINTN                                             LowBottom;
+  UINTN                                             LowTop;
+  UINTN                                             HighBottom;
+  UINT64                                            HighTop;
+  EFI_ACPI_DMAR_HEADER                              *AcpiDmarTable;
+
+  AcpiDmarTable = VTdInfo->AcpiDmarTable;
+
+  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
+
+  if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
+      (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
+    return ;
+  }
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
+    ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
+
+    VTdIndex = GetVTdEngineFromDevScopeEntry (AcpiDmarTable, DmarRmrr->SegmentNumber, DmarDevScopeEntry);
+    if (VTdIndex != (UINTN)-1) {
+      RmrrMask = LShiftU64 (1, VTdIndex);
+
+      LowBottom = 0;
+      LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
+      HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
+      HighTop = GetTopMemory ();
+
+      SetDmaProtectedRange (
+        VTdInfo,
+        RmrrMask,
+        0,
+        (UINT32)(LowTop - LowBottom),
+        HighBottom,
+        HighTop - HighBottom
+        );
+
+      //
+      // Remove the engine from the engine mask.
+      // The assumption is that any other PEI driver does not access
+      // the device covered by this engine.
+      //
+      VTdInfo->EngineMask = VTdInfo->EngineMask & (~RmrrMask);
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+  IN VTD_INFO                    *VTdInfo
+  )
+{
+  EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
+  EFI_ACPI_DMAR_STRUCTURE_HEADER          *DmarHeader;
+
+  AcpiDmarTable = VTdInfo->AcpiDmarTable;
+
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      ProcessRmrr (VTdInfo, (EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+}
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
index 6179dfe..000a81b 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
@@ -22,17 +22,17 @@
 
 #include "IntelVTdPmrPei.h"
 
-extern VTD_INFO                *mVTdInfo;
-
 /**
   Get protected low memory alignment.
 
+  @param HostAddressWidth   The host address width.
   @param VtdUnitBaseAddress The base address of the VTd engine.
 
   @return protected low memory alignment.
 **/
 UINT32
 GetPlmrAlignment (
+  IN UINT8         HostAddressWidth,
   IN UINTN         VtdUnitBaseAddress
   )
 {
@@ -48,19 +48,18 @@ GetPlmrAlignment (
 /**
   Get protected high memory alignment.
 
+  @param HostAddressWidth   The host address width.
   @param VtdUnitBaseAddress The base address of the VTd engine.
 
   @return protected high memory alignment.
 **/
 UINT64
 GetPhmrAlignment (
+  IN UINT8         HostAddressWidth,
   IN UINTN         VtdUnitBaseAddress
   )
 {
   UINT64        Data64;
-  UINT8         HostAddressWidth;
-
-  HostAddressWidth = mVTdInfo->HostAddressWidth;
 
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
   Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
@@ -73,12 +72,14 @@ GetPhmrAlignment (
 /**
   Get protected low memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected low memory alignment.
 **/
 UINT32
 GetLowMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   )
 {
@@ -87,11 +88,11 @@ GetLowMemoryAlignment (
   UINT32        FinalAlignment;
 
   FinalAlignment = 0;
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (FinalAlignment < Alignment) {
       FinalAlignment = Alignment;
     }
@@ -102,12 +103,14 @@ GetLowMemoryAlignment (
 /**
   Get protected high memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected high memory alignment.
 **/
 UINT64
 GetHighMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   )
 {
@@ -116,11 +119,11 @@ GetHighMemoryAlignment (
   UINT64        FinalAlignment;
 
   FinalAlignment = 0;
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (FinalAlignment < Alignment) {
       FinalAlignment = Alignment;
     }
@@ -144,12 +147,19 @@ EnablePmr (
   UINT32        Reg32;
   VTD_CAP_REG   CapReg;
 
+  DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));
+
   CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
   if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
     return EFI_UNSUPPORTED;
   }
 
   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if (Reg32 == 0xFFFFFFFF) {
+    DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
+    ASSERT(FALSE);
+  }
+
   if ((Reg32 & BIT0) == 0) {
     MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
     do {
@@ -157,6 +167,8 @@ EnablePmr (
     } while((Reg32 & BIT0) == 0);
   }
 
+  DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));
+
   return EFI_SUCCESS;
 }
 
@@ -182,6 +194,11 @@ DisablePmr (
   }
 
   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if (Reg32 == 0xFFFFFFFF) {
+    DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
+    ASSERT(FALSE);
+  }
+
   if ((Reg32 & BIT0) != 0) {
     MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
     do {
@@ -195,6 +212,7 @@ DisablePmr (
 /**
   Set PMR region in the VTd engine.
 
+  @param HostAddressWidth   The host address width.
   @param VtdUnitBaseAddress The base address of the VTd engine.
   @param LowMemoryBase      The protected low memory region base.
   @param LowMemoryLength    The protected low memory region length.
@@ -206,6 +224,7 @@ DisablePmr (
 **/
 EFI_STATUS
 SetPmrRegion (
+  IN UINT8         HostAddressWidth,
   IN UINTN         VtdUnitBaseAddress,
   IN UINT32        LowMemoryBase,
   IN UINT32        LowMemoryLength,
@@ -225,9 +244,9 @@ SetPmrRegion (
     return EFI_UNSUPPORTED;
   }
 
-  PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);
+  PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
   DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
-  PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);
+  PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
   DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
 
   if ((LowMemoryBase    != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
@@ -247,8 +266,10 @@ SetPmrRegion (
 
   MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG,    LowMemoryBase);
   MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG,  LowMemoryBase + LowMemoryLength - 1);
+  DEBUG ((DEBUG_INFO, "PLMR set done\n"));
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG,   HighMemoryBase);
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
+  DEBUG ((DEBUG_INFO, "PHMR set done\n"));
 
   return EFI_SUCCESS;
 }
@@ -256,6 +277,7 @@ SetPmrRegion (
 /**
   Set DMA protected region.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
   @param LowMemoryBase      The protected low memory region base.
   @param LowMemoryLength    The protected low memory region length.
@@ -267,6 +289,7 @@ SetPmrRegion (
 **/
 EFI_STATUS
 SetDmaProtectedRange (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask,
   IN UINT32        LowMemoryBase,
   IN UINT32        LowMemoryLength,
@@ -279,13 +302,14 @@ SetDmaProtectedRange (
 
   DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
 
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
     Status = SetPmrRegion (
-               (UINTN)mVTdInfo->VTdEngineAddress[Index],
+               VTdInfo->HostAddressWidth,
+               (UINTN)VTdInfo->VTdEngineAddress[Index],
                LowMemoryBase,
                LowMemoryLength,
                HighMemoryBase,
@@ -294,7 +318,7 @@ SetDmaProtectedRange (
     if (EFI_ERROR(Status)) {
       return Status;
     }
-    Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (EFI_ERROR(Status)) {
       return Status;
     }
@@ -306,25 +330,29 @@ SetDmaProtectedRange (
 /**
   Diable DMA protection.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
-  @retval DMA protection is disabled.
+  @retval EFI_SUCCESS DMA protection is disabled.
 **/
 EFI_STATUS
 DisableDmaProtection (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   )
 {
   UINTN       Index;
   EFI_STATUS  Status;
 
-  DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));
+  DEBUG ((DEBUG_INFO, "DisableDmaProtection - 0x%lx\n", EngineMask));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    DEBUG ((DEBUG_INFO, "Disabling...%d\n", Index));
 
-  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
     if ((EngineMask & LShiftU64(1, Index)) == 0) {
       continue;
     }
-    Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
+    Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
     if (EFI_ERROR(Status)) {
       return Status;
     }
@@ -332,3 +360,67 @@ DisableDmaProtection (
 
   return EFI_SUCCESS;
 }
+
+/**
+  Return if the PMR is enabled.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval TRUE  PMR is enabled.
+  @retval FALSE PMR is disabled or unsupported.
+**/
+BOOLEAN
+IsPmrEnabled (
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT32        Reg32;
+  VTD_CAP_REG   CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+    return FALSE;
+  }
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if ((Reg32 & BIT0) == 0) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Return the mask of the VTd engine which is enabled.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return the mask of the VTd engine which is enabled.
+**/
+UINT64
+GetDmaProtectionEnabledEngineMask (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  BOOLEAN     Result;
+  UINT64      EnabledEngineMask;
+
+  DEBUG ((DEBUG_INFO, "GetDmaProtectionEnabledEngineMask - 0x%lx\n", EngineMask));
+
+  EnabledEngineMask = 0;
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    Result = IsPmrEnabled ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (Result) {
+      EnabledEngineMask |= LShiftU64(1, Index);
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "EnabledEngineMask - 0x%lx\n", EnabledEngineMask));
+  return EnabledEngineMask;
+}
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
index 3fe6d65..b6ff799 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
@@ -24,6 +24,7 @@
 #include <IndustryStandard/Vtd.h>
 #include <Ppi/IoMmu.h>
 #include <Ppi/VtdInfo.h>
+#include <Ppi/MemoryDiscovered.h>
 #include <Ppi/EndOfPeiPhase.h>
 
 #include "IntelVTdPmrPei.h"
@@ -31,13 +32,20 @@
 #define  TOTAL_DMA_BUFFER_SIZE    SIZE_4MB
 #define  TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB
 
-EFI_ACPI_DMAR_HEADER              *mAcpiDmarTable;
-VTD_INFO                          *mVTdInfo;
-UINT64                            mEngineMask;
-UINTN                             mDmaBufferBase;
-UINTN                             mDmaBufferSize;
-UINTN                             mDmaBufferCurrentTop;
-UINTN                             mDmaBufferCurrentBottom;
+EFI_GUID mVTdInfoGuid = {
+  0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }
+};
+
+EFI_GUID mDmaBufferInfoGuid = {
+  0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }
+};
+
+typedef struct {
+  UINTN                             DmaBufferBase;
+  UINTN                             DmaBufferSize;
+  UINTN                             DmaBufferCurrentTop;
+  UINTN                             DmaBufferCurrentBottom;
+} DMA_BUFFER_INFO;
 
 #define MAP_INFO_SIGNATURE  SIGNATURE_32 ('D', 'M', 'A', 'P')
 typedef struct {
@@ -83,7 +91,6 @@ typedef struct {
               +------------------+ <=============== PLMR.Base (0)
 **/
 
-
 /**
   Set IOMMU attribute for a system memory.
 
@@ -149,8 +156,13 @@ PeiIoMmuMap (
   OUT    VOID                                       **Mapping
   )
 {
-  MAP_INFO   *MapInfo;
-  UINTN      Length;
+  MAP_INFO                    *MapInfo;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
       Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
@@ -160,18 +172,18 @@ PeiIoMmuMap (
   }
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   Length = *NumberOfBytes + sizeof(MAP_INFO);
-  if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {
+  if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
     DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
     ASSERT (FALSE);
     return EFI_OUT_OF_RESOURCES;
   }
 
-  *DeviceAddress = mDmaBufferCurrentBottom;
-  mDmaBufferCurrentBottom += Length;
+  *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;
+  DmaBufferInfo->DmaBufferCurrentBottom += Length;
 
   MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);
   MapInfo->Signature     = MAP_INFO_SIGNATURE;
@@ -216,16 +228,21 @@ PeiIoMmuUnmap (
   IN  VOID                                     *Mapping
   )
 {
-  MAP_INFO   *MapInfo;
-  UINTN      Length;
+  MAP_INFO                    *MapInfo;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   if (Mapping == NULL) {
     return EFI_SUCCESS;
   }
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   MapInfo = Mapping;
   ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);
@@ -246,8 +263,8 @@ PeiIoMmuUnmap (
   }
 
   Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);
-  if (mDmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
-    mDmaBufferCurrentBottom -= Length;
+  if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
+    DmaBufferInfo->DmaBufferCurrentBottom -= Length;
   }
 
   return EFI_SUCCESS;
@@ -282,20 +299,25 @@ PeiIoMmuAllocateBuffer (
   IN     UINT64                                   Attributes
   )
 {
-  UINTN  Length;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   Length = EFI_PAGES_TO_SIZE(Pages);
-  if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {
+  if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
     DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
     ASSERT (FALSE);
     return EFI_OUT_OF_RESOURCES;
   }
-  *HostAddress = (VOID *)(UINTN)(mDmaBufferCurrentTop - Length);
-  mDmaBufferCurrentTop -= Length;
+  *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);
+  DmaBufferInfo->DmaBufferCurrentTop -= Length;
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));
   return EFI_SUCCESS;
@@ -321,15 +343,20 @@ PeiIoMmuFreeBuffer (
   IN  VOID                                     *HostAddress
   )
 {
-  UINTN  Length;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
   DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));
-  DEBUG ((DEBUG_VERBOSE, "  mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
 
   Length = EFI_PAGES_TO_SIZE(Pages);
-  if ((UINTN)HostAddress == mDmaBufferCurrentTop) {
-    mDmaBufferCurrentTop += Length;
+  if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {
+    DmaBufferInfo->DmaBufferCurrentTop += Length;
   }
 
   return EFI_SUCCESS;
@@ -506,6 +533,7 @@ GetTopMemory (
 /**
   Initialize DMA protection.
 
+  @param VTdInfo        The VTd engine context information.
   @param DmaBufferSize  the DMA buffer size
   @param DmaBufferBase  the DMA buffer base
 
@@ -514,8 +542,9 @@ GetTopMemory (
 **/
 EFI_STATUS
 InitDmaProtection (
-  IN   UINTN  DmaBufferSize,
-  OUT  UINTN  *DmaBufferBase
+  IN   VTD_INFO                    *VTdInfo,
+  IN   UINTN                       DmaBufferSize,
+  OUT  UINTN                       *DmaBufferBase
   )
 {
   EFI_STATUS                  Status;
@@ -537,8 +566,8 @@ InitDmaProtection (
 
   ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);
 
-  LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask);
-  HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask);
+  LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
+  HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
   if (LowMemoryAlignment < HighMemoryAlignment) {
     MemoryAlignment = (UINTN)HighMemoryAlignment;
   } else {
@@ -558,12 +587,13 @@ InitDmaProtection (
   HighTop = GetTopMemory ();
 
   Status = SetDmaProtectedRange (
-               mEngineMask,
-               (UINT32)LowBottom,
-               (UINT32)(LowTop - LowBottom),
-               HighBottom,
-               HighTop - HighBottom
-               );
+             VTdInfo,
+             VTdInfo->EngineMask,
+             (UINT32)LowBottom,
+             (UINT32)(LowTop - LowBottom),
+             HighBottom,
+             HighTop - HighBottom
+             );
 
   if (EFI_ERROR(Status)) {
     FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));
@@ -573,542 +603,188 @@ InitDmaProtection (
 }
 
 /**
-  Dump DMAR DeviceScopeEntry.
+  Initializes the Intel VTd Info.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
 
-  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
 **/
-VOID
-DumpDmarDeviceScopeEntry (
-  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
+EFI_STATUS
+InitVTdInfo (
+  VOID
   )
 {
-  UINTN   PciPathNumber;
-  UINTN   PciPathIndex;
-  EFI_ACPI_DMAR_PCI_PATH  *PciPath;
-
-  if (DmarDeviceScopeEntry == NULL) {
-    return;
-  }
-
-  DEBUG ((DEBUG_INFO,
-    "    *************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    *************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
-    "    DMAR Device Scope Entry address ...................... 0x%08x\n",
-    DmarDeviceScopeEntry
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      Device Scope Entry Type ............................ 0x%02x\n",
-    DmarDeviceScopeEntry->Type
-    ));
-  switch (DmarDeviceScopeEntry->Type) {
-  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
-    DEBUG ((DEBUG_INFO,
-      "        PCI Endpoint Device\n"
-      ));
-    break;
-  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
-    DEBUG ((DEBUG_INFO,
-      "        PCI Sub-hierachy\n"
-      ));
-    break;
-  default:
-    break;
-  }
-  DEBUG ((DEBUG_INFO,
-    "      Length ............................................. 0x%02x\n",
-    DmarDeviceScopeEntry->Length
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      Enumeration ID ..................................... 0x%02x\n",
-    DmarDeviceScopeEntry->EnumerationId
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      Starting Bus Number ................................ 0x%02x\n",
-    DmarDeviceScopeEntry->StartBusNumber
-    ));
-
-  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
-  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
-  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
-    DEBUG ((DEBUG_INFO,
-      "      Device ............................................. 0x%02x\n",
-      PciPath[PciPathIndex].Device
-      ));
-    DEBUG ((DEBUG_INFO,
-      "      Function ........................................... 0x%02x\n",
-      PciPath[PciPathIndex].Function
-      ));
-  }
-
-  DEBUG ((DEBUG_INFO,
-    "    *************************************************************************\n\n"
-    ));
-
-  return;
-}
+  EFI_STATUS                  Status;
+  EFI_ACPI_DMAR_HEADER        *AcpiDmarTable;
+  VOID                        *Hob;
 
-/**
-  Dump DMAR RMRR table.
+  Status = PeiServicesLocatePpi (
+             &gEdkiiVTdInfoPpiGuid,
+             0,
+             NULL,
+             (VOID **)&AcpiDmarTable
+             );
+  ASSERT_EFI_ERROR(Status);
 
-  @param[in]  Rmrr  DMAR RMRR table
-**/
-VOID
-DumpDmarRmrr (
-  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
-  )
-{
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
-  INTN                                    RmrrLen;
+  DumpAcpiDMAR (AcpiDmarTable);
 
-  if (Rmrr == NULL) {
-    return;
+  //
+  // Clear old VTdInfo Hob.
+  //
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  if (Hob != NULL) {
+    ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));
   }
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  *       Reserved Memory Region Reporting Structure                        *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "  RMRR address ........................................... 0x%016lx\n" :
-    "  RMRR address ........................................... 0x%08x\n",
-    Rmrr
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Type ................................................. 0x%04x\n",
-    Rmrr->Header.Type
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Length ............................................... 0x%04x\n",
-    Rmrr->Header.Length
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Segment Number ....................................... 0x%04x\n",
-    Rmrr->SegmentNumber
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Reserved Memory Region Base Address .................. 0x%016lx\n",
-    Rmrr->ReservedMemoryRegionBaseAddress
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
-    Rmrr->ReservedMemoryRegionLimitAddress
-    ));
-
-  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
-  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
-  while (RmrrLen > 0) {
-    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
-    RmrrLen -= DmarDeviceScopeEntry->Length;
-    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  //
+  // Get DMAR information to local VTdInfo
+  //
+  Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);
+  if (EFI_ERROR(Status)) {
+    return Status;
   }
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n\n"
-    ));
+  //
+  // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.
+  //
 
-  return;
+  return EFI_SUCCESS;
 }
 
 /**
-  Dump DMAR DRHD table.
+  Initializes the Intel VTd PMR for all memory.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
 
-  @param[in]  Drhd  DMAR DRHD table
 **/
-VOID
-DumpDmarDrhd (
-  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+EFI_STATUS
+InitVTdPmrForAll (
+  VOID
   )
 {
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
-  INTN                                    DrhdLen;
+  EFI_STATUS                  Status;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  UINTN                       LowBottom;
+  UINTN                       LowTop;
+  UINTN                       HighBottom;
+  UINT64                      HighTop;
 
-  if (Drhd == NULL) {
-    return;
-  }
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  VTdInfo = GET_GUID_HOB_DATA(Hob);
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "  DRHD address ........................................... 0x%016lx\n" :
-    "  DRHD address ........................................... 0x%08x\n",
-    Drhd
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Type ................................................. 0x%04x\n",
-    Drhd->Header.Type
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Length ............................................... 0x%04x\n",
-    Drhd->Header.Length
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Flags ................................................ 0x%02x\n",
-    Drhd->Flags
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
-    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Segment Number ....................................... 0x%04x\n",
-    Drhd->SegmentNumber
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Register Base Address ................................ 0x%016lx\n",
-    Drhd->RegisterBaseAddress
-    ));
-
-  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
-  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
-  while (DrhdLen > 0) {
-    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
-    DrhdLen -= DmarDeviceScopeEntry->Length;
-    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
-  }
+  LowBottom = 0;
+  LowTop = 0;
+  HighBottom = 0;
+  HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth);
 
-  DEBUG ((DEBUG_INFO,
-    "  ***************************************************************************\n\n"
-    ));
+  Status = SetDmaProtectedRange (
+             VTdInfo,
+             VTdInfo->EngineMask,
+             (UINT32)LowBottom,
+             (UINT32)(LowTop - LowBottom),
+             HighBottom,
+             HighTop - HighBottom
+             );
 
-  return;
+  return Status;
 }
 
 /**
-  Dump DMAR ACPI table.
+  Initializes the Intel VTd PMR for DMA buffer.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
 
-  @param[in]  Dmar  DMAR ACPI table
 **/
-VOID
-DumpAcpiDMAR (
-  IN EFI_ACPI_DMAR_HEADER  *Dmar
+EFI_STATUS
+InitVTdPmrForDma (
+  VOID
   )
 {
-  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
-  INTN                  DmarLen;
+  EFI_STATUS                  Status;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
 
-  if (Dmar == NULL) {
-    return;
-  }
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  VTdInfo = GET_GUID_HOB_DATA(Hob);
 
   //
-  // Dump Dmar table
+  // If there is RMRR memory, parse it here.
   //
-  DEBUG ((DEBUG_INFO,
-    "*****************************************************************************\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "*         DMAR Table                                                        *\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "*****************************************************************************\n"
-    ));
-
-  DEBUG ((DEBUG_INFO,
-    (sizeof(UINTN) == sizeof(UINT64)) ?
-    "DMAR address ............................................. 0x%016lx\n" :
-    "DMAR address ............................................. 0x%08x\n",
-    Dmar
-    ));
-
-  DEBUG ((DEBUG_INFO,
-    "  Table Contents:\n"
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Host Address Width ................................... 0x%02x\n",
-    Dmar->HostAddressWidth
-    ));
-  DEBUG ((DEBUG_INFO,
-    "    Flags ................................................ 0x%02x\n",
-    Dmar->Flags
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      INTR_REMAP ......................................... 0x%02x\n",
-    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
-    ));
-  DEBUG ((DEBUG_INFO,
-    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
-    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
-    ));
-
-  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
-  while (DmarLen > 0) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
-      break;
-    case EFI_ACPI_DMAR_TYPE_RMRR:
-      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
-      break;
-    default:
-      break;
-    }
-    DmarLen -= DmarHeader->Length;
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-
-  DEBUG ((DEBUG_INFO,
-    "*****************************************************************************\n\n"
-    ));
-
-  return;
-}
+  ParseDmarAcpiTableRmrr (VTdInfo);
 
-/**
-  Get VTd engine number.
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
 
-  @return the VTd engine number.
-**/
-UINTN
-GetVtdEngineNumber (
-  VOID
-  )
-{
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-  UINTN                                             VtdIndex;
-
-  VtdIndex = 0;
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      VtdIndex++;
-      break;
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));
+  //
+  // Find a pre-memory in resource hob as DMA buffer
+  // Mark PEI memory to be DMA protected.
+  //
+  Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase);
+  if (EFI_ERROR(Status)) {
+    return Status;
   }
-  return VtdIndex ;
-}
-
-/**
-  Process DMAR DHRD table.
-
-  @param[in]  VtdIndex  The index of VTd engine.
-  @param[in]  DmarDrhd  The DRHD table.
-**/
-VOID
-ProcessDhrd (
-  IN UINTN                      VtdIndex,
-  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
-  )
-{
-  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
-  mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
-}
 
-/**
-  Parse DMAR DRHD table.
-
-  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
-**/
-EFI_STATUS
-ParseDmarAcpiTableDrhd (
-  VOID
-  )
-{
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-  UINTN                                             VtdUnitNumber;
-  UINTN                                             VtdIndex;
+  DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));
 
-  VtdUnitNumber = GetVtdEngineNumber ();
-  if (VtdUnitNumber == 0) {
-    return EFI_UNSUPPORTED;
-  }
-
-  mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
-  if (mVTdInfo == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth;
-  mVTdInfo->VTdEngineCount   = VtdUnitNumber;
-
-  VtdIndex = 0;
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      ASSERT (VtdIndex < VtdUnitNumber);
-      ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
-      VtdIndex++;
-
-      break;
-
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-  ASSERT (VtdIndex == VtdUnitNumber);
+  DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
+  DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;
 
   //
-  // Initialize the engine mask to all.
+  // Install PPI.
   //
-  mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1;
+  Status = PeiServicesInstallPpi (&mIoMmuPpiList);
+  ASSERT_EFI_ERROR(Status);
 
-  return EFI_SUCCESS;
+  return Status;
 }
 
 /**
-  Return the VTd engine index according to the Segment and DevScopeEntry.
+  This function handles S3 resume task at the end of PEI
 
-  @param Segment         The segment of the VTd engine
-  @param DevScopeEntry   The DevScopeEntry of the VTd engine
+  @param[in] PeiServices    Pointer to PEI Services Table.
+  @param[in] NotifyDesc     Pointer to the descriptor for the Notification event that
+                            caused this function to execute.
+  @param[in] Ppi            Pointer to the PPI data associated with this function.
 
-  @return The VTd engine index according to the Segment and DevScopeEntry.
-  @retval -1  The VTd engine is not found.
+  @retval EFI_STATUS        Always return EFI_SUCCESS
 **/
-UINTN
-GetVTdEngineFromDevScopeEntry (
-  IN  UINT16                                      Segment,
-  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
+EFI_STATUS
+EFIAPI
+S3EndOfPeiNotify(
+  IN EFI_PEI_SERVICES          **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+  IN VOID                      *Ppi
   )
 {
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-  UINTN                                             VtdIndex;
-  EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;
-
-  VtdIndex = 0;
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_DRHD:
-      DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
-      if (DmarDrhd->SegmentNumber != Segment) {
-        // Mismatch
-        break;
-      }
-      if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
-          ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
-        // No DevScopeEntry
-        // Do not handle PCI_ALL
-        break;
-      }
-      ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
-      while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
-        if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
-            (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
-          return VtdIndex;
-        }
-        ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
-      }
-      break;
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-  return (UINTN)-1;
-}
-
-/**
-  Process DMAR RMRR table.
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  UINT64                      EngineMask;
 
-  @param[in]  DmarRmrr  The RMRR table.
-**/
-VOID
-ProcessRmrr (
-  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
-  )
-{
-  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
-  UINTN                                             VTdIndex;
-  UINT64                                            RmrrMask;
-  UINTN                                             LowBottom;
-  UINTN                                             LowTop;
-  UINTN                                             HighBottom;
-  UINT64                                            HighTop;
-
-  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
-
-  if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
-      (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
-    return ;
-  }
+  DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
 
-  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
-  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
-    ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
-
-    VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry);
-    if (VTdIndex != (UINTN)-1) {
-      RmrrMask = LShiftU64 (1, VTdIndex);
-
-      LowBottom = 0;
-      LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
-      HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
-      HighTop = GetTopMemory ();
-
-      SetDmaProtectedRange (
-        RmrrMask,
-        0,
-        (UINT32)(LowTop - LowBottom),
-        HighBottom,
-        HighTop - HighBottom
-        );
-
-      //
-      // Remove the engine from the engine mask.
-      // The assumption is that any other PEI driver does not access
-      // the device covered by this engine.
-      //
-      mEngineMask = mEngineMask & (~RmrrMask);
-    }
+  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
+    Hob = GetFirstGuidHob (&mVTdInfoGuid);
+    VTdInfo = GET_GUID_HOB_DATA(Hob);
 
-    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+    EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;
+    DisableDmaProtection (VTdInfo, EngineMask);
   }
+  return EFI_SUCCESS;
 }
 
-/**
-  Parse DMAR DRHD table.
-**/
-VOID
-ParseDmarAcpiTableRmrr (
-  VOID
-  )
-{
-  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
-
-  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
-  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
-    switch (DmarHeader->Type) {
-    case EFI_ACPI_DMAR_TYPE_RMRR:
-      ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
-      break;
-    default:
-      break;
-    }
-    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
-  }
-}
+EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiEndOfPeiSignalPpiGuid,
+  S3EndOfPeiNotify
+};
 
 /**
-  This function handles S3 resume task at the end of PEI
+  This function handles VTd engine setup
 
   @param[in] PeiServices    Pointer to PEI Services Table.
   @param[in] NotifyDesc     Pointer to the descriptor for the Notification event that
@@ -1119,27 +795,80 @@ ParseDmarAcpiTableRmrr (
 **/
 EFI_STATUS
 EFIAPI
-S3EndOfPeiNotify(
+VTdInfoNotify (
   IN EFI_PEI_SERVICES          **PeiServices,
   IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
   IN VOID                      *Ppi
   )
 {
-  UINT64                      EngineMask;
+  EFI_STATUS                  Status;
+  VOID                        *MemoryDiscovered;
+  UINT64                      EnabledEngineMask;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  BOOLEAN                     MemoryInitialized;
 
-  DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
+  DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));
+
+  //
+  // Check if memory is initialized.
+  //
+  MemoryInitialized = FALSE;
+  Status = PeiServicesLocatePpi (
+             &gEfiPeiMemoryDiscoveredPpiGuid,
+             0,
+             NULL,
+             &MemoryDiscovered
+             );
+  if (!EFI_ERROR(Status)) {
+    MemoryInitialized = TRUE;
+  }
+
+  DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));
+
+  if (!MemoryInitialized) {
+    //
+    // If the memory is not initialized,
+    // Protect all system memory
+    //
+    InitVTdInfo ();
+    InitVTdPmrForAll ();
+  } else {
+    //
+    // If the memory is initialized,
+    // Allocate DMA buffer and protect rest system memory
+    //
+
+    //
+    // NOTE: We need reinit VTdInfo because previous information might be overriden.
+    //
+    InitVTdInfo ();
+
+    Hob = GetFirstGuidHob (&mVTdInfoGuid);
+    VTdInfo = GET_GUID_HOB_DATA(Hob);
+
+    //
+    // NOTE: We need check if PMR is enabled or not.
+    //
+    EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);
+    if (EnabledEngineMask != 0) {
+      EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
+      DisableDmaProtection (VTdInfo, EnabledEngineMask);
+    }
+    InitVTdPmrForDma ();
+    if (EnabledEngineMask != 0) {
+      DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
+    }
 
-  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
-    EngineMask = LShiftU64 (1, mVTdInfo->VTdEngineCount) - 1;
-    DisableDmaProtection (EngineMask);
   }
+
   return EFI_SUCCESS;
 }
 
-EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
+EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {
   (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
-  &gEfiEndOfPeiSignalPpiGuid,
-  S3EndOfPeiNotify
+  &gEdkiiVTdInfoPpiGuid,
+  VTdInfoNotify
 };
 
 /**
@@ -1161,71 +890,40 @@ IntelVTdPmrInitialize (
 {
   EFI_STATUS                  Status;
   EFI_BOOT_MODE               BootMode;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));
 
   if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
     return EFI_UNSUPPORTED;
   }
 
-  PeiServicesGetBootMode (&BootMode);
-
-  Status = PeiServicesLocatePpi (
-             &gEdkiiVTdInfoPpiGuid,
-             0,
-             NULL,
-             (VOID **)&mAcpiDmarTable
-             );
-  ASSERT_EFI_ERROR(Status);
-
-  DumpAcpiDMAR (mAcpiDmarTable);
-
-  //
-  // Get DMAR information to local VTdInfo
-  //
-  Status = ParseDmarAcpiTableDrhd ();
-  if (EFI_ERROR(Status)) {
-    return Status;
+  DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));
+  ASSERT(DmaBufferInfo != NULL);
+  if (DmaBufferInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
   }
+  ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));
 
-  //
-  // If there is RMRR memory, parse it here.
-  //
-  ParseDmarAcpiTableRmrr ();
+  PeiServicesGetBootMode (&BootMode);
 
   if (BootMode == BOOT_ON_S3_RESUME) {
-    mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;
+    DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;
   } else {
-    mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
-  }
-  DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize));
-
-  //
-  // Find a pre-memory in resource hob as DMA buffer
-  // Mark PEI memory to be DMA protected.
-  //
-  Status = InitDmaProtection (mDmaBufferSize, &mDmaBufferBase);
-  if (EFI_ERROR(Status)) {
-    return Status;
+    DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
   }
 
-  DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase));
-
-  mDmaBufferCurrentTop = mDmaBufferBase + mDmaBufferSize;
-  mDmaBufferCurrentBottom = mDmaBufferBase;
-
-  //
-  // Install PPI.
-  //
-  Status = PeiServicesInstallPpi (&mIoMmuPpiList);
-  ASSERT_EFI_ERROR(Status);
+  Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);
+  ASSERT_EFI_ERROR (Status);
 
   //
-  // Register EndOfPei Notify for S3 to run FSP NotifyPhase
+  // Register EndOfPei Notify for S3
   //
   if (BootMode == BOOT_ON_S3_RESUME) {
     Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);
     ASSERT_EFI_ERROR (Status);
   }
 
-  return Status;
+  return EFI_SUCCESS;
 }
 
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
index 720f5d4..499119d 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
@@ -16,6 +16,8 @@
 #define __DMA_ACCESS_LIB_H__
 
 typedef struct {
+  EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
+  UINT64                                  EngineMask;
   UINT8                                   HostAddressWidth;
   UINTN                                   VTdEngineCount;
   UINT64                                  VTdEngineAddress[1];
@@ -24,6 +26,7 @@ typedef struct {
 /**
   Set DMA protected region.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
   @param LowMemoryBase      The protected low memory region base.
   @param LowMemoryLength    The protected low memory region length.
@@ -35,6 +38,7 @@ typedef struct {
 **/
 EFI_STATUS
 SetDmaProtectedRange (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask,
   IN UINT32        LowMemoryBase,
   IN UINT32        LowMemoryLength,
@@ -45,38 +49,127 @@ SetDmaProtectedRange (
 /**
   Diable DMA protection.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @retval DMA protection is disabled.
 **/
 EFI_STATUS
 DisableDmaProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Return if the DMA protection is enabled.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @retval TRUE  DMA protection is enabled in at least one VTd engine.
+  @retval FALSE DMA protection is disabled in all VTd engines.
+**/
+UINT64
+GetDmaProtectionEnabledEngineMask (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   );
 
 /**
   Get protected low memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected low memory alignment.
 **/
 UINT32
 GetLowMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   );
 
 /**
   Get protected high memory alignment.
 
+  @param VTdInfo            The VTd engine context information.
   @param EngineMask         The mask of the VTd engine to be accessed.
 
   @return protected high memory alignment.
 **/
 UINT64
 GetHighMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Enable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+EnableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Disable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+DisableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
   IN UINT64        EngineMask
   );
 
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  );
+
+/**
+  Parse DMAR DRHD table.
+
+  @param VTdInfo            The VTd engine context information.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+  IN VTD_INFO                    *VTdInfo
+  );
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  );
+
+/**
+  Get the highest memory.
+
+  @return the highest memory.
+**/
+UINT64
+GetTopMemory (
+  VOID
+  );
+
+extern EFI_GUID mVTdInfoGuid;
+
 #endif
 
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
index 4d0e187..e6d0323 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
@@ -33,6 +33,8 @@
   IntelVTdPmrPei.c
   IntelVTdPmrPei.h
   IntelVTdPmr.c
+  DmarTable.c
+  VtdReg.c
 
 [LibraryClasses]
   DebugLib
@@ -42,17 +44,18 @@
   PeiServicesLib
   HobLib
   IoLib
+  CacheMaintenanceLib
 
 [Ppis]
-  gEdkiiIoMmuPpiGuid            ## PRODUCES
-  gEdkiiVTdInfoPpiGuid          ## CONSUMES
-  gEfiEndOfPeiSignalPpiGuid     ## CONSUMES
+  gEdkiiIoMmuPpiGuid                  ## PRODUCES
+  gEdkiiVTdInfoPpiGuid                ## CONSUMES
+  gEfiPeiMemoryDiscoveredPpiGuid      ## CONSUMES
+  gEfiEndOfPeiSignalPpiGuid           ## CONSUMES
 
 [Pcd]
   gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask   ## CONSUMES
 
 [Depex]
-  gEfiPeiMemoryDiscoveredPpiGuid AND
   gEfiPeiMasterBootModePpiGuid AND
   gEdkiiVTdInfoPpiGuid
 
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
new file mode 100644
index 0000000..888905d
--- /dev/null
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
@@ -0,0 +1,293 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available under
+  the terms and conditions of the BSD License which accompanies this distribution.
+  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Flush VTD page table and context table memory.
+
+  This action is to make sure the IOMMU engine can get final data in memory.
+
+  @param[in]  Base              The base address of memory to be flushed.
+  @param[in]  Size              The size of memory in bytes to be flushed.
+**/
+VOID
+FlushPageTableMemory (
+  IN UINTN  Base,
+  IN UINTN  Size
+  )
+{
+  WriteBackDataCacheRange ((VOID *)Base, Size);
+}
+
+/**
+  Flush VTd engine write buffer.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+VOID
+FlushWriteBuffer (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT32      Reg32;
+  VTD_CAP_REG CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+
+  if (CapReg.Bits.RWBF != 0) {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+    MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
+    do {
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+    } while ((Reg32 & B_GSTS_REG_WBF) != 0);
+  }
+}
+
+/**
+  Invalidate VTd context cache.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+EFI_STATUS
+InvalidateContextCache (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT64  Reg64;
+
+  Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
+  if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+  Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
+  MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
+  } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalidate VTd IOTLB.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+EFI_STATUS
+InvalidateIOTLB (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT64       Reg64;
+  VTD_ECAP_REG ECapReg;
+
+  ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
+
+  Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+  Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
+  MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable DMAR translation.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+  @param RootEntryTable     The address of the VTd RootEntryTable.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  IN UINTN  VtdUnitBaseAddress,
+  IN UINTN  RootEntryTable
+  )
+{
+  UINT32    Reg32;
+
+  DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+
+  DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
+  MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)RootEntryTable);
+
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+
+  DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  //
+  // Init DMAr Fault Event and Data registers
+  //
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdUnitBaseAddress);
+
+  //
+  // Invalidate the context cache
+  //
+  InvalidateContextCache (VtdUnitBaseAddress);
+
+  //
+  // Invalidate the IOTLB cache
+  //
+  InvalidateIOTLB (VtdUnitBaseAddress);
+
+  //
+  // Enable VTd
+  //
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+  DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+  DEBUG ((DEBUG_INFO,"VTD () enabled!<<<<<<\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable DMAR translation.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT32    Reg32;
+
+  DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdUnitBaseAddress);
+
+  //
+  // Disable VTd
+  //
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
+
+  MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);
+
+  DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+EnableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  VOID        *RootEntryTable;
+
+  DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask));
+
+  RootEntryTable = AllocatePages (1);
+  ASSERT (RootEntryTable != NULL);
+  if (RootEntryTable == NULL) {
+    DEBUG ((DEBUG_INFO, " EnableVTdTranslationProtection : OutOfResource\n"));
+    return ;
+  }
+
+  ZeroMem (RootEntryTable, EFI_PAGES_TO_SIZE(1));
+  FlushPageTableMemory ((UINTN)RootEntryTable, EFI_PAGES_TO_SIZE(1));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    EnableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index], (UINTN)RootEntryTable);
+  }
+
+  return ;
+}
+
+/**
+  Disable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+DisableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+
+  DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    DisableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+  }
+
+  return ;
+}
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel