public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 0/7] Add VTd as IOMMU for UEFI.
@ 2017-07-18  7:51 Jiewen Yao
  2017-07-18  7:51 ` [PATCH 1/7] IntelSiliconPkg/Include: Add VTD industry standard Jiewen Yao
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

This series patch adds Intel VTd as IOMMU for UEFI BIOS.

It can also be found at https://github.com/jyao1/edk2/tree/vtd.

EDKII IOMMU protocol is already defined in MdeModulePkg.
This patch use VTd to implement IOMMU protocol.

A platform may use VTd to harden the system to prevent DMA attack
once the DMAR table is produced. The VTd engine will be disabled
at EndOfDxe event.

Test:
1) The patch is tested on Intel Kabylake platform and Intel Broadwell platform.
System boot to X64 UEFI Windows 10 successfully, with VTd engine enabled in BIOS.

2) We tested USB XHCI, ATA AHCI and Intel Graphic with DMA protection.

3) If we do not enable DMA access correctly in translation table, the DMA
access is blocked, and the device driver will return error.

More platform tests are on the way.


This series patch includes 1 protocol.
1) EDKII_PLATFORM_VTD_POLICY_PROTOCOL
This protocol is produced by a platform policy module and consumed
by the IntelVTdDxe driver.

1.1) GetDeviceId() API provides ACPI device information for VTd
source ID conversion.

1.2) GetExceptionDeviceList() API provides a list of exception devices.
We notice that a UEFI device driver might not follow UEFI spec to call PCI
map/unmap function for DMA request.

A platform may choose to unsupport the request from exception devices
or add workaround to support these exception device by returning the
device information by using GetExceptionDeviceList().

IntelVTD driver will consume this API to enable all memory access
for the exception device.


This series patch includes below 2 drivers.

1) IntelVTdDxe
It produces IOMMU Protocol and provide DMA protection.

It registers ACPI_SDT callback to check DMAR table.
Once the DMAR table is installed, IntelVTdDxe will enable VTd engine
to start protecting.

In order to use this feature, a platform MUST publish DMAR table
before any DMA transaction. Typically, it is at PciEnumDone protocol
callback.

If a platform does not have VTd support, or VTd is disabled,
the DMA protection will not be activated.

2) PlatformVTdSampleDxe
This is just a sample driver to show how to produce GetDeviceId()
or GetExceptionDeviceList() API.

It should NOT be included directly by any production.

If a platform need produce EDKII_PLATFORM_VTD_POLICY_PROTOCOL, it
should have its own driver.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>

Jiewen Yao (7):
  IntelSiliconPkg/Include: Add VTD industry standard.
  IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol
  IntelSiliconPkg/Dec: Add ProtocolGuid.
  IntelSiliconPkg: Add VTd driver.
  IntelSiliconPkg/dsc: Add Vtd driver.
  IntelSiliconPkg: Add PlatformVTdSample driver.
  IntelSiliconPkg/dsc: Add PlatformVtd sample driver.

 IntelSiliconPkg/Include/IndustryStandard/Vtd.h                     | 345 +++++++
 IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h               | 100 ++
 IntelSiliconPkg/IntelSiliconPkg.dec                                |   3 +
 IntelSiliconPkg/IntelSiliconPkg.dsc                                |  32 +
 IntelSiliconPkg/IntelVTdDxe/BmDma.c                                | 441 +++++++++
 IntelSiliconPkg/IntelVTdDxe/DmaProtection.c                        | 367 +++++++
 IntelSiliconPkg/IntelVTdDxe/DmaProtection.h                        | 501 ++++++++++
 IntelSiliconPkg/IntelVTdDxe/DmarAcpiTable.c                        | 998 ++++++++++++++++++++
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.c                          | 353 +++++++
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf                        |  79 ++
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.uni                        |  20 +
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxeExtra.uni                   |  20 +
 IntelSiliconPkg/IntelVTdDxe/PciInfo.c                              | 315 ++++++
 IntelSiliconPkg/IntelVTdDxe/TranslationTable.c                     | 969 +++++++++++++++++++
 IntelSiliconPkg/IntelVTdDxe/TranslationTableEx.c                   | 153 +++
 IntelSiliconPkg/IntelVTdDxe/VtdReg.c                               | 602 ++++++++++++
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c        | 339 +++++++
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf      |  59 ++
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni      |  20 +
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni |  20 +
 20 files changed, 5736 insertions(+)
 create mode 100644 IntelSiliconPkg/Include/IndustryStandard/Vtd.h
 create mode 100644 IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/BmDma.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/DmaProtection.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/DmaProtection.h
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/DmarAcpiTable.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.uni
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxeExtra.uni
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/PciInfo.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/TranslationTable.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/TranslationTableEx.c
 create mode 100644 IntelSiliconPkg/IntelVTdDxe/VtdReg.c
 create mode 100644 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
 create mode 100644 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
 create mode 100644 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni
 create mode 100644 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni

-- 
2.7.4.windows.1



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/7] IntelSiliconPkg/Include: Add VTD industry standard.
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  2017-07-18  7:51 ` [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol Jiewen Yao
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 345 ++++++++++++++++++++
 1 file changed, 345 insertions(+)

diff --git a/IntelSiliconPkg/Include/IndustryStandard/Vtd.h b/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
new file mode 100644
index 0000000..573ff59
--- /dev/null
+++ b/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
@@ -0,0 +1,345 @@
+/** @file
+  The definition for VTD register.
+  It is defined in "Intel VT for Direct IO Architecture Specification".
+
+  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.
+
+**/
+
+#ifndef __VTD_REG_H__
+#define __VTD_REG_H__
+
+#pragma pack(1)
+
+//
+// Translation Structure Formats
+//
+#define VTD_ROOT_ENTRY_NUMBER       256
+#define VTD_CONTEXT_ENTRY_NUMBER    256
+
+typedef union {
+  struct {
+    UINT64  Present:1;
+    UINT64  Reserved_1:11;
+    UINT64  ContextTablePointer:52;
+
+    UINT64  Reserved_64;
+  } Bits;
+  struct {
+    UINT64  Uint64Lo;
+    UINT64  Uint64Hi;
+  } Uint128;
+} VTD_ROOT_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  LowerPresent:1;
+    UINT64  Reserved_1:11;
+    UINT64  LowerContextTablePointer:52;
+
+    UINT64  UpperPresent:1;
+    UINT64  Reserved_65:11;
+    UINT64  UpperContextTablePointer:52;
+  } Bits;
+  struct {
+    UINT64  Uint64Lo;
+    UINT64  Uint64Hi;
+  } Uint128;
+} VTD_EXT_ROOT_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  Present:1;
+    UINT64  FaultProcessingDisable:1;
+    UINT64  TranslationType:2;
+    UINT64  Reserved_4:8;
+    UINT64  SecondLevelPageTranslationPointer:52;
+
+    UINT64  AddressWidth:3;
+    UINT64  Ignored_67:4;
+    UINT64  Reserved_71:1;
+    UINT64  DomainIdentifier:16;
+    UINT64  Reserved_88:40;
+  } Bits;
+  struct {
+    UINT64  Uint64Lo;
+    UINT64  Uint64Hi;
+  } Uint128;
+} VTD_CONTEXT_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  Present:1;
+    UINT64  FaultProcessingDisable:1;
+    UINT64  TranslationType:3;
+    UINT64  ExtendedMemoryType:3;
+    UINT64  DeferredInvalidateEnable:1;
+    UINT64  PageRequestEnable:1;
+    UINT64  NestedTranslationEnable:1;
+    UINT64  PASIDEnable:1;
+    UINT64  SecondLevelPageTranslationPointer:52;
+
+    UINT64  AddressWidth:3;
+    UINT64  PageGlobalEnable:1;
+    UINT64  NoExecuteEnable:1;
+    UINT64  WriteProtectEnable:1;
+    UINT64  CacheDisable:1;
+    UINT64  ExtendedMemoryTypeEnable:1;
+    UINT64  DomainIdentifier:16;
+    UINT64  SupervisorModeExecuteProtection:1;
+    UINT64  ExtendedAccessedFlagEnable:1;
+    UINT64  ExecuteRequestsEnable:1;
+    UINT64  SecondLevelExecuteEnable:1;
+    UINT64  Reserved_92:4;
+    UINT64  PageAttributeTable0:3;
+    UINT64  Reserved_Pat0:1;
+    UINT64  PageAttributeTable1:3;
+    UINT64  Reserved_Pat1:1;
+    UINT64  PageAttributeTable2:3;
+    UINT64  Reserved_Pat2:1;
+    UINT64  PageAttributeTable3:3;
+    UINT64  Reserved_Pat3:1;
+    UINT64  PageAttributeTable4:3;
+    UINT64  Reserved_Pat4:1;
+    UINT64  PageAttributeTable5:3;
+    UINT64  Reserved_Pat5:1;
+    UINT64  PageAttributeTable6:3;
+    UINT64  Reserved_Pat6:1;
+    UINT64  PageAttributeTable7:3;
+    UINT64  Reserved_Pat7:1;
+
+    UINT64  PASIDTableSize:4;
+    UINT64  Reserved_132:8;
+    UINT64  PASIDTablePointer:52;
+
+    UINT64  Reserved_192:12;
+    UINT64  PASIDStateTablePointer:52;
+  } Bits;
+  struct {
+    UINT64  Uint64_1;
+    UINT64  Uint64_2;
+    UINT64  Uint64_3;
+    UINT64  Uint64_4;
+  } Uint256;
+} VTD_EXT_CONTEXT_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  Present:1;
+    UINT64  Reserved_1:2;
+    UINT64  PageLevelCacheDisable:1;
+    UINT64  PageLevelWriteThrough:1;
+    UINT64  Reserved_5:6;
+    UINT64  SupervisorRequestsEnable:1;
+    UINT64  FirstLevelPageTranslationPointer:52;
+  } Bits;
+  UINT64    Uint64;
+} VTD_PASID_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  Reserved_0:32;
+    UINT64  ActiveReferenceCount:16;
+    UINT64  Reserved_48:15;
+    UINT64  DeferredInvalidate:1;
+  } Bits;
+  UINT64    Uint64;
+} VTD_PASID_STATE_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  Present:1;
+    UINT64  ReadWrite:1;
+    UINT64  UserSupervisor:1;
+    UINT64  PageLevelWriteThrough:1;
+    UINT64  PageLevelCacheDisable:1;
+    UINT64  Accessed:1;
+    UINT64  Dirty:1;
+    UINT64  PageSize:1; // It is PageAttribute:1 for 4K page entry
+    UINT64  Global:1;
+    UINT64  Ignored_9:1;
+    UINT64  ExtendedAccessed:1;
+    UINT64  Ignored_11:1;
+    // NOTE: There is PageAttribute:1 as bit12 for 1G page entry and 2M page entry
+    UINT64  Address:40;
+    UINT64  Ignored_52:11;
+    UINT64  ExecuteDisable:1;
+  } Bits;
+  UINT64    Uint64;
+} VTD_FIRST_LEVEL_PAGING_ENTRY;
+
+typedef union {
+  struct {
+    UINT64  Read:1;
+    UINT64  Write:1;
+    UINT64  Execute:1;
+    UINT64  ExtendedMemoryType:3;
+    UINT64  IgnorePAT:1;
+    UINT64  PageSize:1;
+    UINT64  Ignored_8:3;
+    UINT64  Snoop:1;
+    UINT64  Address:40;
+    UINT64  Ignored_52:10;
+    UINT64  TransientMapping:1;
+    UINT64  Ignored_63:1;
+  } Bits;
+  UINT64    Uint64;
+} VTD_SECOND_LEVEL_PAGING_ENTRY;
+
+//
+// Register Descriptions
+//
+#define R_VER_REG        0x00
+#define R_CAP_REG        0x08
+#define   B_CAP_REG_RWBF       BIT4
+#define R_ECAP_REG       0x10
+#define R_GCMD_REG       0x18
+#define   B_GMCD_REG_WBF       BIT27
+#define   B_GMCD_REG_SRTP      BIT30
+#define   B_GMCD_REG_TE        BIT31
+#define R_GSTS_REG       0x1C
+#define   B_GSTS_REG_WBF       BIT27
+#define   B_GSTS_REG_RTPS      BIT30
+#define   B_GSTS_REG_TE        BIT31
+#define R_RTADDR_REG     0x20
+#define R_CCMD_REG       0x28
+#define   B_CCMD_REG_CIRG_MASK    (BIT62|BIT61)
+#define   V_CCMD_REG_CIRG_GLOBAL  BIT61
+#define   V_CCMD_REG_CIRG_DOMAIN  BIT62
+#define   V_CCMD_REG_CIRG_DEVICE  (BIT62|BIT61)
+#define   B_CCMD_REG_ICC          BIT63
+#define R_FSTS_REG       0x34
+#define R_FECTL_REG      0x38
+#define R_FEDATA_REG     0x3C
+#define R_FEADDR_REG     0x40
+#define R_FEUADDR_REG    0x44
+#define R_AFLOG_REG      0x58
+#define R_PMEN_REG       0x64
+
+#define R_IVA_REG        0x00 // + IRO
+#define   B_IVA_REG_AM_MASK       (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5)
+#define   B_IVA_REG_AM_4K         0 // 1 page
+#define   B_IVA_REG_AM_2M         9 // 2M page
+#define   B_IVA_REG_IH            BIT6
+#define R_IOTLB_REG      0x08 // + IRO
+#define   B_IOTLB_REG_IIRG_MASK   (BIT61|BIT60)
+#define   V_IOTLB_REG_IIRG_GLOBAL BIT60
+#define   V_IOTLB_REG_IIRG_DOMAIN BIT61
+#define   V_IOTLB_REG_IIRG_PAGE   (BIT61|BIT60)
+#define   B_IOTLB_REG_IVT         BIT63
+
+#define R_FRCD_REG       0x00 // + FRO
+
+typedef union {
+  struct {
+    UINT8         ND:3; // Number of domains supported
+    UINT8         AFL:1; // Advanced Fault Logging
+    UINT8         RWBF:1; // Required Write-Buffer Flushing
+    UINT8         PLMR:1; // Protected Low-Memory Region
+    UINT8         PHMR:1; // Protected High-Memory Region
+    UINT8         CM:1; // Caching Mode
+
+    UINT8         SAGAW:5; // Supported Adjusted Guest Address Widths
+    UINT8         Rsvd_13:3;
+
+    UINT8         MGAW:6; // Maximum Guest Address Width
+    UINT8         ZLR:1; // Zero Length Read
+    UINT8         Rsvd_23:1;
+
+    UINT16        FRO:10; // Fault-recording Register offset
+    UINT16        SLLPS:4; // Second Level Large Page Support
+    UINT16        Rsvd_38:1;
+    UINT16        PSI:1; // Page Selective Invalidation
+
+    UINT8         NFR:8; // Number of Fault-recording Registers
+
+    UINT8         MAMV:6; // Maximum Address Mask Value
+    UINT8         DWD:1; // Write Draining
+    UINT8         DRD:1; // Read Draining
+
+    UINT8         FL1GP:1; // First Level 1-GByte Page Support
+    UINT8         Rsvd_57:2;
+    UINT8         PI:1; // Posted Interrupts Support
+    UINT8         Rsvd_60:4;
+  } Bits;
+  UINT64     Uint64;
+} VTD_CAP_REG;
+
+typedef union {
+  struct {
+    UINT8         C:1; // Page-walk Coherency
+    UINT8         QI:1; // Queued Invalidation support
+    UINT8         DT:1; // Device-TLB support
+    UINT8         IR:1; // Interrupt Remapping support
+    UINT8         EIM:1; // Extended Interrupt Mode
+    UINT8         Rsvd_5:1;
+    UINT8         PT:1; // Pass Through
+    UINT8         SC:1; // Snoop Control
+
+    UINT16        IRO:10; // IOTLB Register Offset
+    UINT16        Rsvd_18:2;
+    UINT16        MHMV:4; // Maximum Handle Mask Value
+
+    UINT8         ECS:1; // Extended Context Support
+    UINT8         MTS:1; // Memory Type Support
+    UINT8         NEST:1; // Nested Translation Support
+    UINT8         DIS:1; // Deferred Invalidate Support
+    UINT8         PASID:1; // Process Address Space ID Support
+    UINT8         PRS:1; // Page Request Support
+    UINT8         ERS:1; // Execute Request Support
+    UINT8         SRS:1; // Supervisor Request Support
+
+    UINT32        Rsvd_32:1;
+    UINT32        NWFS:1; // No Write Flag Support
+    UINT32        EAFS:1; // Extended Accessed Flag Support
+    UINT32        PSS:5; // PASID Size Supported
+
+    UINT32        Rsvd_40:24;
+  } Bits;
+  UINT64     Uint64;
+} VTD_ECAP_REG;
+
+typedef union {
+  struct {
+    UINT64   Rsvd_0:12;
+    UINT64   FI:52;        // FaultInfo
+
+    UINT32   SID:16;       // Source Identifier
+    UINT32   Rsvd_80:13;
+    UINT32   PRIV:1;       // Privilege Mode Requested
+    UINT32   EXE:1;        // Execute Permission Requested
+    UINT32   PP:1;         // PASID Present
+
+    UINT32   FR:8;         // Fault Reason
+    UINT32   PV:20;        // PASID Value
+    UINT32   AT:2;         // Address Type
+    UINT32   T:1;          // Type (0: Write, 1: Read)
+    UINT32   F:1;          // Fault
+  } Bits;
+  UINT64     Uint64[2];
+} VTD_FRCD_REG;
+
+typedef union {
+  struct {
+    UINT8    Function:3;
+    UINT8    Device:5;
+    UINT8    Bus;
+  } Bits;
+  struct {
+    UINT8    ContextIndex;
+    UINT8    RootIndex;
+  } Index;
+  UINT16     Uint16;
+} VTD_SOURCE_ID;
+
+#pragma pack()
+
+#endif
+
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
  2017-07-18  7:51 ` [PATCH 1/7] IntelSiliconPkg/Include: Add VTD industry standard Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  2017-07-26  8:36   ` Zeng, Star
  2017-07-18  7:51 ` [PATCH 3/7] IntelSiliconPkg/Dec: Add ProtocolGuid Jiewen Yao
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h | 100 ++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h b/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
new file mode 100644
index 0000000..1bd9365
--- /dev/null
+++ b/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
@@ -0,0 +1,100 @@
+/** @file
+  The definition for platform VTD policy.
+
+  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.
+
+**/
+
+#ifndef __PLATFORM_VTD_POLICY_PROTOCOL_H__
+#define __PLATFORM_VTD_POLICY_PROTOCOL_H__
+
+#include <IndustryStandard/Vtd.h>
+
+#define EDKII_PLATFORM_VTD_POLICY_PROTOCOL_GUID \
+    { \
+      0x3d17e448, 0x466, 0x4e20, { 0x99, 0x9f, 0xb2, 0xe1, 0x34, 0x88, 0xee, 0x22 } \
+    }
+
+typedef struct _EDKII_PLATFORM_VTD_POLICY_PROTOCOL  EDKII_PLATFORM_VTD_POLICY_PROTOCOL;
+
+#define EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION 0x00010000
+
+typedef struct {
+  UINT16                                   Segment;
+  VTD_SOURCE_ID                            SourceId;
+} EDKII_PLATFORM_VTD_DEVICE_INFO;
+
+/**
+  Get the VTD SourceId from the device handler.
+  This function is required for non PCI device handler.
+
+  Pseudo-algo in Intel VTd driver:
+    Status = PlatformGetVTdDeviceId ();
+    if (EFI_ERROR(Status)) {
+      if (DeviceHandle is PCI) {
+        Get SourceId from Bus/Device/Function
+      } else {
+        return EFI_UNSUPPORTED
+      }
+    }
+    Get VTd engine by Segment/Bus/Device/Function.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[in]  DeviceHandle          Device Identifier in UEFI.
+  @param[out] DeviceInfo            DeviceInfo for indentify the VTd engine in ACPI Table
+                                    and the VTd page entry.
+
+  @retval EFI_SUCCESS           The VtdIndex and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
+  @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
+  @retval EFI_NOT_FOUND         The Segment or SourceId information is NOT found.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_VTD_POLICY_GET_DEVICE_ID) (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  IN  EFI_HANDLE                               DeviceHandle,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           *DeviceInfo
+  );
+
+/**
+  Get a list of handles for the exception devices.
+
+  The VTd driver should always set ALLOW for the device in this list.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[out] DeviceInfoCount       The count of the list of DeviceInfo.
+  @param[out] DeviceInfo            A callee allocated buffer to hold a list of DeviceInfo.
+
+  @retval EFI_SUCCESS           The DeviceInfoCount and DeviceInfo are returned.
+  @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST) (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  OUT UINTN                                    *DeviceInfoCount,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           **DeviceInfo
+  );
+
+struct _EDKII_PLATFORM_VTD_POLICY_PROTOCOL {
+  UINT64                                               Revision;
+  EDKII_PLATFORM_VTD_POLICY_GET_DEVICE_ID              GetDeviceId;
+  EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST  GetExceptionDeviceList;
+};
+
+extern EFI_GUID gEdkiiPlatformVTdPolicyProtocolGuid;
+
+#endif
+
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/7] IntelSiliconPkg/Dec: Add ProtocolGuid.
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
  2017-07-18  7:51 ` [PATCH 1/7] IntelSiliconPkg/Include: Add VTD industry standard Jiewen Yao
  2017-07-18  7:51 ` [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  2017-07-18  7:51 ` [PATCH 4/7] IntelSiliconPkg: Add VTd driver Jiewen Yao
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/IntelSiliconPkg.dec | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/IntelSiliconPkg/IntelSiliconPkg.dec b/IntelSiliconPkg/IntelSiliconPkg.dec
index 8819cb8..663a232 100644
--- a/IntelSiliconPkg/IntelSiliconPkg.dec
+++ b/IntelSiliconPkg/IntelSiliconPkg.dec
@@ -33,6 +33,9 @@
   # Generic DXE Library / Driver can locate HOB(s) and add SMBIOS records into SMBIOS table
   gIntelSmbiosDataHobGuid         = { 0x798e722e, 0x15b2, 0x4e13, { 0x8a, 0xe9, 0x6b, 0xa3, 0x0f, 0xf7, 0xf1, 0x67 }}
 
