diff --git a/arch/x86/kvm/vtd.c b/arch/x86/kvm/vtd.c
new file mode 100644
index 0000000..634802c
--- /dev/null
+++ b/arch/x86/kvm/vtd.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Allen M. Kay <allen.m.kay@intel.com>
+ * Author: Weidong Han <weidong.han@intel.com>
+ */
+
+#include <linux/list.h>
+#include <linux/kvm_host.h>
+#include <linux/pci.h>
+#include <linux/dmar.h>
+#include <linux/intel-iommu.h>
+#include "vtd.h"
+
+int kvm_iommu_map_pages(struct kvm *kvm,
+	gfn_t base_gfn, unsigned long npages)
+{
+	gfn_t gfn = base_gfn;
+	pfn_t pfn;
+	struct page *page;
+	int i, rc;
+
+	if (!kvm->arch.domain)
+		return -EFAULT;
+
+	printk(KERN_DEBUG "kvm_iommu_map_page: gpa = %lx\n",
+		gfn << PAGE_SHIFT);
+	printk(KERN_DEBUG "kvm_iommu_map_page: hpa = %lx\n",
+		gfn_to_pfn(kvm, base_gfn) << PAGE_SHIFT);
+	printk(KERN_DEBUG "kvm_iommu_map_page: size = %lx\n",
+		npages*PAGE_SIZE);
+
+	for (i = 0; i < npages; i++) {
+		pfn = gfn_to_pfn(kvm, gfn);
+		if (pfn_valid(pfn)) {
+			rc = kvm_intel_iommu_page_mapping(kvm->arch.domain,
+				gfn << PAGE_SHIFT, pfn << PAGE_SHIFT,
+				PAGE_SIZE, DMA_PTE_READ | DMA_PTE_WRITE);
+			if (rc) {
+				page = gfn_to_page(kvm, gfn);
+				put_page(page);
+			}
+		} else {
+			printk(KERN_DEBUG "kvm_iommu_map_page:"
+				"invalid pfn=%lx\n", pfn);
+			return 0;
+		}
+		gfn++;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_iommu_map_pages);
+
+static int kvm_iommu_map_memslots(struct kvm *kvm)
+{
+	int i, rc;
+	for (i = 0; i < kvm->nmemslots; i++) {
+		rc = kvm_iommu_map_pages(kvm, kvm->memslots[i].base_gfn,
+				kvm->memslots[i].npages);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
+static int kvm_iommu_unmap_memslots(struct kvm *kvm);
+int kvm_iommu_map_guest(struct kvm *kvm,
+	struct kvm_pci_passthrough_dev *pci_pt_dev)
+{
+	struct pci_dev *pdev = NULL;
+
+	printk(KERN_DEBUG "kvm_iommu_map_guest: host bdf = %x:%x:%x\n",
+		pci_pt_dev->host.busnr,
+		PCI_SLOT(pci_pt_dev->host.devfn),
+		PCI_FUNC(pci_pt_dev->host.devfn));
+
+	for_each_pci_dev(pdev) {
+		if ((pdev->bus->number == pci_pt_dev->host.busnr) &&
+			(pdev->devfn == pci_pt_dev->host.devfn))
+			goto found;
+	}
+	if (kvm->arch.domain) {
+		kvm_intel_iommu_domain_exit(kvm->arch.domain);
+		kvm->arch.domain = NULL;
+	}
+	return -ENODEV;
+found:
+	kvm->arch.domain = kvm_intel_iommu_domain_alloc(pdev);
+	if (kvm->arch.domain == NULL)
+		printk(KERN_WARN "kvm_iommu_map_guest: domain == NULL\n");
+	else
+		printk(KERN_INFO "kvm_iommu_map_guest: domain = %p\n",
+			kvm->arch.domain);
+	if (kvm_iommu_map_memslots(kvm)) {
+		kvm_iommu_unmap_memslots(kvm);
+		return -EFAULT;
+	}
+	kvm_intel_iommu_context_mapping(kvm->arch.domain, pdev);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_iommu_map_guest);
+
+static int kvm_iommu_put_pages(struct kvm *kvm,
+	gfn_t base_gfn, unsigned long npages)
+{
+	gfn_t gfn = base_gfn;
+	struct page *page;
+	int i;
+
+	if (!kvm->arch.domain)
+		return -EFAULT;
+
+	printk(KERN_DEBUG "kvm_iommu_put_pages: gpa = %lx\n",
+		gfn << PAGE_SHIFT);
+	printk(KERN_DEBUG "kvm_iommu_put_pages: hpa = %lx\n",
+		gfn_to_pfn(kvm, gfn) << PAGE_SHIFT);
+	printk(KERN_DEBUG "kvm_iommu_put_pages: size = %lx\n",
+		npages*PAGE_SIZE);
+
+	for (i = 0; i < npages; i++) {
+		page = gfn_to_page(kvm, gfn);
+		put_page(page);
+		gfn++;
+	}
+	return 0;
+}
+
+static int kvm_iommu_unmap_memslots(struct kvm *kvm)
+{
+	int i, rc;
+	for (i = 0; i < kvm->nmemslots; i++) {
+		rc = kvm_iommu_put_pages(kvm, kvm->memslots[i].base_gfn,
+				kvm->memslots[i].npages);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
+int kvm_iommu_unmap_guest(struct kvm *kvm)
+{
+	struct dmar_domain *domain;
+	struct kvm_pci_pt_dev_list *entry;
+	struct pci_dev *pdev = NULL;
+
+	if (kvm->arch.domain)
+		return 0;
+
+	list_for_each_entry(entry, &kvm->arch.pci_pt_dev_head, list) {
+		printk(KERN_DEBUG "kvm_iommu_unmap_guest: %x:%x:%x\n",
+			entry->pt_dev.host.busnr,
+			PCI_SLOT(entry->pt_dev.host.devfn),
+			PCI_FUNC(entry->pt_dev.host.devfn));
+
+		for_each_pci_dev(pdev) {
+			if ((pdev->bus->number == entry->pt_dev.host.busnr) &&
+				(pdev->devfn == entry->pt_dev.host.devfn))
+				goto found;
+		}
+		return -ENODEV;
+found:
+		if (pdev == NULL) {
+			printk(KERN_ERR "kvm_iommu_unmap_guest:pdev == NULL\n");
+			return -EFAULT;
+		}
+
+		/* detach kvm dmar domain */
+		kvm_intel_iommu_detach_dev(kvm->arch.domain,
+				pdev->bus->number, pdev->devfn);
+
+		/* now restore back linux iommu domain */
+		domain = kvm_intel_iommu_find_domain(pdev);
+		if (domain)
+			kvm_intel_iommu_context_mapping(domain, pdev);
+		else
+			printk(KERN_DEBUG
+				"kvm_iommu_unmap_guest: domain == NULL\n");
+	}
+	kvm_iommu_unmap_memslots(kvm);
+	kvm_intel_iommu_domain_exit(kvm->arch.domain);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_iommu_unmap_guest);
diff --git a/arch/x86/kvm/vtd.h b/arch/x86/kvm/vtd.h
new file mode 100644
index 0000000..d03c15c
--- /dev/null
+++ b/arch/x86/kvm/vtd.h
@@ -0,0 +1,36 @@
+#ifndef __VTD_H
+#define __VTD_H
+
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Allen M. Kay <allen.m.kay@intel.com>
+ * Author: Weidong Han <weidong.han@intel.com>
+ */
+
+#define DEBUG
+
+int kvm_intel_iommu_context_mapping(struct dmar_domain *d,
+			struct pci_dev *pdev);
+int kvm_intel_iommu_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
+			u64 hpa, size_t size, int prot);
+void kvm_intel_iommu_detach_dev(struct dmar_domain *domain, u8 bus, u8 devfn);
+struct dmar_domain *kvm_intel_iommu_domain_alloc(struct pci_dev *pdev);
+void kvm_intel_iommu_domain_exit(struct dmar_domain *domain);
+struct dmar_domain *kvm_intel_iommu_find_domain(struct pci_dev *pdev);
+
+#endif
