aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSheng Yang <sheng@linux.intel.com>2009-04-27 08:35:43 -0400
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:50 -0400
commit522c68c4416de3cd3e11a9ff10d58e776a69ae1e (patch)
tree62940e35988f5e2a52df10276882ec64518ee369
parent4b12f0de33a64dfc624b2480f55b674f7fa23ef2 (diff)
KVM: Enable snooping control for supported hardware
Memory aliases with different memory type is a problem for guest. For the guest without assigned device, the memory type of guest memory would always been the same as host(WB); but for the assigned device, some part of memory may be used as DMA and then set to uncacheable memory type(UC/WC), which would be a conflict of host memory type then be a potential issue. Snooping control can guarantee the cache correctness of memory go through the DMA engine of VT-d. [avi: fix build on ia64] Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/ia64/include/asm/kvm_host.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/vmx.c19
-rw-r--r--include/linux/kvm_host.h3
-rw-r--r--virt/kvm/iommu.c27
5 files changed, 46 insertions, 5 deletions
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 589536fa799d..5f43697aed30 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -474,6 +474,7 @@ struct kvm_arch {
474 474
475 struct list_head assigned_dev_head; 475 struct list_head assigned_dev_head;
476 struct iommu_domain *iommu_domain; 476 struct iommu_domain *iommu_domain;
477 int iommu_flags;
477 struct hlist_head irq_ack_notifier_list; 478 struct hlist_head irq_ack_notifier_list;
478 479
479 unsigned long irq_sources_bitmap; 480 unsigned long irq_sources_bitmap;
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 8a6f6b643dfe..253d8f669cf6 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -393,6 +393,7 @@ struct kvm_arch{
393 struct list_head active_mmu_pages; 393 struct list_head active_mmu_pages;
394 struct list_head assigned_dev_head; 394 struct list_head assigned_dev_head;
395 struct iommu_domain *iommu_domain; 395 struct iommu_domain *iommu_domain;
396 int iommu_flags;
396 struct kvm_pic *vpic; 397 struct kvm_pic *vpic;
397 struct kvm_ioapic *vioapic; 398 struct kvm_ioapic *vioapic;
398 struct kvm_pit *vpit; 399 struct kvm_pit *vpit;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 59b080c262e8..e8a5649f9c15 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3581,11 +3581,26 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
3581{ 3581{
3582 u64 ret; 3582 u64 ret;
3583 3583
3584 /* For VT-d and EPT combination
3585 * 1. MMIO: always map as UC
3586 * 2. EPT with VT-d:
3587 * a. VT-d without snooping control feature: can't guarantee the
3588 * result, try to trust guest.
3589 * b. VT-d with snooping control feature: snooping control feature of
3590 * VT-d engine can guarantee the cache correctness. Just set it
3591 * to WB to keep consistent with host. So the same as item 3.
3592 * 3. EPT without VT-d: always map as WB and set IGMT=1 to keep
3593 * consistent with host MTRR
3594 */
3584 if (is_mmio) 3595 if (is_mmio)
3585 ret = MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT; 3596 ret = MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT;
3597 else if (vcpu->kvm->arch.iommu_domain &&
3598 !(vcpu->kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY))
3599 ret = kvm_get_guest_memory_type(vcpu, gfn) <<
3600 VMX_EPT_MT_EPTE_SHIFT;
3586 else 3601 else
3587 ret = (kvm_get_guest_memory_type(vcpu, gfn) << 3602 ret = (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT)
3588 VMX_EPT_MT_EPTE_SHIFT) | VMX_EPT_IGMT_BIT; 3603 | VMX_EPT_IGMT_BIT;
3589 3604
3590 return ret; 3605 return ret;
3591} 3606}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 72d56844f388..bdce8e1303c9 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -367,6 +367,9 @@ void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
367int kvm_request_irq_source_id(struct kvm *kvm); 367int kvm_request_irq_source_id(struct kvm *kvm);
368void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id); 368void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
369 369
370/* For vcpu->arch.iommu_flags */
371#define KVM_IOMMU_CACHE_COHERENCY 0x1
372
370#ifdef CONFIG_IOMMU_API 373#ifdef CONFIG_IOMMU_API
371int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn, 374int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
372 unsigned long npages); 375 unsigned long npages);
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index 4c4037503600..15147583abd1 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -39,11 +39,16 @@ int kvm_iommu_map_pages(struct kvm *kvm,
39 pfn_t pfn; 39 pfn_t pfn;
40 int i, r = 0; 40 int i, r = 0;
41 struct iommu_domain *domain = kvm->arch.iommu_domain; 41 struct iommu_domain *domain = kvm->arch.iommu_domain;
42 int flags;
42 43
43 /* check if iommu exists and in use */ 44 /* check if iommu exists and in use */
44 if (!domain) 45 if (!domain)
45 return 0; 46 return 0;
46 47
48 flags = IOMMU_READ | IOMMU_WRITE;
49 if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY)
50 flags |= IOMMU_CACHE;
51
47 for (i = 0; i < npages; i++) { 52 for (i = 0; i < npages; i++) {
48 /* check if already mapped */ 53 /* check if already mapped */
49 if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) 54 if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn)))
@@ -53,8 +58,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,
53 r = iommu_map_range(domain, 58 r = iommu_map_range(domain,
54 gfn_to_gpa(gfn), 59 gfn_to_gpa(gfn),
55 pfn_to_hpa(pfn), 60 pfn_to_hpa(pfn),
56 PAGE_SIZE, 61 PAGE_SIZE, flags);
57 IOMMU_READ | IOMMU_WRITE);
58 if (r) { 62 if (r) {
59 printk(KERN_ERR "kvm_iommu_map_address:" 63 printk(KERN_ERR "kvm_iommu_map_address:"
60 "iommu failed to map pfn=%lx\n", pfn); 64 "iommu failed to map pfn=%lx\n", pfn);
@@ -88,7 +92,7 @@ int kvm_assign_device(struct kvm *kvm,
88{ 92{
89 struct pci_dev *pdev = NULL; 93 struct pci_dev *pdev = NULL;
90 struct iommu_domain *domain = kvm->arch.iommu_domain; 94 struct iommu_domain *domain = kvm->arch.iommu_domain;
91 int r; 95 int r, last_flags;
92 96
93 /* check if iommu exists and in use */ 97 /* check if iommu exists and in use */
94 if (!domain) 98 if (!domain)
@@ -107,12 +111,29 @@ int kvm_assign_device(struct kvm *kvm,
107 return r; 111 return r;
108 } 112 }
109 113
114 last_flags = kvm->arch.iommu_flags;
115 if (iommu_domain_has_cap(kvm->arch.iommu_domain,
116 IOMMU_CAP_CACHE_COHERENCY))
117 kvm->arch.iommu_flags |= KVM_IOMMU_CACHE_COHERENCY;
118
119 /* Check if need to update IOMMU page table for guest memory */
120 if ((last_flags ^ kvm->arch.iommu_flags) ==
121 KVM_IOMMU_CACHE_COHERENCY) {
122 kvm_iommu_unmap_memslots(kvm);
123 r = kvm_iommu_map_memslots(kvm);
124 if (r)
125 goto out_unmap;
126 }
127
110 printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n", 128 printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n",
111 assigned_dev->host_busnr, 129 assigned_dev->host_busnr,
112 PCI_SLOT(assigned_dev->host_devfn), 130 PCI_SLOT(assigned_dev->host_devfn),
113 PCI_FUNC(assigned_dev->host_devfn)); 131 PCI_FUNC(assigned_dev->host_devfn));
114 132
115 return 0; 133 return 0;
134out_unmap:
135 kvm_iommu_unmap_memslots(kvm);
136 return r;
116} 137}
117 138
118int kvm_deassign_device(struct kvm *kvm, 139int kvm_deassign_device(struct kvm *kvm,