+[Protocols]
+  gEdkiiPlatformVTdPolicyProtocolGuid = { 0x3d17e448, 0x466, 0x4e20, { 0x99, 0x9f, 0xb2, 0xe1, 0x34, 0x88, 0xee, 0x22 }}
+
 [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   ## This is the GUID of the FFS which contains the Graphics Video BIOS Table (VBT)
   # The VBT content is stored as a RAW section which is consumed by GOP PEI/UEFI driver.
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/7] IntelSiliconPkg: Add VTd driver.
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
                   ` (2 preceding siblings ...)
  2017-07-18  7:51 ` [PATCH 3/7] IntelSiliconPkg/Dec: Add ProtocolGuid Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  2017-07-18  7:51 ` [PATCH 5/7] IntelSiliconPkg/dsc: Add Vtd driver Jiewen Yao
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

It provides AllocateBuffer/FreeBuffer/Map/Unmap function.
It also provides VTd capability yet.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/IntelVTdDxe/BmDma.c              | 441 +++++++++
 IntelSiliconPkg/IntelVTdDxe/DmaProtection.c      | 367 +++++++
 IntelSiliconPkg/IntelVTdDxe/DmaProtection.h      | 501 ++++++++++
 IntelSiliconPkg/IntelVTdDxe/DmarAcpiTable.c      | 998 ++++++++++++++++++++
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.c        | 353 +++++++
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf      |  79 ++
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.uni      |  20 +
 IntelSiliconPkg/IntelVTdDxe/IntelVTdDxeExtra.uni |  20 +
 IntelSiliconPkg/IntelVTdDxe/PciInfo.c            | 315 ++++++
 IntelSiliconPkg/IntelVTdDxe/TranslationTable.c   | 969 +++++++++++++++++++
 IntelSiliconPkg/IntelVTdDxe/TranslationTableEx.c | 153 +++
 IntelSiliconPkg/IntelVTdDxe/VtdReg.c             | 602 ++++++++++++
 12 files changed, 4818 insertions(+)

diff --git a/IntelSiliconPkg/IntelVTdDxe/BmDma.c b/IntelSiliconPkg/IntelVTdDxe/BmDma.c
new file mode 100644
index 0000000..5dcee00
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/BmDma.c
@@ -0,0 +1,441 @@
+/** @file
+  BmDma related function
+
+  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 <PiDxe.h>
+
+#include <Protocol/IoMmu.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+// TBD: May make it a policy
+#define DMA_MEMORY_TOP          MAX_UINTN
+//#define DMA_MEMORY_TOP          0x0000000001FFFFFFULL
+
+#define MAP_INFO_SIGNATURE  SIGNATURE_32 ('D', 'M', 'A', 'P')
+typedef struct {
+  UINT32                                    Signature;
+  LIST_ENTRY                                Link;
+  EDKII_IOMMU_OPERATION                     Operation;
+  UINTN                                     NumberOfBytes;
+  UINTN                                     NumberOfPages;
+  EFI_PHYSICAL_ADDRESS                      HostAddress;
+  EFI_PHYSICAL_ADDRESS                      DeviceAddress;
+} MAP_INFO;
+#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)
+
+LIST_ENTRY                        gMaps = INITIALIZE_LIST_HEAD_VARIABLE(gMaps);
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  This                  The protocol instance pointer.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuMap (
+  IN     EDKII_IOMMU_PROTOCOL                       *This,
+  IN     EDKII_IOMMU_OPERATION                      Operation,
+  IN     VOID                                       *HostAddress,
+  IN OUT UINTN                                      *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
+  OUT    VOID                                       **Mapping
+  )
+{
+  EFI_STATUS                                        Status;
+  EFI_PHYSICAL_ADDRESS                              PhysicalAddress;
+  MAP_INFO                                          *MapInfo;
+  EFI_PHYSICAL_ADDRESS                              DmaMemoryTop;
+  BOOLEAN                                           NeedRemap;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress, NumberOfBytes, Operation));
+
+  if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
+      Mapping == NULL) {
+    DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Make sure that Operation is valid
+  //
+  if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {
+    DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+  NeedRemap = FALSE;
+  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+
+  DmaMemoryTop = DMA_MEMORY_TOP;
+
+  //
+  // Alignment check
+  //
+  if ((*NumberOfBytes != ALIGN_VALUE(*NumberOfBytes, SIZE_4KB)) ||
+      (PhysicalAddress != ALIGN_VALUE(PhysicalAddress, SIZE_4KB))) {
+    if ((Operation == EdkiiIoMmuOperationBusMasterCommonBuffer) ||
+        (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64)) {
+      //
+      // The input buffer might be a subset from IoMmuAllocateBuffer.
+      // Skip the check.
+      //
+    } else {
+      NeedRemap = TRUE;
+    }
+  }
+
+  if ((PhysicalAddress + *NumberOfBytes) >= DMA_MEMORY_TOP) {
+    NeedRemap = TRUE;
+  }
+
+  if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&
+        Operation != EdkiiIoMmuOperationBusMasterWrite64 &&
+        Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&
+      ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {
+    //
+    // If the root bridge or the device cannot handle performing DMA above
+    // 4GB but any part of the DMA transfer being mapped is above 4GB, then
+    // map the DMA transfer to a buffer below 4GB.
+    //
+    NeedRemap = TRUE;
+    DmaMemoryTop = MIN (DmaMemoryTop, SIZE_4GB - 1);
+  }
+
+  if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
+      Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
+    if (NeedRemap) {
+      //
+      // Common Buffer operations can not be remapped.  If the common buffer
+      // if above 4GB, then it is not possible to generate a mapping, so return
+      // an error.
+      //
+      DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_UNSUPPORTED));
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
+  // called later.
+  //
+  MapInfo = AllocatePool (sizeof (MAP_INFO));
+  if (MapInfo == NULL) {
+    *NumberOfBytes = 0;
+    DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the MAP_INFO structure
+  //
+  MapInfo->Signature         = MAP_INFO_SIGNATURE;
+  MapInfo->Operation         = Operation;
+  MapInfo->NumberOfBytes     = *NumberOfBytes;
+  MapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
+  MapInfo->HostAddress       = PhysicalAddress;
+  MapInfo->DeviceAddress     = DmaMemoryTop;
+
+  //
+  // Allocate a buffer below 4GB to map the transfer to.
+  //
+  if (NeedRemap) {
+    Status = gBS->AllocatePages (
+                    AllocateMaxAddress,
+                    EfiBootServicesData,
+                    MapInfo->NumberOfPages,
+                    &MapInfo->DeviceAddress
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (MapInfo);
+      *NumberOfBytes = 0;
+      DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", Status));
+      return Status;
+    }
+
+    //
+    // If this is a read operation from the Bus Master's point of view,
+    // then copy the contents of the real buffer into the mapped buffer
+    // so the Bus Master can read the contents of the real buffer.
+    //
+    if (Operation == EdkiiIoMmuOperationBusMasterRead ||
+        Operation == EdkiiIoMmuOperationBusMasterRead64) {
+      CopyMem (
+        (VOID *) (UINTN) MapInfo->DeviceAddress,
+        (VOID *) (UINTN) MapInfo->HostAddress,
+        MapInfo->NumberOfBytes
+        );
+    }
+  } else {
+    MapInfo->DeviceAddress = MapInfo->HostAddress;
+  }
+
+  InsertTailList (&gMaps, &MapInfo->Link);
+
+  //
+  // The DeviceAddress is the address of the maped buffer below 4GB
+  //
+  *DeviceAddress = MapInfo->DeviceAddress;
+  //
+  // Return a pointer to the MAP_INFO structure in Mapping
+  //
+  *Mapping       = MapInfo;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress, *Mapping));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  The protocol instance pointer.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IoMmuUnmap (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  VOID                                     *Mapping
+  )
+{
+  MAP_INFO                 *MapInfo;
+  LIST_ENTRY               *Link;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuUnmap: 0x%08x\n", Mapping));
+
+  if (Mapping == NULL) {
+    DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MapInfo = NULL;
+  for (Link = GetFirstNode (&gMaps)
+       ; !IsNull (&gMaps, Link)
+       ; Link = GetNextNode (&gMaps, Link)
+       ) {
+    MapInfo = MAP_INFO_FROM_LINK (Link);
+    if (MapInfo == Mapping) {
+      break;
+    }
+  }
+  //
+  // Mapping is not a valid value returned by Map()
+  //
+  if (MapInfo != Mapping) {
+    DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+  RemoveEntryList (&MapInfo->Link);
+
+  if (MapInfo->DeviceAddress != MapInfo->HostAddress) {
+    //
+    // If this is a write operation from the Bus Master's point of view,
+    // then copy the contents of the mapped buffer into the real buffer
+    // so the processor can read the contents of the real buffer.
+    //
+    if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||
+        MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {
+      CopyMem (
+        (VOID *) (UINTN) MapInfo->HostAddress,
+        (VOID *) (UINTN) MapInfo->DeviceAddress,
+        MapInfo->NumberOfBytes
+        );
+    }
+
+    //
+    // Free the mapped buffer and the MAP_INFO structure.
+    //
+    gBS->FreePages (MapInfo->DeviceAddress, MapInfo->NumberOfPages);
+  }
+
+  FreePool (Mapping);
+  return EFI_SUCCESS;
+}
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  This                  The protocol instance pointer.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuAllocateBuffer (
+  IN     EDKII_IOMMU_PROTOCOL                     *This,
+  IN     EFI_ALLOCATE_TYPE                        Type,
+  IN     EFI_MEMORY_TYPE                          MemoryType,
+  IN     UINTN                                    Pages,
+  IN OUT VOID                                     **HostAddress,
+  IN     UINT64                                   Attributes
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PHYSICAL_ADDRESS      PhysicalAddress;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages));
+
+  //
+  // Validate Attributes
+  //
+  if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
+    DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check for invalid inputs
+  //
+  if (HostAddress == NULL) {
+    DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // The only valid memory types are EfiBootServicesData and
+  // EfiRuntimeServicesData
+  //
+  if (MemoryType != EfiBootServicesData &&
+      MemoryType != EfiRuntimeServicesData) {
+    DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PhysicalAddress = DMA_MEMORY_TOP;
+  if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+    //
+    // Limit allocations to memory below 4GB
+    //
+    PhysicalAddress = MIN (PhysicalAddress, SIZE_4GB - 1);
+  }
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  MemoryType,
+                  Pages,
+                  &PhysicalAddress
+                  );
+  if (!EFI_ERROR (Status)) {
+    *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress));
+
+  return Status;
+}
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  The protocol instance pointer.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuFreeBuffer (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  UINTN                                    Pages,
+  IN  VOID                                     *HostAddress
+  )
+{
+  DEBUG ((DEBUG_VERBOSE, "IoMmuFreeBuffer: 0x%\n", Pages));
+  return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
+}
+
+/**
+  Get device information from mapping.
+
+  @param[in]  Mapping        The mapping.
+  @param[out] DeviceAddress  The device address of the mapping.
+  @param[out] NumberOfPages  The number of pages of the mapping.
+
+  @retval EFI_SUCCESS            The device information is returned.
+  @retval EFI_INVALID_PARAMETER  The mapping is invalid.
+**/
+EFI_STATUS
+GetDeviceInfoFromMapping (
+  IN  VOID                                     *Mapping,
+  OUT EFI_PHYSICAL_ADDRESS                     *DeviceAddress,
+  OUT UINTN                                    *NumberOfPages
+  )
+{
+  MAP_INFO                 *MapInfo;
+  LIST_ENTRY               *Link;
+
+  if (Mapping == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MapInfo = NULL;
+  for (Link = GetFirstNode (&gMaps)
+       ; !IsNull (&gMaps, Link)
+       ; Link = GetNextNode (&gMaps, Link)
+       ) {
+    MapInfo = MAP_INFO_FROM_LINK (Link);
+    if (MapInfo == Mapping) {
+      break;
+    }
+  }
+  //
+  // Mapping is not a valid value returned by Map()
+  //
+  if (MapInfo != Mapping) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DeviceAddress = MapInfo->DeviceAddress;
+  *NumberOfPages = MapInfo->NumberOfPages;
+  return EFI_SUCCESS;
+}
+
diff --git a/IntelSiliconPkg/IntelVTdDxe/DmaProtection.c b/IntelSiliconPkg/IntelVTdDxe/DmaProtection.c
new file mode 100644
index 0000000..f0628b5
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/DmaProtection.c
@@ -0,0 +1,367 @@
+/** @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 "DmaProtection.h"
+
+EFI_ACPI_SDT_PROTOCOL                   *mAcpiSdt;
+UINT64                                  mBelow4GMemoryLimit;
+UINT64                                  mAbove4GMemoryLimit;
+
+EDKII_PLATFORM_VTD_POLICY_PROTOCOL      *mPlatformVTdPolicy;
+
+/**
+  return the UEFI memory information.
+
+  @param[out] Below4GMemoryLimit  The below 4GiB memory limit
+  @param[out] Above4GMemoryLimit  The above 4GiB memory limit
+**/
+VOID
+ReturnUefiMemoryMap (
+  OUT UINT64   *Below4GMemoryLimit,
+  OUT UINT64   *Above4GMemoryLimit
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMap;
+  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMapEnd;
+  EFI_MEMORY_DESCRIPTOR       *EfiEntry;
+  EFI_MEMORY_DESCRIPTOR       *NextEfiEntry;
+  EFI_MEMORY_DESCRIPTOR       TempEfiEntry;
+  UINTN                       EfiMemoryMapSize;
+  UINTN                       EfiMapKey;
+  UINTN                       EfiDescriptorSize;
+  UINT32                      EfiDescriptorVersion;
+  UINT64                      MemoryBlockLength;
+
+  *Below4GMemoryLimit = 0;
+  *Above4GMemoryLimit = 0;
+
+  //
+  // Get the EFI memory map.
+  //
+  EfiMemoryMapSize  = 0;
+  EfiMemoryMap      = NULL;
+  Status = gBS->GetMemoryMap (
+                  &EfiMemoryMapSize,
+                  EfiMemoryMap,
+                  &EfiMapKey,
+                  &EfiDescriptorSize,
+                  &EfiDescriptorVersion
+                  );
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+  do {
+    //
+    // Use size returned back plus 1 descriptor for the AllocatePool.
+    // We don't just multiply by 2 since the "for" loop below terminates on
+    // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
+    // we process bogus entries and create bogus E820 entries.
+    //
+    EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
+    ASSERT (EfiMemoryMap != NULL);
+    Status = gBS->GetMemoryMap (
+                    &EfiMemoryMapSize,
+                    EfiMemoryMap,
+                    &EfiMapKey,
+                    &EfiDescriptorSize,
+                    &EfiDescriptorVersion
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (EfiMemoryMap);
+    }
+  } while (Status == EFI_BUFFER_TOO_SMALL);
+
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Sort memory map from low to high
+  //
+  EfiEntry        = EfiMemoryMap;
+  NextEfiEntry    = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+  while (EfiEntry < EfiMemoryMapEnd) {
+    while (NextEfiEntry < EfiMemoryMapEnd) {
+      if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
+        CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+        CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+        CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+      }
+
+      NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
+    }
+
+    EfiEntry      = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+    NextEfiEntry  = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+  }
+
+  //
+  //
+  //
+  DEBUG ((DEBUG_INFO, "MemoryMap:\n"));
+  EfiEntry        = EfiMemoryMap;
+  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+  while (EfiEntry < EfiMemoryMapEnd) {
+    MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
+    DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));
+    switch (EfiEntry->Type) {
+    case EfiLoaderCode:
+    case EfiLoaderData:
+    case EfiBootServicesCode:
+    case EfiBootServicesData:
+    case EfiConventionalMemory:
+    case EfiRuntimeServicesCode:
+    case EfiRuntimeServicesData:
+    case EfiACPIReclaimMemory:
+    case EfiACPIMemoryNVS:
+    case EfiReservedMemoryType:
+      if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {
+        //
+        // Skip the memory block is under 1MB
+        //
+      } else if (EfiEntry->PhysicalStart >= BASE_4GB) {
+        if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
+          *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
+        }
+      } else {
+        if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
+          *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
+        }
+      }
+      break;
+    }
+    EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+  }
+
+  FreePool (EfiMemoryMap);
+
+  DEBUG ((DEBUG_INFO, "Result:\n"));
+  DEBUG ((DEBUG_INFO, "Below4GMemoryLimit:  0x%016lx\n", *Below4GMemoryLimit));
+  DEBUG ((DEBUG_INFO, "Above4GMemoryLimit:  0x%016lx\n", *Above4GMemoryLimit));
+
+  return ;
+}
+
+/**
+  Initialize platform VTd policy.
+**/
+VOID
+InitializePlatformVTdPolicy (
+  VOID
+  )
+{
+  EFI_STATUS                        Status;
+  UINTN                             DeviceInfoCount;
+  EDKII_PLATFORM_VTD_DEVICE_INFO    *DeviceInfo;
+  UINTN                             Index;
+
+  //
+  // It is optional.
+  //
+  Status = gBS->LocateProtocol (
+                  &gEdkiiPlatformVTdPolicyProtocolGuid,
+                  NULL,
+                  (VOID **)&mPlatformVTdPolicy
+                  );
+  if (!EFI_ERROR(Status)) {
+    Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);
+    if (!EFI_ERROR(Status)) {
+      for (Index = 0; Index < DeviceInfoCount; Index++) {
+        AlwaysEnablePageAttribute (DeviceInfo[Index].Segment, DeviceInfo[Index].SourceId);
+      }
+      FreePool (DeviceInfo);
+    }
+  }
+}
+
+/**
+  Setup VTd engine.
+**/
+VOID
+SetupVtd (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  VOID            *PciEnumerationComplete;
+  UINTN           Index;
+  UINT64          Below4GMemoryLimit;
+  UINT64          Above4GMemoryLimit;
+
+  //
+  // PCI Enumeration must be done
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiPciEnumerationCompleteProtocolGuid,
+                  NULL,
+                  &PciEnumerationComplete
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);
+  Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);
+  DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));
+
+  mBelow4GMemoryLimit = Below4GMemoryLimit;
+  mAbove4GMemoryLimit = Above4GMemoryLimit;
+
+  //
+  // 1. setup
+  //
+  DEBUG ((DEBUG_INFO, "GetDmarAcpiTable\n"));
+  Status = GetDmarAcpiTable ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));
+  Status = ParseDmarAcpiTableDrhd ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
+  PrepareVtdConfig ();
+
+  //
+  // 2. initialization
+  //
+  DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));
+  Status = SetupTranslationTable ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  InitializePlatformVTdPolicy ();
+
+  ParseDmarAcpiTableRmrr ();
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));
+    if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {
+      DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);
+    }
+    if (mVtdUnitInformation[Index].RootEntryTable != NULL) {
+      DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);
+    }
+  }
+
+  //
+  // 3. enable
+  //
+  DEBUG ((DEBUG_INFO, "EnableDmar\n"));
+  Status = EnableDmar ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));
+  DumpVtdRegsAll ();
+}
+
+/**
+  ACPI notification function.
+
+  @param[in] Table    A pointer to the ACPI table header.
+  @param[in] Version  The ACPI table's version.
+  @param[in] TableKey The table key for this ACPI table.
+
+  @retval EFI_SUCCESS The notification function is executed.
+**/
+EFI_STATUS
+EFIAPI
+AcpiNotificationFunc (
+  IN EFI_ACPI_SDT_HEADER    *Table,
+  IN EFI_ACPI_TABLE_VERSION Version,
+  IN UINTN                  TableKey
+  )
+{
+  if (Table->Signature == EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE) {
+    DEBUG((DEBUG_INFO, "Vtd AcpiNotificationFunc\n"));
+    SetupVtd ();
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Exit boot service callback function.
+
+  @param[in]  Event    The event handle.
+  @param[in]  Context  The event content.
+**/
+VOID
+EFIAPI
+OnExitBootServices (
+  IN EFI_EVENT                               Event,
+  IN VOID                                    *Context
+  )
+{
+  DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));
+  DumpVtdRegsAll ();
+  DisableDmar ();
+  DumpVtdRegsAll ();
+}
+
+/**
+  Legacy boot callback function.
+
+  @param[in]  Event    The event handle.
+  @param[in]  Context  The event content.
+**/
+VOID
+EFIAPI
+OnLegacyBoot (
+  EFI_EVENT                               Event,
+  VOID                                    *Context
+  )
+{
+  DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));
+  DumpVtdRegsAll ();
+  DisableDmar ();
+  DumpVtdRegsAll ();
+}
+
+/**
+  Initialize DMA protection.
+**/
+VOID
+InitializeDmaProtection (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   ExitBootServicesEvent;
+  EFI_EVENT   LegacyBootEvent;
+
+  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **) &mAcpiSdt);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = mAcpiSdt->RegisterNotify (TRUE, AcpiNotificationFunc);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  OnExitBootServices,
+                  NULL,
+                  &gEfiEventExitBootServicesGuid,
+                  &ExitBootServicesEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = EfiCreateEventLegacyBootEx (
+             TPL_NOTIFY,
+             OnLegacyBoot,
+             NULL,
+             &LegacyBootEvent
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return ;
+}
diff --git a/IntelSiliconPkg/IntelVTdDxe/DmaProtection.h b/IntelSiliconPkg/IntelVTdDxe/DmaProtection.h
new file mode 100644
index 0000000..6efed6e
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/DmaProtection.h
@@ -0,0 +1,501 @@
+/** @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.
+
+**/
+
+#ifndef _DMAR_PROTECTION_H_
+#define _DMAR_PROTECTION_H_
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/Acpi.h>
+
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciEnumerationComplete.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/PlatformVtdPolicy.h>
+#include <Protocol/IoMmu.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/DmaRemappingReportingTable.h>
+#include <IndustryStandard/Vtd.h>
+
+#define ALIGN_VALUE_UP(Value, Alignment)  (((Value) + (Alignment) - 1) & (~((Alignment) - 1)))
+#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))
+
+//
+// This is the initial max PCI descriptor.
+// The number may be enlarged later.
+//
+#define MAX_PCI_DESCRIPTORS             0x100
+
+typedef struct {
+  BOOLEAN                IncludeAllFlag;
+  UINTN                  PciDescriptorNumber;
+  UINTN                  PciDescriptorMaxNumber;
+  BOOLEAN                *IsRealPciDevice;
+  VTD_SOURCE_ID          *PciDescriptors;
+} PCI_DEVICE_INFORMATION;
+
+typedef struct {
+  UINTN                            VtdUnitBaseAddress;
+  UINT16                           Segment;
+  VTD_CAP_REG                      CapReg;
+  VTD_ECAP_REG                     ECapReg;
+  VTD_ROOT_ENTRY                   *RootEntryTable;
+  VTD_EXT_ROOT_ENTRY               *ExtRootEntryTable;
+  VTD_SECOND_LEVEL_PAGING_ENTRY    *FixedSecondLevelPagingEntry;
+  BOOLEAN                          HasDirtyPages;
+  PCI_DEVICE_INFORMATION           PciDeviceInfo;
+} VTD_UNIT_INFORMATION;
+
+extern EFI_ACPI_DMAR_HEADER  *mAcpiDmarTable;
+
+extern UINT64                           mVtdHostAddressWidthMask;
+extern UINTN                            mVtdUnitNumber;
+extern VTD_UNIT_INFORMATION             *mVtdUnitInformation;
+
+extern UINT64                           mBelow4GMemoryLimit;
+extern UINT64                           mAbove4GMemoryLimit;
+
+extern EDKII_PLATFORM_VTD_POLICY_PROTOCOL   *mPlatformVTdPolicy;
+
+/**
+  Prepare VTD configuration.
+**/
+VOID
+PrepareVtdConfig (
+  VOID
+  );
+
+/**
+  Setup VTd translation table.
+
+  @retval EFI_SUCCESS           Setup translation table successfully.
+  @retval EFI_OUT_OF_RESOURCE   Setup translation table fail.
+**/
+EFI_STATUS
+SetupTranslationTable (
+  VOID
+  );
+
+/**
+  Enable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  VOID
+  );
+
+/**
+  Disable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  VOID
+  );
+
+/**
+  Invalid VTd IOTLB page.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Address               The address of IOTLB page.
+  @param[in]  AddressMode           The address mode of IOTLB page.
+  @param[in]  DomainIdentifier      The domain ID of the source.
+
+  @retval EFI_SUCCESS           VTd IOTLB page is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd IOTLB page is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBPage (
+  IN UINTN  VtdIndex,
+  IN UINT64 Address,
+  IN UINT8  AddressMode,
+  IN UINT16 DomainIdentifier
+  );
+
+/**
+  Invalid VTd IOTLB domain.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  DomainIdentifier      The domain ID of the source.
+
+  @retval EFI_SUCCESS           VTd IOTLB domain is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd IOTLB domain is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBDomain (
+  IN UINTN  VtdIndex,
+  IN UINT16 DomainIdentifier
+  );
+
+/**
+  Invalid VTd global IOTLB.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+
+  @retval EFI_SUCCESS           VTd global IOTLB is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd global IOTLB is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBGlobal (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Dump VTd registers.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpVtdRegs (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Dump VTd registers for all VTd engine.
+**/
+VOID
+DumpVtdRegsAll (
+  VOID
+  );
+
+/**
+  Dump VTd capability registers.
+
+  @param[in]  CapReg              The capability register.
+**/
+VOID
+DumpVtdCapRegs (
+  IN VTD_CAP_REG *CapReg
+  );
+
+/**
+  Dump VTd extended capability registers.
+
+  @param[in]  ECapReg              The extended capability register.
+**/
+VOID
+DumpVtdECapRegs (
+  IN VTD_ECAP_REG *ECapReg
+  );
+
+/**
+  Register PCI device to VTd engine as PCI descriptor.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[in]  IsRealPciDevice       TRUE: It is a real PCI device.
+                                    FALSE: It is not a real PCI device.
+  @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.
+                                    FALSE: SUCCESS will be returned if the PCI device is registered.
+
+  @retval EFI_SUCCESS           The PCI device is registered.
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
+  @retval EFI_ALREADY_STARTED   The device is already registered.
+**/
+EFI_STATUS
+RegisterPciDevice (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId,
+  IN BOOLEAN        IsRealPciDevice,
+  IN BOOLEAN        CheckExist
+  );
+
+/**
+  Scan PCI bus and register PCI devices under the bus.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+
+  @retval EFI_SUCCESS           The PCI devices under the bus are registered.
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
+**/
+EFI_STATUS
+ScanPciBus (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN UINT8          Bus
+  );
+
+/**
+  Dump the PCI device information managed by this VTd engine.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpPciDeviceInfo (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Find the VTd index by the Segment and SourceId.
+
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[out] ExtContextEntry       The ExtContextEntry of the source.
+  @param[out] ContextEntry          The ContextEntry of the source.
+
+  @return The index of the PCI descriptor.
+  @retval (UINTN)-1  The PCI descriptor is not found.
+**/
+UINTN
+FindVtdIndexByPciDevice (
+  IN  UINT16                  Segment,
+  IN  VTD_SOURCE_ID           SourceId,
+  OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,
+  OUT VTD_CONTEXT_ENTRY       **ContextEntry
+  );
+
+/**
+  Get the DMAR ACPI table.
+
+  @retval EFI_SUCCESS    The DMAR ACPI table is got.
+  @retval EFI_NOT_FOUND  The DMAR ACPI table is not found.
+**/
+EFI_STATUS
+GetDmarAcpiTable (
+  VOID
+  );
+
+/**
+  Parse DMAR DRHD table.
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  VOID
+  );
+
+/**
+  Parse DMAR RMRR table.
+
+  @return EFI_SUCCESS  The DMAR RMRR table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableRmrr (
+  VOID
+  );
+
+/**
+  Dump DMAR context entry table.
+
+  @param[in]  RootEntry DMAR root entry.
+**/
+VOID
+DumpDmarContextEntryTable (
+  IN VTD_ROOT_ENTRY *RootEntry
+  );
+
+/**
+  Dump DMAR extended context entry table.
+
+  @param[in]  ExtRootEntry DMAR extended root entry.
+**/
+VOID
+DumpDmarExtContextEntryTable (
+  IN VTD_EXT_ROOT_ENTRY *ExtRootEntry
+  );
+
+/**
+  Dump DMAR second level paging entry.
+
+  @param[in]  SecondLevelPagingEntry The second level paging entry.
+**/
+VOID
+DumpSecondLevelPagingEntry (
+  IN VOID *SecondLevelPagingEntry
+  );
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  VtdIndex                The index used to identify a VTd engine.
+  @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
+  @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
+  @param[in]  Length                  The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess             The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetPageAttribute (
+  IN UINTN                         VtdIndex,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        BaseAddress,
+  IN UINT64                        Length,
+  IN UINT64                        IoMmuAccess
+  );
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetAccessAttribute (
+  IN UINT16                Segment,
+  IN VTD_SOURCE_ID         SourceId,
+  IN UINT64                BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  );
+
+/**
+  Return the index of PCI descriptor.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @return The index of the PCI descriptor.
+  @retval (UINTN)-1  The PCI descriptor is not found.
+**/
+UINTN
+GetPciDescriptor (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId
+  );
+
+/**
+  Dump VTd registers if there is error.
+**/
+VOID
+DumpVtdIfError (
+  VOID
+  );
+
+/**
+  Initialize platform VTd policy.
+**/
+VOID
+InitializePlatformVTdPolicy (
+  VOID
+  );
+
+/**
+  Always enable the VTd page attribute for the device.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
+**/
+EFI_STATUS
+AlwaysEnablePageAttribute (
+  IN UINT16                  Segment,
+  IN VTD_SOURCE_ID           SourceId
+  );
+
+/**
+  Convert the DeviceHandle to SourceId and Segment.
+
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[out] Segment           The Segment used to identify a VTd engine.
+  @param[out] SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS            The Segment and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+**/
+EFI_STATUS
+DeviceHandleToSourceId (
+  IN EFI_HANDLE            DeviceHandle,
+  OUT UINT16               *Segment,
+  OUT VTD_SOURCE_ID        *SourceId
+  );
+
+/**
+  Get device information from mapping.
+
+  @param[in]  Mapping        The mapping.
+  @param[out] DeviceAddress  The device address of the mapping.
+  @param[out] NumberOfPages  The number of pages of the mapping.
+
+  @retval EFI_SUCCESS            The device information is returned.
+  @retval EFI_INVALID_PARAMETER  The mapping is invalid.
+**/
+EFI_STATUS
+GetDeviceInfoFromMapping (
+  IN  VOID                                     *Mapping,
+  OUT EFI_PHYSICAL_ADDRESS                     *DeviceAddress,
+  OUT UINTN                                    *NumberOfPages
+  );
+
+/**
+  Initialize DMA protection.
+**/
+VOID
+InitializeDmaProtection (
+  VOID
+  );
+
+/**
+  Allocate zero pages.
+
+  @param[in]  Pages the number of pages.
+
+  @return the page address.
+  @retval NULL No resource to allocate pages.
+**/
+VOID *
+EFIAPI
+AllocateZeroPages (
+  IN UINTN  Pages
+  );
+
+#endif
diff --git a/IntelSiliconPkg/IntelVTdDxe/DmarAcpiTable.c b/IntelSiliconPkg/IntelVTdDxe/DmarAcpiTable.c
new file mode 100644
index 0000000..84b5485
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/DmarAcpiTable.c
@@ -0,0 +1,998 @@
+/** @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 "DmaProtection.h"
+
+#pragma pack(1)
+
+typedef struct {
+  EFI_ACPI_DESCRIPTION_HEADER  Header;
+  UINT32                       Entry;
+} RSDT_TABLE;
+
+typedef struct {
+  EFI_ACPI_DESCRIPTION_HEADER  Header;
+  UINT64                       Entry;
+} XSDT_TABLE;
+
+#pragma pack()
+
+EFI_ACPI_DMAR_HEADER  *mAcpiDmarTable;
+
+/**
+  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"
+    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
+    "    *************************************************************************\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;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
+    DEBUG ((DEBUG_INFO,
+      "        IOAPIC\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
+    DEBUG ((DEBUG_INFO,
+      "        MSI Capable HPET\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
+    DEBUG ((DEBUG_INFO,
+      "        ACPI Namespace Device\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 ANDD table.
+
+  @param[in]  Andd  DMAR ANDD table
+**/
+VOID
+DumpDmarAndd (
+  IN EFI_ACPI_DMAR_ANDD_HEADER *Andd
+  )
+{
+  if (Andd == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    "  *       ACPI Name-space Device Declaration Structure                      *\n"
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  ANDD address ........................................... 0x%016lx\n" :
+    "  ANDD address ........................................... 0x%08x\n",
+    Andd
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Andd->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Andd->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    ACPI Device Number ................................... 0x%02x\n",
+    Andd->AcpiDeviceNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    ACPI Object Name ..................................... '%a'\n",
+    (Andd + 1)
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR RHSA table.
+
+  @param[in]  Rhsa  DMAR RHSA table
+**/
+VOID
+DumpDmarRhsa (
+  IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa
+  )
+{
+  if (Rhsa == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    "  *       Remapping Hardware Status Affinity Structure                      *\n"
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  RHSA address ........................................... 0x%016lx\n" :
+    "  RHSA address ........................................... 0x%08x\n",
+    Rhsa
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Rhsa->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Rhsa->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Register Base Address ................................ 0x%016lx\n",
+    Rhsa->RegisterBaseAddress
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Proximity Domain ..................................... 0x%08x\n",
+    Rhsa->ProximityDomain
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ATSR table.
+
+  @param[in]  Atsr  DMAR ATSR table
+**/
+VOID
+DumpDmarAtsr (
+  IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    AtsrLen;
+
+  if (Atsr == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    "  *       Root Port ATS Capability Reporting Structure                      *\n"
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  ATSR address ........................................... 0x%016lx\n" :
+    "  ATSR address ........................................... 0x%08x\n",
+    Atsr
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Atsr->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Atsr->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Atsr->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      ALL_PORTS .......................................... 0x%02x\n",
+    Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Atsr->SegmentNumber
+    ));
+
+  AtsrLen  = Atsr->Header.Length - sizeof(EFI_ACPI_DMAR_ATSR_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Atsr + 1);
+  while (AtsrLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    AtsrLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  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"
+    "  *       Reserved Memory Region Reporting Structure                        *\n"
+    "  ***************************************************************************\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"
+    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
+    "  ***************************************************************************\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"
+    "*         DMAR Table                                                        *\n"
+    "*****************************************************************************\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;
+    case EFI_ACPI_DMAR_TYPE_ATSR:
+      DumpDmarAtsr ((EFI_ACPI_DMAR_ATSR_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_RHSA:
+      DumpDmarRhsa ((EFI_ACPI_DMAR_RHSA_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_ANDD:
+      DumpDmarAndd ((EFI_ACPI_DMAR_ANDD_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarLen -= DmarHeader->Length;
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ACPI table.
+**/
+VOID
+VtdDumpDmarTable (
+  VOID
+  )
+{
+  DumpAcpiDMAR ((EFI_ACPI_DMAR_HEADER *)(UINTN)mAcpiDmarTable);
+}
+
+/**
+  Get PCI device information from DMAR DevScopeEntry.
+
+  @param[in]  Segment               The segment number.
+  @param[in]  DmarDevScopeEntry     DMAR DevScopeEntry
+  @param[out] Bus                   The bus number.
+  @param[out] Device                The device number.
+  @param[out] Function              The function number.
+
+  @retval EFI_SUCCESS  The PCI device information is returned.
+**/
+EFI_STATUS
+GetPciBusDeviceFunction (
+  IN  UINT16                                      Segment,
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,
+  OUT UINT8                                       *Bus,
+  OUT UINT8                                       *Device,
+  OUT UINT8                                       *Function
+  )
+{
+  EFI_ACPI_DMAR_PCI_PATH                     *DmarPciPath;
+  UINT8                                      MyBus;
+  UINT8                                      MyDevice;
+  UINT8                                      MyFunction;
+
+  DmarPciPath = (EFI_ACPI_DMAR_PCI_PATH *)((UINTN)(DmarDevScopeEntry + 1));
+  MyBus = DmarDevScopeEntry->StartBusNumber;
+  MyDevice = DmarPciPath->Device;
+  MyFunction = DmarPciPath->Function;
+
+  switch (DmarDevScopeEntry->Type) {
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+    while ((UINTN)DmarPciPath < (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length) {
+      MyBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, MyBus, MyDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+      MyDevice = DmarPciPath->Device;
+      MyFunction = DmarPciPath->Function;
+      DmarPciPath ++;
+    }
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
+    break;
+  }
+
+  *Bus = MyBus;
+  *Device = MyDevice;
+  *Function = MyFunction;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Process DMAR DHRD table.
+
+  @param[in]  VtdIndex  The index of VTd engine.
+  @param[in]  DmarDrhd  The DRHD table.
+
+  @retval EFI_SUCCESS The DRHD table is processed.
+**/
+EFI_STATUS
+ProcessDhrd (
+  IN UINTN                      VtdIndex,
+  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINT8                                             Bus;
+  UINT8                                             Device;
+  UINT8                                             Function;
+  UINT8                                             SecondaryBusNumber;
+  EFI_STATUS                                        Status;
+  VTD_SOURCE_ID                                     SourceId;
+  BOOLEAN                                           IsRealPciDevice;
+
+  mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress = (UINTN)DmarDrhd->RegisterBaseAddress;
+  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
+
+  mVtdUnitInformation[VtdIndex].Segment = DmarDrhd->SegmentNumber;
+
+  if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) {
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = TRUE;
+    DEBUG ((DEBUG_INFO,"  ProcessDhrd: with INCLUDE ALL\n"));
+
+    Status = ScanPciBus(VtdIndex, DmarDrhd->SegmentNumber, 0);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } else {
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = FALSE;
+    DEBUG ((DEBUG_INFO,"  ProcessDhrd: without INCLUDE ALL\n"));
+  }
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
+
+    Status = GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    switch (DmarDevScopeEntry->Type) {
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+      IsRealPciDevice = TRUE;
+      break;
+    default:
+      IsRealPciDevice = FALSE;
+      break;
+    }
+
+    DEBUG ((DEBUG_INFO,"  ProcessDhrd: "));
+    switch (DmarDevScopeEntry->Type) {
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+      DEBUG ((DEBUG_INFO,"PCI Endpoint"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+      DEBUG ((DEBUG_INFO,"PCI-PCI bridge"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
+      DEBUG ((DEBUG_INFO,"IOAPIC"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
+      DEBUG ((DEBUG_INFO,"MSI Capable HPET"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
+      DEBUG ((DEBUG_INFO,"ACPI Namespace Device"));
+      break;
+    }
+    DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumber, Bus, Device, Function));
+
+    SourceId.Bits.Bus = Bus;
+    SourceId.Bits.Device = Device;
+    SourceId.Bits.Function = Function;
+
+    Status = RegisterPciDevice (VtdIndex, DmarDrhd->SegmentNumber, SourceId, IsRealPciDevice, TRUE);
+    if (EFI_ERROR (Status)) {
+      //
+      // There might be duplication for special device other than standard PCI device.
+      //
+      switch (DmarDevScopeEntry->Type) {
+      case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+      case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+        return Status;
+      }
+    }
+
+    switch (DmarDevScopeEntry->Type) {
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+      SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DmarDrhd->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+      Status = ScanPciBus (VtdIndex, DmarDrhd->SegmentNumber, SecondaryBusNumber);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    default:
+      break;
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Process DMAR RMRR table.
+
+  @param[in]  DmarRmrr  The RMRR table.
+
+  @retval EFI_SUCCESS The RMRR table is processed.
+**/
+EFI_STATUS
+ProcessRmrr (
+  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINT8                                             Bus;
+  UINT8                                             Device;
+  UINT8                                             Function;
+  EFI_STATUS                                        Status;
+  VTD_SOURCE_ID                                     SourceId;
+
+  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
+    if (DmarDevScopeEntry->Type != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
+      DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%x] \n", DmarDevScopeEntry->Type));
+      return EFI_DEVICE_ERROR;
+    }
+
+    Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->SegmentNumber, Bus, Device, Function));
+
+    SourceId.Bits.Bus = Bus;
+    SourceId.Bits.Device = Device;
+    SourceId.Bits.Function = Function;
+    Status = SetAccessAttribute (
+               DmarRmrr->SegmentNumber,
+               SourceId,
+               DmarRmrr->ReservedMemoryRegionBaseAddress,
+               DmarRmrr->ReservedMemoryRegionLimitAddress + 1 - DmarRmrr->ReservedMemoryRegionBaseAddress,
+               EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get 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);
+  }
+  return VtdIndex ;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  VOID
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  EFI_STATUS                                        Status;
+  UINTN                                             VtdIndex;
+
+  mVtdUnitNumber = GetVtdEngineNumber ();
+  DEBUG ((DEBUG_INFO,"  VtdUnitNumber - %d\n", mVtdUnitNumber));
+  ASSERT (mVtdUnitNumber > 0);
+  if (mVtdUnitNumber == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  mVtdUnitInformation = AllocateZeroPool (sizeof(*mVtdUnitInformation) * mVtdUnitNumber);
+  ASSERT (mVtdUnitInformation != NULL);
+  if (mVtdUnitInformation == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mVtdHostAddressWidthMask = LShiftU64 (1ull, mAcpiDmarTable->HostAddressWidth) - 1;
+
+  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 < mVtdUnitNumber);
+      Status = ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      VtdIndex++;
+
+      break;
+
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  ASSERT (VtdIndex == mVtdUnitNumber);
+
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+    DumpPciDeviceInfo (VtdIndex);
+  }
+  return EFI_SUCCESS ;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableRmrr (
+  VOID
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  EFI_STATUS                                        Status;
+
+  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:
+      Status = ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return EFI_SUCCESS ;
+}
+
+/**
+  This function scan ACPI table in RSDT.
+
+  @param[in]  Rsdt      ACPI RSDT
+  @param[in]  Signature ACPI table signature
+
+  @return ACPI table
+**/
+VOID *
+ScanTableInRSDT (
+  IN RSDT_TABLE                   *Rsdt,
+  IN UINT32                       Signature
+  )
+{
+  UINTN                         Index;
+  UINT32                        EntryCount;
+  UINT32                        *EntryPtr;
+  EFI_ACPI_DESCRIPTION_HEADER   *Table;
+
+  EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
+
+  EntryPtr = &Rsdt->Entry;
+  for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
+    Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));
+    if (Table->Signature == Signature) {
+      return Table;
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  This function scan ACPI table in XSDT.
+
+  @param[in]  Xsdt      ACPI XSDT
+  @param[in]  Signature ACPI table signature
+
+  @return ACPI table
+**/
+VOID *
+ScanTableInXSDT (
+  IN XSDT_TABLE                   *Xsdt,
+  IN UINT32                       Signature
+  )
+{
+  UINTN                        Index;
+  UINT32                       EntryCount;
+  UINT64                       EntryPtr;
+  UINTN                        BasePtr;
+  EFI_ACPI_DESCRIPTION_HEADER  *Table;
+
+  EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
+
+  BasePtr = (UINTN)(&(Xsdt->Entry));
+  for (Index = 0; Index < EntryCount; Index ++) {
+    CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
+    Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));
+    if (Table->Signature == Signature) {
+      return Table;
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  This function scan ACPI table in RSDP.
+
+  @param[in]  Rsdp      ACPI RSDP
+  @param[in]  Signature ACPI table signature
+
+  @return ACPI table
+**/
+VOID *
+FindAcpiPtr (
+  IN EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp,
+  IN UINT32                                       Signature
+  )
+{
+  EFI_ACPI_DESCRIPTION_HEADER                    *AcpiTable;
+  RSDT_TABLE                                     *Rsdt;
+  XSDT_TABLE                                     *Xsdt;
+
+  AcpiTable = NULL;
+
+  //
+  // Check ACPI2.0 table
+  //
+  Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;
+  Xsdt = NULL;
+  if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {
+    Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;
+  }
+  //
+  // Check Xsdt
+  //
+  if (Xsdt != NULL) {
+    AcpiTable = ScanTableInXSDT (Xsdt, Signature);
+  }
+  //
+  // Check Rsdt
+  //
+  if ((AcpiTable == NULL) && (Rsdt != NULL)) {
+    AcpiTable = ScanTableInRSDT (Rsdt, Signature);
+  }
+
+  return AcpiTable;
+}
+
+/**
+  Get the DMAR ACPI table.
+
+  @retval EFI_SUCCESS    The DMAR ACPI table is got.
+  @retval EFI_NOT_FOUND  The DMAR ACPI table is not found.
+**/
+EFI_STATUS
+GetDmarAcpiTable (
+  VOID
+  )
+{
+  VOID                              *AcpiTable;
+  EFI_STATUS                        Status;
+
+  AcpiTable = NULL;
+  Status = EfiGetSystemConfigurationTable (
+             &gEfiAcpi20TableGuid,
+             &AcpiTable
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EfiGetSystemConfigurationTable (
+               &gEfiAcpiTableGuid,
+               &AcpiTable
+               );
+  }
+  ASSERT (AcpiTable != NULL);
+
+  mAcpiDmarTable = FindAcpiPtr (
+                      (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable,
+                      EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE
+                      );
+  DEBUG ((DEBUG_INFO,"DMAR Table - 0x%08x\n", mAcpiDmarTable));
+  if (mAcpiDmarTable == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+  VtdDumpDmarTable();
+
+  return EFI_SUCCESS;
+}
diff --git a/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.c b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.c
new file mode 100644
index 0000000..d22222d
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.c
@@ -0,0 +1,353 @@
+/** @file
+  Intel VTd driver.
+
+  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 <PiDxe.h>
+
+#include <Protocol/IoMmu.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "DmaProtection.h"
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  This                  The protocol instance pointer.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuMap (
+  IN     EDKII_IOMMU_PROTOCOL                       *This,
+  IN     EDKII_IOMMU_OPERATION                      Operation,
+  IN     VOID                                       *HostAddress,
+  IN OUT UINTN                                      *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
+  OUT    VOID                                       **Mapping
+  );
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  The protocol instance pointer.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IoMmuUnmap (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  VOID                                     *Mapping
+  );
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  This                  The protocol instance pointer.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuAllocateBuffer (
+  IN     EDKII_IOMMU_PROTOCOL                     *This,
+  IN     EFI_ALLOCATE_TYPE                        Type,
+  IN     EFI_MEMORY_TYPE                          MemoryType,
+  IN     UINTN                                    Pages,
+  IN OUT VOID                                     **HostAddress,
+  IN     UINT64                                   Attributes
+  );
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  The protocol instance pointer.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuFreeBuffer (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  UINTN                                    Pages,
+  IN  VOID                                     *HostAddress
+  );
+
+/**
+  Convert the DeviceHandle to SourceId and Segment.
+
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[out] Segment           The Segment used to identify a VTd engine.
+  @param[out] SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS            The Segment and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+**/
+EFI_STATUS
+DeviceHandleToSourceId (
+  IN EFI_HANDLE            DeviceHandle,
+  OUT UINT16               *Segment,
+  OUT VTD_SOURCE_ID        *SourceId
+  )
+{
+  EFI_PCI_IO_PROTOCOL                      *PciIo;
+  UINTN                                    Seg;
+  UINTN                                    Bus;
+  UINTN                                    Dev;
+  UINTN                                    Func;
+  EFI_STATUS                               Status;
+  EDKII_PLATFORM_VTD_DEVICE_INFO           DeviceInfo;
+
+  Status = EFI_NOT_FOUND;
+  if (mPlatformVTdPolicy != NULL) {
+    Status = mPlatformVTdPolicy->GetDeviceId (mPlatformVTdPolicy, DeviceHandle, &DeviceInfo);
+    if (!EFI_ERROR(Status)) {
+      *Segment  = DeviceInfo.Segment;
+      *SourceId = DeviceInfo.SourceId;
+      return EFI_SUCCESS;
+    }
+  }
+
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
+  if (EFI_ERROR(Status)) {
+    return EFI_UNSUPPORTED;
+  }
+  Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
+  if (EFI_ERROR(Status)) {
+    return EFI_UNSUPPORTED;
+  }
+  *Segment = (UINT16)Seg;
+  SourceId->Bits.Bus = (UINT8)Bus;
+  SourceId->Bits.Device = (UINT8)Dev;
+  SourceId->Bits.Function = (UINT8)Func;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set IOMMU attribute for a system memory.
+
+  If the IOMMU protocol exists, the system memory cannot be used
+  for DMA by default.
+
+  When a device requests a DMA access for a system memory,
+  the device driver need use SetAttribute() to update the IOMMU
+  attribute to request DMA access (read and/or write).
+
+  The DeviceHandle is used to identify which device submits the request.
+  The IOMMU implementation need translate the device path to an IOMMU device ID,
+  and set IOMMU hardware register accordingly.
+  1) DeviceHandle can be a standard PCI device.
+     The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+     The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+     The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+     After the memory is used, the memory need set 0 to keep it being protected.
+  2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+     The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDKII_IOMMU_ACCESS_WRITE.
+
+  @param[in]  This              The protocol instance pointer.
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[in]  DeviceAddress     The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_INVALID_PARAMETER  DeviceAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by DeviceAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+
+**/
+EFI_STATUS
+VTdSetAttribute (
+  IN EDKII_IOMMU_PROTOCOL  *This,
+  IN EFI_HANDLE            DeviceHandle,
+  IN EFI_PHYSICAL_ADDRESS  DeviceAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  )
+{
+  EFI_STATUS           Status;
+  UINT16               Segment;
+  VTD_SOURCE_ID        SourceId;
+
+  DumpVtdIfError ();
+
+  Status = DeviceHandleToSourceId (DeviceHandle, &Segment, &SourceId);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuSetAttribute: "));
+  DEBUG ((DEBUG_VERBOSE, "PCI(S%x.B%x.D%x.F%x) ", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+  DEBUG ((DEBUG_VERBOSE, "(0x%lx~0x%lx) - %lx\n", DeviceAddress, Length, IoMmuAccess));
+
+  Status = SetAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);
+
+  return Status;
+}
+
+/**
+  Set IOMMU attribute for a system memory.
+
+  If the IOMMU protocol exists, the system memory cannot be used
+  for DMA by default.
+
+  When a device requests a DMA access for a system memory,
+  the device driver need use SetAttribute() to update the IOMMU
+  attribute to request DMA access (read and/or write).
+
+  The DeviceHandle is used to identify which device submits the request.
+  The IOMMU implementation need translate the device path to an IOMMU device ID,
+  and set IOMMU hardware register accordingly.
+  1) DeviceHandle can be a standard PCI device.
+     The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+     The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+     The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+     After the memory is used, the memory need set 0 to keep it being protected.
+  2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+     The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDKII_IOMMU_ACCESS_WRITE.
+
+  @param[in]  This              The protocol instance pointer.
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[in]  Mapping           The mapping value returned from Map().
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_INVALID_PARAMETER  Mapping is not a value that was returned by Map().
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by Mapping.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuSetAttribute (
+  IN EDKII_IOMMU_PROTOCOL  *This,
+  IN EFI_HANDLE            DeviceHandle,
+  IN VOID                  *Mapping,
+  IN UINT64                IoMmuAccess
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;
+  UINTN                 NumberOfPages;
+
+  Status = GetDeviceInfoFromMapping (Mapping, &DeviceAddress, &NumberOfPages);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+  Status = VTdSetAttribute (
+             This,
+             DeviceHandle,
+             DeviceAddress,
+             EFI_PAGES_TO_SIZE(NumberOfPages),
+             IoMmuAccess
+             );
+
+  return Status;
+}
+
+EDKII_IOMMU_PROTOCOL  mIntelVTd = {
+  EDKII_IOMMU_PROTOCOL_REVISION,
+  IoMmuSetAttribute,
+  IoMmuMap,
+  IoMmuUnmap,
+  IoMmuAllocateBuffer,
+  IoMmuFreeBuffer,
+};
+
+/**
+  Initialize the VTd driver.
+
+  @param[in]  ImageHandle  ImageHandle of the loaded driver
+  @param[in]  SystemTable  Pointer to the System Table
+
+  @retval  EFI_SUCCESS           The Protocol is installed.
+  @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize driver.
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IntelVTdInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  InitializeDmaProtection ();
+
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEdkiiIoMmuProtocolGuid, &mIntelVTd,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf
new file mode 100644
index 0000000..6a61c13
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf
@@ -0,0 +1,79 @@
+## @file
+# Intel VTd DXE Driver.
+#
+# This driver initializes VTd engine based upon DMAR ACPI tables
+# and provide DMA protection to PCI or ACPI device.
+#
+# 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.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IntelVTdDxe
+  MODULE_UNI_FILE                = IntelVTdDxe.uni
+  FILE_GUID                      = 987555D6-595D-4CFA-B895-59B89368BD4D
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = IntelVTdInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#
+
+[Sources]
+  IntelVTdDxe.c
+  BmDma.c
+  DmaProtection.c
+  DmaProtection.h
+  DmarAcpiTable.c
+  PciInfo.c
+  TranslationTable.c
+  TranslationTableEx.c
+  VtdReg.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  IoLib
+  PciSegmentLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiLib
+
+[Guids]
+  gEfiEventExitBootServicesGuid   ## CONSUMES ## Event
+  gEfiAcpi20TableGuid             ## CONSUMES ## SystemTable
+  gEfiAcpiTableGuid               ## CONSUMES ## SystemTable
+
+[Protocols]
+  gEdkiiIoMmuProtocolGuid                     ## PRODUCES
+  gEfiAcpiSdtProtocolGuid                     ## CONSUMES
+  gEfiPciIoProtocolGuid                       ## CONSUMES
+  gEfiPciEnumerationCompleteProtocolGuid      ## CONSUMES
+  gEdkiiPlatformVTdPolicyProtocolGuid         ## SOMETIMES_CONSUMES
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid AND
+  gEfiAcpiSdtProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  IntelVTdDxeExtra.uni
+
diff --git a/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.uni b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.uni
new file mode 100644
index 0000000..45ce3c3
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.uni
@@ -0,0 +1,20 @@
+// /** @file
+// IntelVTdDxe Module Localized Abstract and Description Content
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Intel VTd DXE Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver initializes VTd engine based upon DMAR ACPI tables and provide DMA protection to PCI or ACPI device."
+
diff --git a/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxeExtra.uni b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxeExtra.uni
new file mode 100644
index 0000000..5cb3eb0
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/IntelVTdDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// IntelVTdDxe Localized Strings and Content
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Intel VTd DXE Driver"
+
+
diff --git a/IntelSiliconPkg/IntelVTdDxe/PciInfo.c b/IntelSiliconPkg/IntelVTdDxe/PciInfo.c
new file mode 100644
index 0000000..ea84317
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/PciInfo.c
@@ -0,0 +1,315 @@
+/** @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 "DmaProtection.h"
+
+/**
+  Return the index of PCI descriptor.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @return The index of the PCI descriptor.
+  @retval (UINTN)-1  The PCI descriptor is not found.
+**/
+UINTN
+GetPciDescriptor (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId
+  )
+{
+  UINTN  Index;
+
+  if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
+    return (UINTN)-1;
+  }
+
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {
+    if ((mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus == SourceId.Bits.Bus) &&
+        (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device == SourceId.Bits.Device) &&
+        (mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function == SourceId.Bits.Function) ) {
+      return Index;
+    }
+  }
+
+  return (UINTN)-1;
+}
+
+/**
+  Register PCI device to VTd engine as PCI descriptor.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[in]  IsRealPciDevice       TRUE: It is a real PCI device.
+                                    FALSE: It is not a real PCI device.
+  @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.
+                                    FALSE: SUCCESS will be returned if the PCI device is registered.
+
+  @retval EFI_SUCCESS           The PCI device is registered.
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
+  @retval EFI_ALREADY_STARTED   The device is already registered.
+**/
+EFI_STATUS
+RegisterPciDevice (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId,
+  IN BOOLEAN        IsRealPciDevice,
+  IN BOOLEAN        CheckExist
+  )
+{
+  PCI_DEVICE_INFORMATION  *PciDeviceInfo;
+  VTD_SOURCE_ID           *PciDescriptor;
+  UINTN                   PciDescriptorIndex;
+  UINTN                   Index;
+  BOOLEAN                 *NewIsRealPciDevice;
+  VTD_SOURCE_ID           *NewPciDescriptors;
+
+  PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;
+
+  if (PciDeviceInfo->IncludeAllFlag) {
+    //
+    // Do not register device in other VTD Unit
+    //
+    for (Index = 0; Index < VtdIndex; Index++) {
+      PciDescriptorIndex = GetPciDescriptor (Index, Segment, SourceId);
+      if (PciDescriptorIndex != (UINTN)-1) {
+        DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered by Other Vtd(%d)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, Index));
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);
+  if (PciDescriptorIndex == (UINTN)-1) {
+    //
+    // Register new
+    //
+
+    if (PciDeviceInfo->PciDescriptorNumber >= PciDeviceInfo->PciDescriptorMaxNumber) {
+      //
+      // Reallocate
+      //
+      NewIsRealPciDevice = AllocateZeroPool (sizeof(*NewIsRealPciDevice) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));
+      if (NewIsRealPciDevice == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      NewPciDescriptors = AllocateZeroPool (sizeof(*NewPciDescriptors) * (PciDeviceInfo->PciDescriptorMaxNumber + MAX_PCI_DESCRIPTORS));
+      if (NewPciDescriptors == NULL) {
+        FreePool (NewIsRealPciDevice);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      PciDeviceInfo->PciDescriptorMaxNumber += MAX_PCI_DESCRIPTORS;
+      if (PciDeviceInfo->IsRealPciDevice != NULL) {
+        CopyMem (NewIsRealPciDevice, PciDeviceInfo->IsRealPciDevice, sizeof(*NewIsRealPciDevice) * PciDeviceInfo->PciDescriptorNumber);
+        FreePool (PciDeviceInfo->IsRealPciDevice);
+      }
+      PciDeviceInfo->IsRealPciDevice = NewIsRealPciDevice;
+      if (PciDeviceInfo->PciDescriptors != NULL) {
+        CopyMem (NewPciDescriptors, PciDeviceInfo->PciDescriptors, sizeof(*NewPciDescriptors) * PciDeviceInfo->PciDescriptorNumber);
+        FreePool (PciDeviceInfo->PciDescriptors);
+      }
+      PciDeviceInfo->PciDescriptors = NewPciDescriptors;
+    }
+
+    ASSERT (PciDeviceInfo->PciDescriptorNumber < PciDeviceInfo->PciDescriptorMaxNumber);
+
+    PciDescriptor = &PciDeviceInfo->PciDescriptors[PciDeviceInfo->PciDescriptorNumber];
+    PciDescriptor->Bits.Bus = SourceId.Bits.Bus;
+    PciDescriptor->Bits.Device = SourceId.Bits.Device;
+    PciDescriptor->Bits.Function = SourceId.Bits.Function;
+    PciDeviceInfo->IsRealPciDevice[PciDeviceInfo->PciDescriptorNumber] = IsRealPciDevice;
+
+    PciDeviceInfo->PciDescriptorNumber++;
+
+    DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    if (!IsRealPciDevice) {
+      DEBUG ((DEBUG_INFO, " (*)"));
+    }
+    DEBUG ((DEBUG_INFO, "\n"));
+  } else {
+    if (CheckExist) {
+      DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      return EFI_ALREADY_STARTED;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Scan PCI bus and register PCI devices under the bus.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+
+  @retval EFI_SUCCESS           The PCI devices under the bus are registered.
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
+**/
+EFI_STATUS
+ScanPciBus (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN UINT8          Bus
+  )
+{
+  UINT8                   Device;
+  UINT8                   Function;
+  UINT8                   SecondaryBusNumber;
+  UINT8                   HeaderType;
+  UINT8                   BaseClass;
+  UINT8                   SubClass;
+  UINT32                  MaxFunction;
+  UINT16                  VendorID;
+  UINT16                  DeviceID;
+  EFI_STATUS              Status;
+  VTD_SOURCE_ID           SourceId;
+
+  // Scan the PCI bus for devices
+  for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {
+    HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
+    MaxFunction = PCI_MAX_FUNC + 1;
+    if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
+      MaxFunction = 1;
+    }
+    for (Function = 0; Function < MaxFunction; Function++) {
+      VendorID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
+      DeviceID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
+      if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
+        continue;
+      }
+
+      SourceId.Bits.Bus = Bus;
+      SourceId.Bits.Device = Device;
+      SourceId.Bits.Function = Function;
+      Status = RegisterPciDevice (VtdIndex, Segment, SourceId, TRUE, FALSE);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
+      if (BaseClass == PCI_CLASS_BRIDGE) {
+        SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
+        if (SubClass == PCI_CLASS_BRIDGE_P2P) {
+          SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+          DEBUG ((DEBUG_INFO,"  ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));
+          if (SecondaryBusNumber != 0) {
+            Status = ScanPciBus (VtdIndex, Segment, SecondaryBusNumber);
+            if (EFI_ERROR (Status)) {
+              return Status;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump the PCI device information managed by this VTd engine.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpPciDeviceInfo (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN  Index;
+
+  DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber,
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag
+    ));
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {
+    DEBUG ((DEBUG_INFO,"  S%04x B%02x D%02x F%02x\n",
+      mVtdUnitInformation[VtdIndex].Segment,
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Bus,
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Device,
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index].Bits.Function
+      ));
+  }
+}
+
+/**
+  Find the VTd index by the Segment and SourceId.
+
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[out] ExtContextEntry       The ExtContextEntry of the source.
+  @param[out] ContextEntry          The ContextEntry of the source.
+
+  @return The index of the PCI descriptor.
+  @retval (UINTN)-1  The PCI descriptor is not found.
+**/
+UINTN
+FindVtdIndexByPciDevice (
+  IN  UINT16                  Segment,
+  IN  VTD_SOURCE_ID           SourceId,
+  OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,
+  OUT VTD_CONTEXT_ENTRY       **ContextEntry
+  )
+{
+  UINTN                   VtdIndex;
+  VTD_ROOT_ENTRY          *RootEntry;
+  VTD_CONTEXT_ENTRY       *ContextEntryTable;
+  VTD_CONTEXT_ENTRY       *ThisContextEntry;
+  VTD_EXT_ROOT_ENTRY      *ExtRootEntry;
+  VTD_EXT_CONTEXT_ENTRY   *ExtContextEntryTable;
+  VTD_EXT_CONTEXT_ENTRY   *ThisExtContextEntry;
+  UINTN                   PciDescriptorIndex;
+
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+    if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
+      continue;
+    }
+
+    PciDescriptorIndex = GetPciDescriptor (VtdIndex, Segment, SourceId);
+    if (PciDescriptorIndex == (UINTN)-1) {
+      continue;
+    }
+
+//    DEBUG ((DEBUG_INFO,"FindVtdIndex(0x%x) for S%04x B%02x D%02x F%02x\n", VtdIndex, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {
+      ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
+      ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)LShiftU64 (ExtRootEntry->Bits.LowerContextTablePointer, 12) ;
+      ThisExtContextEntry  = &ExtContextEntryTable[SourceId.Index.ContextIndex];
+      if (ThisExtContextEntry->Bits.AddressWidth == 0) {
+        continue;
+      }
+      *ExtContextEntry = ThisExtContextEntry;
+      *ContextEntry    = NULL;
+    } else {
+      RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
+      ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)LShiftU64 (RootEntry->Bits.ContextTablePointer, 12) ;
+      ThisContextEntry  = &ContextEntryTable[SourceId.Index.ContextIndex];
+      if (ThisContextEntry->Bits.AddressWidth == 0) {
+        continue;
+      }
+      *ExtContextEntry = NULL;
+      *ContextEntry    = ThisContextEntry;
+    }
+
+    return VtdIndex;
+  }
+
+  return (UINTN)-1;
+}
+
diff --git a/IntelSiliconPkg/IntelVTdDxe/TranslationTable.c b/IntelSiliconPkg/IntelVTdDxe/TranslationTable.c
new file mode 100644
index 0000000..0cff2cc
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/TranslationTable.c
@@ -0,0 +1,969 @@
+/** @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 "DmaProtection.h"
+
+/**
+  Create extended context entry.
+
+  @param[in]  VtdIndex  The index of the VTd engine.
+
+  @retval EFI_SUCCESS          The extended context entry is created.
+  @retval EFI_OUT_OF_RESOURCE  No enough resource to create extended context entry.
+**/
+EFI_STATUS
+CreateExtContextEntry (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Allocate zero pages.
+
+  @param[in]  Pages the number of pages.
+
+  @return the page address.
+  @retval NULL No resource to allocate pages.
+**/
+VOID *
+EFIAPI
+AllocateZeroPages (
+  IN UINTN  Pages
+  )
+{
+  VOID *Addr;
+
+  Addr = AllocatePages (Pages);
+  if (Addr == NULL) {
+    return NULL;
+  }
+  ZeroMem (Addr, EFI_PAGES_TO_SIZE(Pages));
+  return Addr;
+}
+
+/**
+  Set second level paging entry attribute based upon IoMmuAccess.
+
+  @param[in]  PtEntry      The paging entry.
+  @param[in]  IoMmuAccess  The IOMMU access.
+**/
+VOID
+SetSecondLevelPagingEntryAttribute (
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY  *PtEntry,
+  IN UINT64                         IoMmuAccess
+  )
+{
+  PtEntry->Bits.Read  = ((IoMmuAccess & EDKII_IOMMU_ACCESS_READ) != 0);
+  PtEntry->Bits.Write = ((IoMmuAccess & EDKII_IOMMU_ACCESS_WRITE) != 0);
+}
+
+/**
+  Create context entry.
+
+  @param[in]  VtdIndex  The index of the VTd engine.
+
+  @retval EFI_SUCCESS          The context entry is created.
+  @retval EFI_OUT_OF_RESOURCE  No enough resource to create context entry.
+**/
+EFI_STATUS
+CreateContextEntry (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN                  Index;
+  VOID                   *Buffer;
+  UINTN                  RootPages;
+  UINTN                  ContextPages;
+  VTD_ROOT_ENTRY         *RootEntry;
+  VTD_CONTEXT_ENTRY      *ContextEntryTable;
+  VTD_CONTEXT_ENTRY      *ContextEntry;
+  VTD_SOURCE_ID          *PciDescriptor;
+  VTD_SOURCE_ID          SourceId;
+  UINTN                  MaxBusNumber;
+  UINTN                  EntryTablePages;
+
+  MaxBusNumber = 0;
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {
+    PciDescriptor = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index];
+    if (PciDescriptor->Bits.Bus > MaxBusNumber) {
+      MaxBusNumber = PciDescriptor->Bits.Bus;
+    }
+  }
+  DEBUG ((DEBUG_INFO,"  MaxBusNumber - 0x%x\n", MaxBusNumber));
+
+  RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);
+  ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);
+  EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);
+  Buffer = AllocateZeroPages (EntryTablePages);
+  if (Buffer == NULL) {
+    DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  mVtdUnitInformation[VtdIndex].RootEntryTable = (VTD_ROOT_ENTRY *)Buffer;
+  Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);
+
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {
+    PciDescriptor = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index];
+
+    SourceId.Bits.Bus = PciDescriptor->Bits.Bus;
+    SourceId.Bits.Device = PciDescriptor->Bits.Device;
+    SourceId.Bits.Function = PciDescriptor->Bits.Function;
+
+    RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
+    if (RootEntry->Bits.Present == 0) {
+      RootEntry->Bits.ContextTablePointer  = RShiftU64 ((UINT64)(UINTN)Buffer, 12);
+      RootEntry->Bits.Present = 1;
+      Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);
+    }
+
+    ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)LShiftU64(RootEntry->Bits.ContextTablePointer, 12) ;
+    ContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];
+    ContextEntry->Bits.TranslationType = 0;
+    ContextEntry->Bits.FaultProcessingDisable = 0;
+    ContextEntry->Bits.Present = 0;
+
+    DEBUG ((DEBUG_INFO,"Source: S%04x B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {
+    case BIT1:
+      ContextEntry->Bits.AddressWidth = 0x1;
+      break;
+    case BIT2:
+      ContextEntry->Bits.AddressWidth = 0x2;
+      break;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Create second level paging entry table.
+
+  @param[in]  VtdIndex                    The index of the VTd engine.
+  @param[in]  SecondLevelPagingEntry      The second level paging entry.
+  @param[in]  MemoryBase                  The base of the memory.
+  @param[in]  MemoryLimit                 The limit of the memory.
+  @param[in]  IoMmuAccess                 The IOMMU access.
+
+  @return The second level paging entry.
+**/
+VTD_SECOND_LEVEL_PAGING_ENTRY *
+CreateSecondLevelPagingEntryTable (
+  IN UINTN                         VtdIndex,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        MemoryBase,
+  IN UINT64                        MemoryLimit,
+  IN UINT64                        IoMmuAccess
+  )
+{
+  UINTN                          Index4;
+  UINTN                          Index3;
+  UINTN                          Index2;
+  UINTN                          Lvl4Start;
+  UINTN                          Lvl4End;
+  UINTN                          Lvl3Start;
+  UINTN                          Lvl3End;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl4PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl3PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl2PtEntry;
+  UINT64                         BaseAddress;
+  UINT64                         EndAddress;
+
+  if (MemoryLimit == 0) {
+    return EFI_SUCCESS;
+  }
+
+  BaseAddress = ALIGN_VALUE_LOW(MemoryBase, SIZE_2MB);
+  EndAddress = ALIGN_VALUE_UP(MemoryLimit, SIZE_2MB);
+  DEBUG ((DEBUG_INFO,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%016lx, EndAddress - 0x%016lx\n", BaseAddress, EndAddress));
+
+  if (SecondLevelPagingEntry == NULL) {
+    SecondLevelPagingEntry = AllocateZeroPages (1);
+    if (SecondLevelPagingEntry == NULL) {
+      DEBUG ((DEBUG_ERROR,"Could not Alloc LVL4 PT. \n"));
+      return NULL;
+    }
+  }
+
+  //
+  // If no access is needed, just create not present entry.
+  //
+  if (IoMmuAccess == 0) {
+    return SecondLevelPagingEntry;
+  }
+
+  Lvl4Start = RShiftU64 (BaseAddress, 39) & 0x1FF;
+  Lvl4End = RShiftU64 (EndAddress - 1, 39) & 0x1FF;
+
+  DEBUG ((DEBUG_INFO,"  Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start, Lvl4End));
+
+  Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;
+  for (Index4 = Lvl4Start; Index4 <= Lvl4End; Index4++) {
+    if (Lvl4PtEntry[Index4].Uint64 == 0) {
+      Lvl4PtEntry[Index4].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);
+      if (Lvl4PtEntry[Index4].Uint64 == 0) {
+        DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));
+        ASSERT(FALSE);
+        return NULL;
+      }
+      SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+    }
+
+    Lvl3Start = RShiftU64 (BaseAddress, 30) & 0x1FF;
+    if (ALIGN_VALUE_LOW(BaseAddress + SIZE_1GB, SIZE_1GB) <= EndAddress) {
+      Lvl3End = SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY);
+    } else {
+      Lvl3End = RShiftU64 (EndAddress - 1, 30) & 0x1FF;
+    }
+    DEBUG ((DEBUG_INFO,"  Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n", Index4, Lvl3Start, Lvl3End));
+
+    Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)LShiftU64 (Lvl4PtEntry[Index4].Bits.Address, 12);
+    for (Index3 = Lvl3Start; Index3 <= Lvl3End; Index3++) {
+      if (Lvl3PtEntry[Index3].Uint64 == 0) {
+        Lvl3PtEntry[Index3].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);
+        if (Lvl3PtEntry[Index3].Uint64 == 0) {
+          DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));
+          ASSERT(FALSE);
+          return NULL;
+        }
+        SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+      }
+
+      Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)LShiftU64 (Lvl3PtEntry[Index3].Bits.Address, 12);
+      for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {
+        Lvl2PtEntry[Index2].Uint64 = BaseAddress;
+        SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry[Index2], IoMmuAccess);
+        Lvl2PtEntry[Index2].Bits.PageSize = 1;
+        BaseAddress += SIZE_2MB;
+        if (BaseAddress >= MemoryLimit) {
+          goto Done;
+        }
+      }
+    }
+  }
+
+Done:
+  return SecondLevelPagingEntry;
+}
+
+/**
+  Create second level paging entry.
+
+  @param[in]  VtdIndex                    The index of the VTd engine.
+  @param[in]  IoMmuAccess                 The IOMMU access.
+
+  @return The second level paging entry.
+**/
+VTD_SECOND_LEVEL_PAGING_ENTRY *
+CreateSecondLevelPagingEntry (
+  IN UINTN   VtdIndex,
+  IN UINT64  IoMmuAccess
+  )
+{
+  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;
+
+  SecondLevelPagingEntry = NULL;
+  SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, 0, mBelow4GMemoryLimit, IoMmuAccess);
+  if (SecondLevelPagingEntry == NULL) {
+    return NULL;
+  }
+  SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, SIZE_4GB, mAbove4GMemoryLimit, IoMmuAccess);
+  if (SecondLevelPagingEntry == NULL) {
+    return NULL;
+  }
+
+  return SecondLevelPagingEntry;
+}
+
+/**
+  Setup VTd translation table.
+
+  @retval EFI_SUCCESS           Setup translation table successfully.
+  @retval EFI_OUT_OF_RESOURCE   Setup translation table fail.
+**/
+EFI_STATUS
+SetupTranslationTable (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  UINTN           Index;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, "CreateContextEntry - %d\n", Index));
+    if (mVtdUnitInformation[Index].ECapReg.Bits.ECS) {
+      Status = CreateExtContextEntry (Index);
+    } else {
+      Status = CreateContextEntry (Index);
+    }
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump DMAR context entry table.
+
+  @param[in]  RootEntry DMAR root entry.
+**/
+VOID
+DumpDmarContextEntryTable (
+  IN VTD_ROOT_ENTRY *RootEntry
+  )
+{
+  UINTN                 Index;
+  UINTN                 Index2;
+  VTD_CONTEXT_ENTRY     *ContextEntry;
+
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+  DEBUG ((DEBUG_INFO,"DMAR Context Entry Table:\n"));
+
+  DEBUG ((DEBUG_INFO,"RootEntry Address - 0x%x\n", RootEntry));
+
+  for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {
+    if ((RootEntry[Index].Uint128.Uint64Lo != 0) || (RootEntry[Index].Uint128.Uint64Hi != 0)) {
+      DEBUG ((DEBUG_INFO,"  RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",
+        Index, Index, RootEntry[Index].Uint128.Uint64Hi, RootEntry[Index].Uint128.Uint64Lo));
+    }
+    if (RootEntry[Index].Bits.Present == 0) {
+      continue;
+    }
+    ContextEntry = (VTD_CONTEXT_ENTRY *)(UINTN)LShiftU64 (RootEntry[Index].Bits.ContextTablePointer, 12);
+    for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER; Index2++) {
+      if ((ContextEntry[Index2].Uint128.Uint64Lo != 0) || (ContextEntry[Index2].Uint128.Uint64Hi != 0)) {
+        DEBUG ((DEBUG_INFO,"    ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n",
+          Index2, Index2 >> 3, Index2 & 0x7, ContextEntry[Index2].Uint128.Uint64Hi, ContextEntry[Index2].Uint128.Uint64Lo));
+      }
+      if (ContextEntry[Index2].Bits.Present == 0) {
+        continue;
+      }
+      DumpSecondLevelPagingEntry ((VOID *)(UINTN)LShiftU64 (ContextEntry[Index2].Bits.SecondLevelPageTranslationPointer, 12));
+    }
+  }
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+}
+
+/**
+  Dump DMAR second level paging entry.
+
+  @param[in]  SecondLevelPagingEntry The second level paging entry.
+**/
+VOID
+DumpSecondLevelPagingEntry (
+  IN VOID *SecondLevelPagingEntry
+  )
+{
+  UINTN                          Index4;
+  UINTN                          Index3;
+  UINTN                          Index2;
+  UINTN                          Index1;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl4PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl3PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl2PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl1PtEntry;
+
+  DEBUG ((DEBUG_VERBOSE,"================\n"));
+  DEBUG ((DEBUG_VERBOSE,"DMAR Second Level Page Table:\n"));
+
+  DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));
+  Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;
+  for (Index4 = 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index4++) {
+    if (Lvl4PtEntry[Index4].Uint64 != 0) {
+      DEBUG ((DEBUG_VERBOSE,"  Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4, Lvl4PtEntry[Index4].Uint64));
+    }
+    if (Lvl4PtEntry[Index4].Uint64 == 0) {
+      continue;
+    }
+    Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)LShiftU64 (Lvl4PtEntry[Index4].Bits.Address, 12);
+    for (Index3 = 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index3++) {
+      if (Lvl3PtEntry[Index3].Uint64 != 0) {
+        DEBUG ((DEBUG_VERBOSE,"    Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3, Lvl3PtEntry[Index3].Uint64));
+      }
+      if (Lvl3PtEntry[Index3].Uint64 == 0) {
+        continue;
+      }
+
+      Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)LShiftU64 (Lvl3PtEntry[Index3].Bits.Address, 12);
+      for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {
+        if (Lvl2PtEntry[Index2].Uint64 != 0) {
+          DEBUG ((DEBUG_VERBOSE,"      Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2, Lvl2PtEntry[Index2].Uint64));
+        }
+        if (Lvl2PtEntry[Index2].Uint64 == 0) {
+          continue;
+        }
+        if (Lvl2PtEntry[Index2].Bits.PageSize == 0) {
+          Lvl1PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)LShiftU64 (Lvl2PtEntry[Index2].Bits.Address, 12);
+          for (Index1 = 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index1++) {
+            if (Lvl1PtEntry[Index1].Uint64 != 0) {
+              DEBUG ((DEBUG_VERBOSE,"        Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1, Lvl1PtEntry[Index1].Uint64));
+            }
+          }
+        }
+      }
+    }
+  }
+  DEBUG ((DEBUG_VERBOSE,"================\n"));
+}
+
+/**
+  Invalid page entry.
+
+  @param VtdIndex  The VTd engine index.
+**/
+VOID
+InvalidatePageEntry (
+  IN UINTN                 VtdIndex
+  )
+{
+  if (mVtdUnitInformation[VtdIndex].HasDirtyPages) {
+    InvalidateVtdIOTLBGlobal (VtdIndex);
+  }
+  mVtdUnitInformation[VtdIndex].HasDirtyPages = FALSE;
+}
+
+#define VTD_PG_R                   BIT0
+#define VTD_PG_W                   BIT1
+#define VTD_PG_X                   BIT2
+#define VTD_PG_EMT                 (BIT3 | BIT4 | BIT5)
+#define VTD_PG_TM                  (BIT62)
+
+#define VTD_PG_PS                  BIT7
+
+#define PAGE_PROGATE_BITS          (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VTD_PG_R)
+
+#define PAGING_4K_MASK  0xFFF
+#define PAGING_2M_MASK  0x1FFFFF
+#define PAGING_1G_MASK  0x3FFFFFFF
+
+#define PAGING_VTD_INDEX_MASK     0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+typedef enum {
+  PageNone,
+  Page4K,
+  Page2M,
+  Page1G,
+} PAGE_ATTRIBUTE;
+
+typedef struct {
+  PAGE_ATTRIBUTE   Attribute;
+  UINT64           Length;
+  UINT64           AddressMask;
+} PAGE_ATTRIBUTE_TABLE;
+
+PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
+  {Page4K,  SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
+  {Page2M,  SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
+  {Page1G,  SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
+};
+
+/**
+  Return length according to page attributes.
+
+  @param[in]  PageAttributes   The page attribute of the page entry.
+
+  @return The length of page entry.
+**/
+UINTN
+PageAttributeToLength (
+  IN PAGE_ATTRIBUTE  PageAttribute
+  )
+{
+  UINTN  Index;
+  for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
+    if (PageAttribute == mPageAttributeTable[Index].Attribute) {
+      return (UINTN)mPageAttributeTable[Index].Length;
+    }
+  }
+  return 0;
+}
+
+/**
+  Return page table entry to match the address.
+
+  @param[in]   SecondLevelPagingEntry   The second level paging entry in VTd table for the device.
+  @param[in]   Address                  The address to be checked.
+  @param[out]  PageAttributes           The page attribute of the page entry.
+
+  @return The page entry.
+**/
+VOID *
+GetSecondLevelPageTableEntry (
+  IN  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN  PHYSICAL_ADDRESS              Address,
+  OUT PAGE_ATTRIBUTE                *PageAttribute
+  )
+{
+  UINTN                 Index1;
+  UINTN                 Index2;
+  UINTN                 Index3;
+  UINTN                 Index4;
+  UINT64                *L1PageTable;
+  UINT64                *L2PageTable;
+  UINT64                *L3PageTable;
+  UINT64                *L4PageTable;
+
+  Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_VTD_INDEX_MASK;
+  Index3 = ((UINTN)Address >> 30) & PAGING_VTD_INDEX_MASK;
+  Index2 = ((UINTN)Address >> 21) & PAGING_VTD_INDEX_MASK;
+  Index1 = ((UINTN)Address >> 12) & PAGING_VTD_INDEX_MASK;
+
+  L4PageTable = (UINT64 *)SecondLevelPagingEntry;
+  if (L4PageTable[Index4] == 0) {
+    L4PageTable[Index4] = (UINT64)(UINTN)AllocateZeroPages (1);
+    if (L4PageTable[Index4] == 0) {
+      DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));
+      ASSERT(FALSE);
+      *PageAttribute = PageNone;
+      return NULL;
+    }
+    SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+  }
+
+  L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
+  if (L3PageTable[Index3] == 0) {
+    L3PageTable[Index3] = (UINT64)(UINTN)AllocateZeroPages (1);
+    if (L3PageTable[Index3] == 0) {
+      DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));
+      ASSERT(FALSE);
+      *PageAttribute = PageNone;
+      return NULL;
+    }
+    SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+  }
+  if ((L3PageTable[Index3] & VTD_PG_PS) != 0) {
+    // 1G
+    *PageAttribute = Page1G;
+    return &L3PageTable[Index3];
+  }
+
+  L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
+  if (L2PageTable[Index2] == 0) {
+    L2PageTable[Index2] = Address & PAGING_2M_ADDRESS_MASK_64;
+    SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L2PageTable[Index2], 0);
+    L2PageTable[Index2] |= VTD_PG_PS;
+  }
+  if ((L2PageTable[Index2] & VTD_PG_PS) != 0) {
+    // 2M
+    *PageAttribute = Page2M;
+    return &L2PageTable[Index2];
+  }
+
+  // 4k
+  L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
+  if ((L1PageTable[Index1] == 0) && (Address != 0)) {
+    *PageAttribute = PageNone;
+    return NULL;
+  }
+  *PageAttribute = Page4K;
+  return &L1PageTable[Index1];
+}
+
+/**
+  Modify memory attributes of page entry.
+
+  @param[in]   PageEntry        The page entry.
+  @param[in]   IoMmuAccess      The IOMMU access.
+  @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.
+**/
+VOID
+ConvertSecondLevelPageEntryAttribute (
+  IN  VTD_SECOND_LEVEL_PAGING_ENTRY     *PageEntry,
+  IN  UINT64                            IoMmuAccess,
+  OUT BOOLEAN                           *IsModified
+  )
+{
+  UINT64  CurrentPageEntry;
+  UINT64  NewPageEntry;
+
+  CurrentPageEntry = PageEntry->Uint64;
+  SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);
+  NewPageEntry = PageEntry->Uint64;
+  if (CurrentPageEntry != NewPageEntry) {
+    *IsModified = TRUE;
+    DEBUG ((DEBUG_VERBOSE, "ConvertSecondLevelPageEntryAttribute 0x%lx", CurrentPageEntry));
+    DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
+  } else {
+    *IsModified = FALSE;
+  }
+}
+
+/**
+  This function returns if there is need to split page entry.
+
+  @param[in]  BaseAddress      The base address to be checked.
+  @param[in]  Length           The length to be checked.
+  @param[in]  PageAttribute    The page attribute of the page entry.
+
+  @retval SplitAttributes on if there is need to split page entry.
+**/
+PAGE_ATTRIBUTE
+NeedSplitPage (
+  IN  PHYSICAL_ADDRESS                  BaseAddress,
+  IN  UINT64                            Length,
+  IN  PAGE_ATTRIBUTE                    PageAttribute
+  )
+{
+  UINT64                PageEntryLength;
+
+  PageEntryLength = PageAttributeToLength (PageAttribute);
+
+  if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
+    return PageNone;
+  }
+
+  if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
+    return Page4K;
+  }
+
+  return Page2M;
+}
+
+/**
+  This function splits one page entry to small page entries.
+
+  @param[in]  PageEntry        The page entry to be splitted.
+  @param[in]  PageAttribute    The page attribute of the page entry.
+  @param[in]  SplitAttribute   How to split the page entry.
+
+  @retval RETURN_SUCCESS            The page entry is splitted.
+  @retval RETURN_UNSUPPORTED        The page entry does not support to be splitted.
+  @retval RETURN_OUT_OF_RESOURCES   No resource to split page entry.
+**/
+RETURN_STATUS
+SplitSecondLevelPage (
+  IN  VTD_SECOND_LEVEL_PAGING_ENTRY     *PageEntry,
+  IN  PAGE_ATTRIBUTE                    PageAttribute,
+  IN  PAGE_ATTRIBUTE                    SplitAttribute
+  )
+{
+  UINT64   BaseAddress;
+  UINT64   *NewPageEntry;
+  UINTN    Index;
+
+  ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
+
+  if (PageAttribute == Page2M) {
+    //
+    // Split 2M to 4K
+    //
+    ASSERT (SplitAttribute == Page4K);
+    if (SplitAttribute == Page4K) {
+      NewPageEntry = AllocateZeroPages (1);
+      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
+      if (NewPageEntry == NULL) {
+        return RETURN_OUT_OF_RESOURCES;
+      }
+      BaseAddress = PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_64;
+      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
+        NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | (PageEntry->Uint64 & PAGE_PROGATE_BITS);
+      }
+      PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;
+      SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+      return RETURN_SUCCESS;
+    } else {
+      return RETURN_UNSUPPORTED;
+    }
+  } else if (PageAttribute == Page1G) {
+    //
+    // Split 1G to 2M
+    // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
+    //
+    ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
+    if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
+      NewPageEntry = AllocateZeroPages (1);
+      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
+      if (NewPageEntry == NULL) {
+        return RETURN_OUT_OF_RESOURCES;
+      }
+      BaseAddress = PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_64;
+      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
+        NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | VTD_PG_PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);
+      }
+      PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;
+      SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+      return RETURN_SUCCESS;
+    } else {
+      return RETURN_UNSUPPORTED;
+    }
+  } else {
+    return RETURN_UNSUPPORTED;
+  }
+}
+
+/**
+  Set VTd attribute for a system memory on second level page entry
+
+  @param[in]  VtdIndex                The index used to identify a VTd engine.
+  @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
+  @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
+  @param[in]  Length                  The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess             The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetSecondLevelPagingAttribute (
+  IN UINTN                         VtdIndex,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        BaseAddress,
+  IN UINT64                        Length,
+  IN UINT64                        IoMmuAccess
+  )
+{
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *PageEntry;
+  PAGE_ATTRIBUTE                 PageAttribute;
+  UINTN                          PageEntryLength;
+  PAGE_ATTRIBUTE                 SplitAttribute;
+  EFI_STATUS                     Status;
+  BOOLEAN                        IsEntryModified;
+
+  DEBUG ((DEBUG_VERBOSE,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x%016lx : %x) \n", VtdIndex, BaseAddress, Length, IoMmuAccess));
+  DEBUG ((DEBUG_VERBOSE,"  SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));
+
+  if (BaseAddress != ALIGN_VALUE(BaseAddress, SIZE_4KB)) {
+    DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
+    return EFI_UNSUPPORTED;
+  }
+  if (Length != ALIGN_VALUE(Length, SIZE_4KB)) {
+    DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  while (Length != 0) {
+    PageEntry = GetSecondLevelPageTableEntry (SecondLevelPagingEntry, BaseAddress, &PageAttribute);
+    if (PageEntry == NULL) {
+      DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));
+      return RETURN_UNSUPPORTED;
+    }
+    PageEntryLength = PageAttributeToLength (PageAttribute);
+    SplitAttribute = NeedSplitPage (BaseAddress, Length, PageAttribute);
+    if (SplitAttribute == PageNone) {
+      ConvertSecondLevelPageEntryAttribute (PageEntry, IoMmuAccess, &IsEntryModified);
+      if (IsEntryModified) {
+        mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;
+      }
+      //
+      // Convert success, move to next
+      //
+      BaseAddress += PageEntryLength;
+      Length -= PageEntryLength;
+    } else {
+      Status = SplitSecondLevelPage (PageEntry, PageAttribute, SplitAttribute);
+      if (RETURN_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));
+        return RETURN_UNSUPPORTED;
+      }
+      mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;
+      //
+      // Just split current page
+      // Convert success in next around
+      //
+    }
+  }
+
+  InvalidatePageEntry (VtdIndex);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  VtdIndex                The index used to identify a VTd engine.
+  @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
+  @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
+  @param[in]  Length                  The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess             The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetPageAttribute (
+  IN UINTN                         VtdIndex,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        BaseAddress,
+  IN UINT64                        Length,
+  IN UINT64                        IoMmuAccess
+  )
+{
+  EFI_STATUS Status;
+  Status = EFI_NOT_FOUND;
+  if (SecondLevelPagingEntry != NULL) {
+    Status = SetSecondLevelPagingAttribute (VtdIndex, SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);
+  }
+  return Status;
+}
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetAccessAttribute (
+  IN UINT16                Segment,
+  IN VTD_SOURCE_ID         SourceId,
+  IN UINT64                BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  )
+{
+  UINTN                         VtdIndex;
+  EFI_STATUS                    Status;
+  VTD_EXT_CONTEXT_ENTRY         *ExtContextEntry;
+  VTD_CONTEXT_ENTRY             *ContextEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;
+  UINT64                        Pt;
+
+  DEBUG ((DEBUG_INFO,"SetAccessAttribute (S%04x B%02x D%02x F%02x) (0x%016lx - 0x%08x, %x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, BaseAddress, (UINTN)Length, IoMmuAccess));
+
+  VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);
+  if (VtdIndex == (UINTN)-1) {
+    DEBUG ((DEBUG_ERROR,"SetAccessAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (ExtContextEntry != NULL) {
+    if (ExtContextEntry->Bits.Present == 0) {
+      SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);
+
+      ExtContextEntry->Bits.SecondLevelPageTranslationPointer = Pt;
+      ExtContextEntry->Bits.DomainIdentifier = GetPciDescriptor (VtdIndex, Segment, SourceId);
+      ExtContextEntry->Bits.Present = 1;
+      DumpDmarExtContextEntryTable (mVtdUnitInformation[VtdIndex].ExtRootEntryTable);
+    } else {
+      SecondLevelPagingEntry = (VOID *)(UINTN)LShiftU64 (ExtContextEntry->Bits.SecondLevelPageTranslationPointer, 12);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    }
+  } else {
+    if (ContextEntry->Bits.Present == 0) {
+      SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);
+
+      ContextEntry->Bits.SecondLevelPageTranslationPointer = Pt;
+      ContextEntry->Bits.DomainIdentifier = GetPciDescriptor (VtdIndex, Segment, SourceId);
+      ContextEntry->Bits.Present = 1;
+      DumpDmarContextEntryTable (mVtdUnitInformation[VtdIndex].RootEntryTable);
+    } else {
+      SecondLevelPagingEntry = (VOID *)(UINTN)LShiftU64 (ContextEntry->Bits.SecondLevelPageTranslationPointer, 12);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    }
+  }
+
+  //
+  // Do not update FixedSecondLevelPagingEntry
+  //
+  if (SecondLevelPagingEntry != mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry) {
+    Status = SetPageAttribute (
+               VtdIndex,
+               SecondLevelPagingEntry,
+               BaseAddress,
+               Length,
+               IoMmuAccess
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR,"SetPageAttribute - %r\n", Status));
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Always enable the VTd page attribute for the device.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
+**/
+EFI_STATUS
+AlwaysEnablePageAttribute (
+  IN UINT16                  Segment,
+  IN VTD_SOURCE_ID           SourceId
+  )
+{
+  UINTN                         VtdIndex;
+  VTD_EXT_CONTEXT_ENTRY         *ExtContextEntry;
+  VTD_CONTEXT_ENTRY             *ContextEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;
+  UINT64                        Pt;
+
+  DEBUG ((DEBUG_INFO,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+  VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);
+  if (VtdIndex == (UINTN)-1) {
+    DEBUG ((DEBUG_ERROR,"AlwaysEnablePageAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry == 0) {
+    DEBUG((DEBUG_INFO, "CreateSecondLevelPagingEntry - %d\n", VtdIndex));
+    mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+  }
+
+  SecondLevelPagingEntry = mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry;
+  Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);
+  if (ExtContextEntry != NULL) {
+    ExtContextEntry->Bits.SecondLevelPageTranslationPointer = Pt;
+    ExtContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);
+    ExtContextEntry->Bits.Present = 1;
+  } else {
+    ContextEntry->Bits.SecondLevelPageTranslationPointer = Pt;
+    ContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);
+    ContextEntry->Bits.Present = 1;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/IntelSiliconPkg/IntelVTdDxe/TranslationTableEx.c b/IntelSiliconPkg/IntelVTdDxe/TranslationTableEx.c
new file mode 100644
index 0000000..0f54b97
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/TranslationTableEx.c
@@ -0,0 +1,153 @@
+/** @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 "DmaProtection.h"
+
+/**
+  Create extended context entry.
+
+  @param[in]  VtdIndex  The index of the VTd engine.
+
+  @retval EFI_SUCCESS          The extended context entry is created.
+  @retval EFI_OUT_OF_RESOURCE  No enough resource to create extended context entry.
+**/
+EFI_STATUS
+CreateExtContextEntry (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN                  Index;
+  VOID                   *Buffer;
+  UINTN                  RootPages;
+  UINTN                  ContextPages;
+  VTD_EXT_ROOT_ENTRY     *ExtRootEntry;
+  VTD_EXT_CONTEXT_ENTRY  *ExtContextEntryTable;
+  VTD_EXT_CONTEXT_ENTRY  *ExtContextEntry;
+  VTD_SOURCE_ID          *PciDescriptor;
+  VTD_SOURCE_ID          SourceId;
+  UINTN                  MaxBusNumber;
+  UINTN                  EntryTablePages;
+
+  MaxBusNumber = 0;
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {
+    PciDescriptor = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index];
+    if (PciDescriptor->Bits.Bus > MaxBusNumber) {
+      MaxBusNumber = PciDescriptor->Bits.Bus;
+    }
+  }
+  DEBUG ((DEBUG_INFO,"  MaxBusNumber - 0x%x\n", MaxBusNumber));
+
+  RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);
+  ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);
+  EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);
+  Buffer = AllocateZeroPages (EntryTablePages);
+  if (Buffer == NULL) {
+    DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  mVtdUnitInformation[VtdIndex].ExtRootEntryTable = (VTD_EXT_ROOT_ENTRY *)Buffer;
+  Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);
+
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptorNumber; Index++) {
+    PciDescriptor = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDescriptors[Index];
+
+    SourceId.Bits.Bus = PciDescriptor->Bits.Bus;
+    SourceId.Bits.Device = PciDescriptor->Bits.Device;
+    SourceId.Bits.Function = PciDescriptor->Bits.Function;
+
+    ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
+    if (ExtRootEntry->Bits.LowerPresent == 0) {
+      ExtRootEntry->Bits.LowerContextTablePointer  = RShiftU64 ((UINT64)(UINTN)Buffer, 12);
+      ExtRootEntry->Bits.LowerPresent = 1;
+      ExtRootEntry->Bits.UpperContextTablePointer  = RShiftU64 ((UINT64)(UINTN)Buffer, 12) + 1;
+      ExtRootEntry->Bits.UpperPresent = 1;
+      Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);
+    }
+
+    ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)LShiftU64(ExtRootEntry->Bits.LowerContextTablePointer, 12) ;
+    ExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];
+    ExtContextEntry->Bits.TranslationType = 0;
+    ExtContextEntry->Bits.FaultProcessingDisable = 0;
+    ExtContextEntry->Bits.Present = 0;
+
+    DEBUG ((DEBUG_INFO,"DOMAIN: S%04x, B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {
+    case BIT1:
+      ExtContextEntry->Bits.AddressWidth = 0x1;
+      break;
+    case BIT2:
+      ExtContextEntry->Bits.AddressWidth = 0x2;
+      break;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump DMAR extended context entry table.
+
+  @param[in]  ExtRootEntry DMAR extended root entry.
+**/
+VOID
+DumpDmarExtContextEntryTable (
+  IN VTD_EXT_ROOT_ENTRY *ExtRootEntry
+  )
+{
+  UINTN                 Index;
+  UINTN                 Index2;
+  VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;
+
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+  DEBUG ((DEBUG_INFO,"DMAR ExtContext Entry Table:\n"));
+
+  DEBUG ((DEBUG_INFO,"ExtRootEntry Address - 0x%x\n", ExtRootEntry));
+
+  for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {
+    if ((ExtRootEntry[Index].Uint128.Uint64Lo != 0) || (ExtRootEntry[Index].Uint128.Uint64Hi != 0)) {
+      DEBUG ((DEBUG_INFO,"  ExtRootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",
+        Index, Index, ExtRootEntry[Index].Uint128.Uint64Hi, ExtRootEntry[Index].Uint128.Uint64Lo));
+    }
+    if (ExtRootEntry[Index].Bits.LowerPresent == 0) {
+      continue;
+    }
+    ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)LShiftU64 (ExtRootEntry[Index].Bits.LowerContextTablePointer, 12);
+    for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {
+      if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) ||
+          (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) {
+        DEBUG ((DEBUG_INFO,"    ExtContextEntryLower(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n",
+          Index2, Index2 >> 3, Index2 & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));
+      }
+      if (ExtContextEntry[Index2].Bits.Present == 0) {
+        continue;
+      }
+    }
+
+    if (ExtRootEntry[Index].Bits.UpperPresent == 0) {
+      continue;
+    }
+    ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)LShiftU64 (ExtRootEntry[Index].Bits.UpperContextTablePointer, 12);
+    for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {
+      if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) ||
+          (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) {
+        DEBUG ((DEBUG_INFO,"    ExtContextEntryUpper(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n",
+          Index2, (Index2 + 128) >> 3, (Index2 + 128) & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));
+      }
+      if (ExtContextEntry[Index2].Bits.Present == 0) {
+        continue;
+      }
+    }
+  }
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+}
diff --git a/IntelSiliconPkg/IntelVTdDxe/VtdReg.c b/IntelSiliconPkg/IntelVTdDxe/VtdReg.c
new file mode 100644
index 0000000..456a039
--- /dev/null
+++ b/IntelSiliconPkg/IntelVTdDxe/VtdReg.c
@@ -0,0 +1,602 @@
+/** @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 "DmaProtection.h"
+
+UINT64                           mVtdHostAddressWidthMask;
+UINTN                            mVtdUnitNumber;
+VTD_UNIT_INFORMATION             *mVtdUnitInformation;
+
+BOOLEAN  mVtdEnabled;
+
+/**
+  Invalid VTd global IOTLB.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+
+  @retval EFI_SUCCESS           VTd global IOTLB is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd global IOTLB is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBGlobal (
+  IN UINTN  VtdIndex
+  )
+{
+  UINT64  Reg64;
+  UINT32  Reg32;
+
+  if (!mVtdEnabled) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBGlobal(%d)\n", VtdIndex));
+
+  AsmWbinvd();
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CAP_REG);
+  if ((Reg32 & B_CAP_REG_RWBF) != 0) {
+    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_WBF);
+  }
+
+  //
+  // Invalidate the context cache
+  //
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateVtdIOTLBGlobal: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));
+    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 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+  //
+  // Invalidate the IOTLB cache
+  //
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateVtdIOTLBGlobal: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
+    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 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+  //
+  // Disable VTd
+  //
+  MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+  do {
+    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  //
+  // Enable VTd
+  //
+  MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+  do {
+    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalid VTd IOTLB domain.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  DomainIdentifier      The domain ID of the source.
+
+  @retval EFI_SUCCESS           VTd IOTLB domain is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd IOTLB domain is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBDomain (
+  IN UINTN  VtdIndex,
+  IN UINT16 DomainIdentifier
+  )
+{
+  UINT64  Reg64;
+
+  if (!mVtdEnabled) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBDomain(%d): 0x%016lx (0x%04x)\n", VtdIndex, DomainIdentifier));
+
+  //
+  // Invalidate the context cache
+  //
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateVtdIOTLBDomain: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+  Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_DOMAIN);
+  Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_DOMAIN);
+  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+  //
+  // Invalidate the IOTLB cache
+  //
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateVtdIOTLBDomain: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+  Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_DOMAIN);
+  Reg64 |= DomainIdentifier;
+  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalid VTd IOTLB page.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Address               The address of IOTLB page.
+  @param[in]  AddressMode           The address mode of IOTLB page.
+  @param[in]  DomainIdentifier      The domain ID of the source.
+
+  @retval EFI_SUCCESS           VTd IOTLB page is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd IOTLB page is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBPage (
+  IN UINTN  VtdIndex,
+  IN UINT64 Address,
+  IN UINT8  AddressMode,
+  IN UINT16 DomainIdentifier
+  )
+{
+  UINT64  Reg64;
+  UINT64  Data64;
+
+  if (!mVtdEnabled) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBPage(%d): 0x%016lx (0x%02x)\n", VtdIndex, Address, AddressMode));
+
+  if (mVtdUnitInformation[VtdIndex].CapReg.Bits.PSI != 0) {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+    if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+      DEBUG ((DEBUG_ERROR,"ERROR: InvalidateVtdIOTLBPage: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
+      return EFI_DEVICE_ERROR;
+    }
+
+    Data64 = Address | AddressMode;
+    MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IVA_REG, Data64);
+
+    Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+    Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_PAGE);
+    Reg64 |= LShiftU64 (DomainIdentifier, 32);
+    MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+    do {
+      Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+    } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+  } else {
+    InvalidateVtdIOTLBGlobal (VtdIndex);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Prepare VTD configuration.
+**/
+VOID
+PrepareVtdConfig (
+  VOID
+  )
+{
+  UINTN         Index;
+  UINTN         DomainNumber;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index));
+    mVtdUnitInformation[Index].CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
+    DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg);
+    mVtdUnitInformation[Index].ECapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_ECAP_REG);
+    DumpVtdECapRegs (&mVtdUnitInformation[Index].ECapReg);
+
+    if ((mVtdUnitInformation[Index].CapReg.Bits.SLLPS & BIT0) == 0) {
+      DEBUG((DEBUG_WARN, "!!!! 2MB super page is not supported on VTD %d !!!!\n", Index));
+    }
+    if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT2) == 0) {
+      DEBUG((DEBUG_ERROR, "!!!! 4-level page-table is not supported on VTD %d !!!!\n", Index));
+      return ;
+    }
+
+    DomainNumber = (UINTN)1 << (UINT8)((UINTN)mVtdUnitInformation[Index].CapReg.Bits.ND * 2 + 4);
+    if (mVtdUnitInformation[Index].PciDeviceInfo.PciDescriptorNumber >= DomainNumber) {
+      DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >= DomainNumber(0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo.PciDescriptorNumber, DomainNumber));
+      return ;
+    }
+  }
+  return ;
+}
+
+/**
+  Enable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  VOID
+  )
+{
+  UINTN     Index;
+  UINT64    Reg64;
+  UINT32    Reg32;
+
+  AsmWbinvd();
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%d] \n", Index));
+
+    if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {
+      DEBUG((DEBUG_INFO, "ExtRootEntryTable 0x%x \n", mVtdUnitInformation[Index].ExtRootEntryTable));
+      MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].ExtRootEntryTable | BIT11);
+    } else {
+      DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", mVtdUnitInformation[Index].RootEntryTable));
+      MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].RootEntryTable);
+    }
+
+    MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+
+    DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+    //
+    // Init DMAr Fault Event and Data registers
+    //
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_FEDATA_REG);
+
+    //
+    // Write Buffer Flush before invalidation
+    //
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
+    if ((Reg32 & B_CAP_REG_RWBF) != 0) {
+      MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_WBF);
+    }
+
+    //
+    // Invalidate the context cache
+    //
+    Reg64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CCMD_REG);
+    if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+      DEBUG ((DEBUG_INFO,"ERROR: EnableDmar: B_CCMD_REG_ICC is set for VTD(%d)\n",Index));
+      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 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+    DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_CCMD_REG_ICC ...\n"));
+    do {
+      Reg64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CCMD_REG);
+    } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+    //
+    // Invalidate the IOTLB cache
+    //
+    DEBUG((DEBUG_INFO, "EnableDmar: IRO 0x%x\n", mVtdUnitInformation[Index].ECapReg.Bits.IRO));
+
+    Reg64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + (mVtdUnitInformation[Index].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+    if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+      DEBUG ((DEBUG_INFO,"ERROR: EnableDmar: B_IOTLB_REG_IVT is set for VTD(%d)\n", Index));
+      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 (mVtdUnitInformation[Index].VtdUnitBaseAddress + (mVtdUnitInformation[Index].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+    DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_IOTLB_REG_IVT ...\n"));
+    do {
+      Reg64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + (mVtdUnitInformation[Index].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+    } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+    //
+    // Enable VTd
+    //
+    MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+    DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+    DEBUG ((DEBUG_INFO,"VTD (%d) enabled!<<<<<<\n",Index));
+  }
+
+  mVtdEnabled = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  VOID
+  )
+{
+  UINTN     Index;
+  UINT32    Reg32;
+
+  AsmWbinvd();
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%d] \n", Index));
+
+    //
+    // Write Buffer Flush before invalidation
+    //
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
+    if ((Reg32 & B_CAP_REG_RWBF) != 0) {
+      MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_WBF);
+    }
+
+    //
+    // Disable VTd
+    //
+    MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
+
+    DEBUG ((DEBUG_INFO,"VTD (%d) Disabled!<<<<<<\n",Index));
+  }
+
+  mVtdEnabled = FALSE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump VTd capability registers.
+
+  @param[in]  CapReg              The capability register.
+**/
+VOID
+DumpVtdCapRegs (
+  IN VTD_CAP_REG *CapReg
+  )
+{
+  DEBUG((DEBUG_INFO, "  CapReg:\n", CapReg->Uint64));
+  DEBUG((DEBUG_INFO, "    ND     - 0x%x\n", CapReg->Bits.ND));
+  DEBUG((DEBUG_INFO, "    AFL    - 0x%x\n", CapReg->Bits.AFL));
+  DEBUG((DEBUG_INFO, "    RWBF   - 0x%x\n", CapReg->Bits.RWBF));
+  DEBUG((DEBUG_INFO, "    PLMR   - 0x%x\n", CapReg->Bits.PLMR));
+  DEBUG((DEBUG_INFO, "    PHMR   - 0x%x\n", CapReg->Bits.PHMR));
+  DEBUG((DEBUG_INFO, "    CM     - 0x%x\n", CapReg->Bits.CM));
+  DEBUG((DEBUG_INFO, "    SAGAW  - 0x%x\n", CapReg->Bits.SAGAW));
+  DEBUG((DEBUG_INFO, "    MGAW   - 0x%x\n", CapReg->Bits.MGAW));
+  DEBUG((DEBUG_INFO, "    ZLR    - 0x%x\n", CapReg->Bits.ZLR));
+  DEBUG((DEBUG_INFO, "    FRO    - 0x%x\n", CapReg->Bits.FRO));
+  DEBUG((DEBUG_INFO, "    SLLPS  - 0x%x\n", CapReg->Bits.SLLPS));
+  DEBUG((DEBUG_INFO, "    PSI    - 0x%x\n", CapReg->Bits.PSI));
+  DEBUG((DEBUG_INFO, "    NFR    - 0x%x\n", CapReg->Bits.NFR));
+  DEBUG((DEBUG_INFO, "    MAMV   - 0x%x\n", CapReg->Bits.MAMV));
+  DEBUG((DEBUG_INFO, "    DWD    - 0x%x\n", CapReg->Bits.DWD));
+  DEBUG((DEBUG_INFO, "    DRD    - 0x%x\n", CapReg->Bits.DRD));
+  DEBUG((DEBUG_INFO, "    FL1GP  - 0x%x\n", CapReg->Bits.FL1GP));
+  DEBUG((DEBUG_INFO, "    PI     - 0x%x\n", CapReg->Bits.PI));
+}
+
+/**
+  Dump VTd extended capability registers.
+
+  @param[in]  ECapReg              The extended capability register.
+**/
+VOID
+DumpVtdECapRegs (
+  IN VTD_ECAP_REG *ECapReg
+  )
+{
+  DEBUG((DEBUG_INFO, "  ECapReg:\n", ECapReg->Uint64));
+  DEBUG((DEBUG_INFO, "    C      - 0x%x\n", ECapReg->Bits.C));
+  DEBUG((DEBUG_INFO, "    QI     - 0x%x\n", ECapReg->Bits.QI));
+  DEBUG((DEBUG_INFO, "    DT     - 0x%x\n", ECapReg->Bits.DT));
+  DEBUG((DEBUG_INFO, "    IR     - 0x%x\n", ECapReg->Bits.IR));
+  DEBUG((DEBUG_INFO, "    EIM    - 0x%x\n", ECapReg->Bits.EIM));
+  DEBUG((DEBUG_INFO, "    PT     - 0x%x\n", ECapReg->Bits.PT));
+  DEBUG((DEBUG_INFO, "    SC     - 0x%x\n", ECapReg->Bits.SC));
+  DEBUG((DEBUG_INFO, "    IRO    - 0x%x\n", ECapReg->Bits.IRO));
+  DEBUG((DEBUG_INFO, "    MHMV   - 0x%x\n", ECapReg->Bits.MHMV));
+  DEBUG((DEBUG_INFO, "    ECS    - 0x%x\n", ECapReg->Bits.ECS));
+  DEBUG((DEBUG_INFO, "    MTS    - 0x%x\n", ECapReg->Bits.MTS));
+  DEBUG((DEBUG_INFO, "    NEST   - 0x%x\n", ECapReg->Bits.NEST));
+  DEBUG((DEBUG_INFO, "    DIS    - 0x%x\n", ECapReg->Bits.DIS));
+  DEBUG((DEBUG_INFO, "    PASID  - 0x%x\n", ECapReg->Bits.PASID));
+  DEBUG((DEBUG_INFO, "    PRS    - 0x%x\n", ECapReg->Bits.PRS));
+  DEBUG((DEBUG_INFO, "    ERS    - 0x%x\n", ECapReg->Bits.ERS));
+  DEBUG((DEBUG_INFO, "    SRS    - 0x%x\n", ECapReg->Bits.SRS));
+  DEBUG((DEBUG_INFO, "    NWFS   - 0x%x\n", ECapReg->Bits.NWFS));
+  DEBUG((DEBUG_INFO, "    EAFS   - 0x%x\n", ECapReg->Bits.EAFS));
+  DEBUG((DEBUG_INFO, "    PSS    - 0x%x\n", ECapReg->Bits.PSS));
+}
+
+/**
+  Dump VTd registers.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpVtdRegs (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN         Index;
+  UINT64        Reg64;
+  VTD_FRCD_REG  FrcdReg;
+  VTD_CAP_REG   CapReg;
+  UINT32        Reg32;
+  VTD_SOURCE_ID SourceId;
+
+  DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) Begin ####\n", VtdIndex));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_VER_REG);
+  DEBUG((DEBUG_INFO, "  VER_REG     - 0x%08x\n", Reg32));
+
+  CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CAP_REG);
+  DEBUG((DEBUG_INFO, "  CAP_REG     - 0x%016lx\n", CapReg.Uint64));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_ECAP_REG);
+  DEBUG((DEBUG_INFO, "  ECAP_REG    - 0x%016lx\n", Reg64));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  DEBUG((DEBUG_INFO, "  GSTS_REG    - 0x%08x \n", Reg32));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_RTADDR_REG);
+  DEBUG((DEBUG_INFO, "  RTADDR_REG  - 0x%016lx\n", Reg64));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  DEBUG((DEBUG_INFO, "  CCMD_REG    - 0x%016lx\n", Reg64));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
+  DEBUG((DEBUG_INFO, "  FSTS_REG    - 0x%08x\n", Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FECTL_REG);
+  DEBUG((DEBUG_INFO, "  FECTL_REG   - 0x%08x\n", Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEDATA_REG);
+  DEBUG((DEBUG_INFO, "  FEDATA_REG  - 0x%08x\n", Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEADDR_REG);
+  DEBUG((DEBUG_INFO, "  FEADDR_REG  - 0x%08x\n",Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEUADDR_REG);
+  DEBUG((DEBUG_INFO, "  FEUADDR_REG - 0x%08x\n",Reg32));
+
+  for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
+    FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));
+    FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
+    DEBUG((DEBUG_INFO, "  FRCD_REG[%d] - 0x%016lx %016lx\n", Index, FrcdReg.Uint64[1], FrcdReg.Uint64[0]));
+    if (FrcdReg.Uint64[1] != 0 || FrcdReg.Uint64[0] != 0) {
+      DEBUG((DEBUG_INFO, "    Fault Info - 0x%016lx\n", LShiftU64(FrcdReg.Bits.FI, 12)));
+      SourceId.Uint16 = (UINT16)FrcdReg.Bits.SID;
+      DEBUG((DEBUG_INFO, "    Source - B%02x D%02x F%02x\n", SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      DEBUG((DEBUG_INFO, "    Type - %x (%a)\n", FrcdReg.Bits.T, FrcdReg.Bits.T ? "read" : "write"));
+      DEBUG((DEBUG_INFO, "    Reason - %x\n", FrcdReg.Bits.FR));
+    }
+  }
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IVA_REG);
+  DEBUG((DEBUG_INFO, "  IVA_REG     - 0x%016lx\n",Reg64));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  DEBUG((DEBUG_INFO, "  IOTLB_REG   - 0x%016lx\n",Reg64));
+
+  DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) End ####\n", VtdIndex));
+}
+
+/**
+  Dump VTd registers for all VTd engine.
+**/
+VOID
+DumpVtdRegsAll (
+  VOID
+  )
+{
+  UINTN       Num;
+
+  for (Num = 0; Num < mVtdUnitNumber; Num++) {
+    DumpVtdRegs (Num);
+  }
+}
+
+/**
+  Dump VTd registers if there is error.
+**/
+VOID
+DumpVtdIfError (
+  VOID
+  )
+{
+  UINTN         Num;
+  UINTN         Index;
+  VTD_FRCD_REG  FrcdReg;
+  VTD_CAP_REG   CapReg;
+  UINT32        Reg32;
+  BOOLEAN       HasError;
+
+  for (Num = 0; Num < mVtdUnitNumber; Num++) {
+    HasError = FALSE;
+    Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG);
+    if (Reg32 != 0) {
+      HasError = TRUE;
+    }
+    Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FECTL_REG);
+    if ((Reg32 & BIT30) != 0) {
+      HasError = TRUE;
+    }
+
+    CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_CAP_REG);
+    for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
+      FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));
+      FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
+      if ((FrcdReg.Uint64[0] != 0) || (FrcdReg.Uint64[1] != 0)) {
+        HasError = TRUE;
+      }
+    }
+
+    if (HasError) {
+      DEBUG((DEBUG_INFO, "#### ERROR ####\n"));
+      DumpVtdRegs (Num);
+      DEBUG((DEBUG_INFO, "#### ERROR ####\n"));
+    }
+  }
+}
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/7] IntelSiliconPkg/dsc: Add Vtd driver.
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
                   ` (3 preceding siblings ...)
  2017-07-18  7:51 ` [PATCH 4/7] IntelSiliconPkg: Add VTd driver Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  2017-07-18  7:51 ` [PATCH 6/7] IntelSiliconPkg: Add PlatformVTdSample driver Jiewen Yao
  2017-07-18  7:51 ` [PATCH 7/7] IntelSiliconPkg/dsc: Add PlatformVtd sample driver Jiewen Yao
  6 siblings, 0 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/IntelSiliconPkg.dsc | 31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/IntelSiliconPkg/IntelSiliconPkg.dsc b/IntelSiliconPkg/IntelSiliconPkg.dsc
index f77f2a9..f2625cb 100644
--- a/IntelSiliconPkg/IntelSiliconPkg.dsc
+++ b/IntelSiliconPkg/IntelSiliconPkg.dsc
@@ -23,6 +23,32 @@
   BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
   SKUID_IDENTIFIER               = DEFAULT
 
+[LibraryClasses]
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+  PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+  IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+  UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+  PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+  SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+
+  HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
 ###################################################################################################
 #
 # Components Section - list of the modules and components that will be processed by compilation
@@ -44,3 +70,8 @@
 
 [Components]
   IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf
+  IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf
+
+[BuildOptions]
+  *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/7] IntelSiliconPkg: Add PlatformVTdSample driver.
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
                   ` (4 preceding siblings ...)
  2017-07-18  7:51 ` [PATCH 5/7] IntelSiliconPkg/dsc: Add Vtd driver Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  2017-07-18  7:51 ` [PATCH 7/7] IntelSiliconPkg/dsc: Add PlatformVtd sample driver Jiewen Yao
  6 siblings, 0 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

It provides sample on Platform VTd policy protocol.
This protocol is optional.

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c        | 339 ++++++++++++++++++++
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf      |  59 ++++
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni      |  20 ++
 IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni |  20 ++
 4 files changed, 438 insertions(+)

diff --git a/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
new file mode 100644
index 0000000..13b5feb
--- /dev/null
+++ b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
@@ -0,0 +1,339 @@
+/** @file
+  Platform VTd Sample driver.
+
+  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 <PiDxe.h>
+
+#include <IndustryStandard/Vtd.h>
+#include <Protocol/PlatformVtdPolicy.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+typedef struct {
+  ACPI_EXTENDED_HID_DEVICE_PATH      I2cController;
+  UINT8                              HidStr[8];
+  UINT8                              UidStr[1];
+  UINT8                              CidStr[8];
+} PLATFORM_I2C_CONTROLLER_DEVICE_PATH;
+
+typedef struct {
+  ACPI_EXTENDED_HID_DEVICE_PATH      I2cDevice;
+  UINT8                              HidStr[13];
+  UINT8                              UidStr[1];
+  UINT8                              CidStr[13];
+} PLATFORM_I2C_DEVICE_DEVICE_PATH;
+
+typedef struct {
+  PLATFORM_I2C_CONTROLLER_DEVICE_PATH      I2cController;
+  PLATFORM_I2C_DEVICE_DEVICE_PATH          I2cDevice;
+  EFI_DEVICE_PATH_PROTOCOL                 End;
+} PLATFORM_I2C_DEVICE_PATH;
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH      PciRootBridge;
+  PCI_DEVICE_PATH           PciDevice;
+  EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
+} PLATFORM_PCI_DEVICE_PATH;
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH      PciRootBridge;
+  PCI_DEVICE_PATH           PciBridge;
+  PCI_DEVICE_PATH           PciDevice;
+  EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
+} PLATFORM_PCI_BRIDGE_DEVICE_PATH;
+
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  UINT16                    Segment;
+  VTD_SOURCE_ID             SourceId;
+} PLATFORM_ACPI_DEVICE_MAPPING;
+
+#define PLATFORM_PCI_ROOT_BRIDGE \
+  { \
+    { \
+      ACPI_DEVICE_PATH, \
+      ACPI_DP, \
+      { \
+        (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+        (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+      }, \
+    }, \
+    EISA_PNP_ID (0x0A03), \
+    0 \
+  }
+
+#define PLATFORM_END_ENTIRE \
+  { \
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
+  }
+
+#define PLATFORM_PCI(Device, Function) \
+  { \
+    { \
+      HARDWARE_DEVICE_PATH, \
+      HW_PCI_DP, \
+      { \
+        (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+        (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    (Function), \
+    (Device) \
+  }
+
+#define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \
+  { \
+    { \
+      { \
+        ACPI_DEVICE_PATH, \
+        ACPI_EXTENDED_DP, \
+        {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \
+      }, \
+      Hid, \
+      Uid, \
+      Cid \
+    }, \
+    HidStr, \
+    UidStr, \
+    CidStr \
+  }
+
+PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath = {
+  PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),
+  PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),
+  PLATFORM_END_ENTIRE
+};
+
+PLATFORM_ACPI_DEVICE_MAPPING  mAcpiDeviceMapping[] = {
+  {
+    (EFI_DEVICE_PATH_PROTOCOL *)&mPlatformI2CDevicePath,
+    0x0,                 // Segment
+    {{0x01, 0x15, 0x00}} // Function, Device, Bus
+  }
+};
+
+PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath = {
+  PLATFORM_PCI_ROOT_BRIDGE,
+  PLATFORM_PCI(0x1C, 1),
+  PLATFORM_PCI(0, 0),
+  PLATFORM_END_ENTIRE
+};
+
+EDKII_PLATFORM_VTD_DEVICE_INFO  mExceptionDeviceList[] = {
+  {
+    0x0,                 // Segment
+    {{0x00, 0x00, 0x02}} // Function, Device, Bus
+  },
+};
+
+/**
+  Compares 2 device path.
+
+  @param[in] DevicePath1  A device path with EndDevicePath node.
+  @param[in] DevicePath2  A device path with EndDevicePath node.
+
+  @retval TRUE   2 device path are identical.
+  @retval FALSE  2 device path are not identical.
+**/
+BOOLEAN
+CompareDevicePath (
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath1,
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath2
+  )
+{
+  UINTN  Size1;
+  UINTN  Size2;
+
+  Size1 = GetDevicePathSize (DevicePath1);
+  Size2 = GetDevicePathSize (DevicePath2);
+  if (Size1 != Size2) {
+    return FALSE;
+  }
+  if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Get the VTD SourceId from the device handler.
+  This function is required for non PCI device handler.
+
+  Pseudo-algo in Intel VTd driver:
+    Status = PlatformGetVTdDeviceId ();
+    if (EFI_ERROR(Status)) {
+      if (DeviceHandle is PCI) {
+        Get SourceId from Bus/Device/Function
+      } else {
+        return EFI_UNSUPPORTED
+      }
+    }
+    Get VTd engine by Segment/Bus/Device/Function.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[in]  DeviceHandle          Device Identifier in UEFI.
+  @param[out] DeviceInfo            DeviceInfo for indentify the VTd engine in ACPI Table
+                                    and the VTd page entry.
+
+  @retval EFI_SUCCESS           The VtdIndex and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
+  @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
+  @retval EFI_NOT_FOUND         The Segment or SourceId information is NOT found.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdGetDeviceId (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  IN  EFI_HANDLE                               DeviceHandle,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           *DeviceInfo
+  )
+{
+  EFI_PCI_IO_PROTOCOL       *PciIo;
+  UINTN                     Seg;
+  UINTN                     Bus;
+  UINTN                     Dev;
+  UINTN                     Func;
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  UINTN                     Index;
+
+  DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetDeviceId\n"));
+
+  if (DeviceInfo == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (DeviceHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Handle PCI device
+  //
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
+  if (!EFI_ERROR(Status)) {
+    Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
+    if (EFI_ERROR(Status)) {
+      return EFI_UNSUPPORTED;
+    }
+    DeviceInfo->Segment = (UINT16)Seg;
+    DeviceInfo->SourceId.Bits.Bus = (UINT8)Bus;
+    DeviceInfo->SourceId.Bits.Device = (UINT8)Dev;
+    DeviceInfo->SourceId.Bits.Function = (UINT8)Func;
+
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Handle ACPI device
+  //
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
+  if (!EFI_ERROR(Status)) {
+    for (Index = 0; Index < ARRAY_SIZE(mAcpiDeviceMapping); Index++) {
+      if (CompareDevicePath (mAcpiDeviceMapping[Index].DevicePath, DevicePath)) {
+        DeviceInfo->Segment = mAcpiDeviceMapping[Index].Segment;
+        DeviceInfo->SourceId = mAcpiDeviceMapping[Index].SourceId;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get a list of handles for the exception devices.
+
+  The VTd driver should always set ALLOW for the device in this list.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[out] DeviceInfoCount       The count of the list of DeviceInfo.
+  @param[out] DeviceInfo            A callee allocated buffer to hold a list of DeviceInfo.
+
+  @retval EFI_SUCCESS           The DeviceInfoCount and DeviceInfo are returned.
+  @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdGetExceptionDeviceList (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  OUT UINTN                                    *DeviceInfoCount,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           **DeviceInfo
+  )
+{
+  DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetExceptionDeviceList\n"));
+
+  if (DeviceInfoCount == NULL || DeviceInfo == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceList));
+  if (*DeviceInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyMem (*DeviceInfo, mExceptionDeviceList, sizeof(mExceptionDeviceList));
+
+  *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceList);
+
+  return EFI_SUCCESS;
+}
+
+EDKII_PLATFORM_VTD_POLICY_PROTOCOL  mPlatformVTdSample = {
+  EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION,
+  PlatformVTdGetDeviceId,
+  PlatformVTdGetExceptionDeviceList,
+};
+
+/**
+  Platform VTd sample driver.
+
+  @param[in]  ImageHandle  ImageHandle of the loaded driver
+  @param[in]  SystemTable  Pointer to the System Table
+
+  @retval  EFI_SUCCESS           The Protocol is installed.
+  @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize driver.
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdSampleInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEdkiiPlatformVTdPolicyProtocolGuid, &mPlatformVTdSample,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
new file mode 100644
index 0000000..9895bc2
--- /dev/null
+++ b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
@@ -0,0 +1,59 @@
+## @file
+# Platform VTd Sample driver.
+#
+# 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.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformVTdSampleDxe
+  MODULE_UNI_FILE                = PlatformVTdSampleDxe.uni
+  FILE_GUID                      = 5DFAE03E-9C19-4996-85BF-65297BD4137F
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PlatformVTdSampleInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#
+
+[Sources]
+  PlatformVTdSampleDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  IoLib
+  PciSegmentLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  DevicePathLib
+
+[Protocols]
+  gEdkiiPlatformVTdPolicyProtocolGuid         ## PRODUCES
+  gEfiPciIoProtocolGuid                       ## CONSUMES
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  PlatformVTdSampleDxeExtra.uni
+
diff --git a/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni
new file mode 100644
index 0000000..231b98d
--- /dev/null
+++ b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni
@@ -0,0 +1,20 @@
+// /** @file
+// PlatformVTdSampleDxe Module Localized Abstract and Description Content
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Platform VTd Sample DXE Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver provides sample on how to produce Platform VTd policy protocol."
+
diff --git a/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni
new file mode 100644
index 0000000..fd29c26
--- /dev/null
+++ b/IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// PlatformVTdSampleDxe Localized Strings and Content
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform VTd Sample DXE Driver"
+
+
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/7] IntelSiliconPkg/dsc: Add PlatformVtd sample driver.
  2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
                   ` (5 preceding siblings ...)
  2017-07-18  7:51 ` [PATCH 6/7] IntelSiliconPkg: Add PlatformVTdSample driver Jiewen Yao
@ 2017-07-18  7:51 ` Jiewen Yao
  6 siblings, 0 replies; 9+ messages in thread
From: Jiewen Yao @ 2017-07-18  7:51 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/IntelSiliconPkg.dsc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/IntelSiliconPkg/IntelSiliconPkg.dsc b/IntelSiliconPkg/IntelSiliconPkg.dsc
index f2625cb..d837d84 100644
--- a/IntelSiliconPkg/IntelSiliconPkg.dsc
+++ b/IntelSiliconPkg/IntelSiliconPkg.dsc
@@ -71,6 +71,7 @@
 [Components]
   IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf
   IntelSiliconPkg/IntelVTdDxe/IntelVTdDxe.inf
+  IntelSiliconPkg/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
 
 [BuildOptions]
   *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol
  2017-07-18  7:51 ` [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol Jiewen Yao
@ 2017-07-26  8:36   ` Zeng, Star
  0 siblings, 0 replies; 9+ messages in thread
From: Zeng, Star @ 2017-07-26  8:36 UTC (permalink / raw)
  To: Yao, Jiewen, edk2-devel@lists.01.org; +Cc: Zeng, Star

How about we update the description for EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST?

+  Get a list of handles for the exception devices.
->
+  Get a list of the exception devices.

With this update, Reviewed-by: Star Zeng <star.zeng@intel.com> to the whole patch series.


Thanks,
Star
-----Original Message-----
From: Yao, Jiewen 
Sent: Tuesday, July 18, 2017 3:52 PM
To: edk2-devel@lists.01.org
Cc: Zeng, Star <star.zeng@intel.com>
Subject: [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol

Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h | 100 ++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h b/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
new file mode 100644
index 0000000..1bd9365
--- /dev/null
+++ b/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
@@ -0,0 +1,100 @@
+/** @file
+  The definition for platform VTD policy.
+
+  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.
+
+**/
+
+#ifndef __PLATFORM_VTD_POLICY_PROTOCOL_H__
+#define __PLATFORM_VTD_POLICY_PROTOCOL_H__
+
+#include <IndustryStandard/Vtd.h>
+
+#define EDKII_PLATFORM_VTD_POLICY_PROTOCOL_GUID \
+    { \
+      0x3d17e448, 0x466, 0x4e20, { 0x99, 0x9f, 0xb2, 0xe1, 0x34, 0x88, 0xee, 0x22 } \
+    }
+
+typedef struct _EDKII_PLATFORM_VTD_POLICY_PROTOCOL  
+EDKII_PLATFORM_VTD_POLICY_PROTOCOL;
+
+#define EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION 0x00010000
+
+typedef struct {
+  UINT16                                   Segment;
+  VTD_SOURCE_ID                            SourceId;
+} EDKII_PLATFORM_VTD_DEVICE_INFO;
+
+/**
+  Get the VTD SourceId from the device handler.
+  This function is required for non PCI device handler.
+
+  Pseudo-algo in Intel VTd driver:
+    Status = PlatformGetVTdDeviceId ();
+    if (EFI_ERROR(Status)) {
+      if (DeviceHandle is PCI) {
+        Get SourceId from Bus/Device/Function
+      } else {
+        return EFI_UNSUPPORTED
+      }
+    }
+    Get VTd engine by Segment/Bus/Device/Function.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[in]  DeviceHandle          Device Identifier in UEFI.
+  @param[out] DeviceInfo            DeviceInfo for indentify the VTd engine in ACPI Table
+                                    and the VTd page entry.
+
+  @retval EFI_SUCCESS           The VtdIndex and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
+  @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
+  @retval EFI_NOT_FOUND         The Segment or SourceId information is NOT found.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_VTD_POLICY_GET_DEVICE_ID) (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  IN  EFI_HANDLE                               DeviceHandle,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           *DeviceInfo
+  );
+
+/**
+  Get a list of handles for the exception devices.
+
+  The VTd driver should always set ALLOW for the device in this list.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[out] DeviceInfoCount       The count of the list of DeviceInfo.
+  @param[out] DeviceInfo            A callee allocated buffer to hold a list of DeviceInfo.
+
+  @retval EFI_SUCCESS           The DeviceInfoCount and DeviceInfo are returned.
+  @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST) (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  OUT UINTN                                    *DeviceInfoCount,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           **DeviceInfo
+  );
+
+struct _EDKII_PLATFORM_VTD_POLICY_PROTOCOL {
+  UINT64                                               Revision;
+  EDKII_PLATFORM_VTD_POLICY_GET_DEVICE_ID              GetDeviceId;
+  EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST  
+GetExceptionDeviceList; };
+
+extern EFI_GUID gEdkiiPlatformVTdPolicyProtocolGuid;
+
+#endif
+
--
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2017-07-26  8:34 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-07-18  7:51 [PATCH 0/7] Add VTd as IOMMU for UEFI Jiewen Yao
2017-07-18  7:51 ` [PATCH 1/7] IntelSiliconPkg/Include: Add VTD industry standard Jiewen Yao
2017-07-18  7:51 ` [PATCH 2/7] IntelSiliconPkg/Include: Add PlatformVtdPolicy Protocol Jiewen Yao
2017-07-26  8:36   ` Zeng, Star
2017-07-18  7:51 ` [PATCH 3/7] IntelSiliconPkg/Dec: Add ProtocolGuid Jiewen Yao
2017-07-18  7:51 ` [PATCH 4/7] IntelSiliconPkg: Add VTd driver Jiewen Yao
2017-07-18  7:51 ` [PATCH 5/7] IntelSiliconPkg/dsc: Add Vtd driver Jiewen Yao
2017-07-18  7:51 ` [PATCH 6/7] IntelSiliconPkg: Add PlatformVTdSample driver Jiewen Yao
2017-07-18  7:51 ` [PATCH 7/7] IntelSiliconPkg/dsc: Add PlatformVtd sample driver Jiewen Yao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox