Skip to content

Commit 522c68c

Browse files
Sheng Yangavikivity
authored andcommitted
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>
1 parent 4b12f0d commit 522c68c

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

arch/ia64/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ struct kvm_arch {
474474

475475
struct list_head assigned_dev_head;
476476
struct iommu_domain *iommu_domain;
477+
int iommu_flags;
477478
struct hlist_head irq_ack_notifier_list;
478479

479480
unsigned long irq_sources_bitmap;

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ struct kvm_arch{
393393
struct list_head active_mmu_pages;
394394
struct list_head assigned_dev_head;
395395
struct iommu_domain *iommu_domain;
396+
int iommu_flags;
396397
struct kvm_pic *vpic;
397398
struct kvm_ioapic *vioapic;
398399
struct kvm_pit *vpit;

arch/x86/kvm/vmx.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,11 +3581,26 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
35813581
{
35823582
u64 ret;
35833583

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+
*/
35843595
if (is_mmio)
35853596
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;
35863601
else
3587-
ret = (kvm_get_guest_memory_type(vcpu, gfn) <<
3588-
VMX_EPT_MT_EPTE_SHIFT) | VMX_EPT_IGMT_BIT;
3602+
ret = (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT)
3603+
| VMX_EPT_IGMT_BIT;
35893604

35903605
return ret;
35913606
}

include/linux/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
367367
int kvm_request_irq_source_id(struct kvm *kvm);
368368
void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
369369

370+
/* For vcpu->arch.iommu_flags */
371+
#define KVM_IOMMU_CACHE_COHERENCY 0x1
372+
370373
#ifdef CONFIG_IOMMU_API
371374
int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
372375
unsigned long npages);

virt/kvm/iommu.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,16 @@ int kvm_iommu_map_pages(struct kvm *kvm,
3939
pfn_t pfn;
4040
int i, r = 0;
4141
struct iommu_domain *domain = kvm->arch.iommu_domain;
42+
int flags;
4243

4344
/* check if iommu exists and in use */
4445
if (!domain)
4546
return 0;
4647

48+
flags = IOMMU_READ | IOMMU_WRITE;
49+
if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY)
50+
flags |= IOMMU_CACHE;
51+
4752
for (i = 0; i < npages; i++) {
4853
/* check if already mapped */
4954
if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn)))
@@ -53,8 +58,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,
5358
r = iommu_map_range(domain,
5459
gfn_to_gpa(gfn),
5560
pfn_to_hpa(pfn),
56-
PAGE_SIZE,
57-
IOMMU_READ | IOMMU_WRITE);
61+
PAGE_SIZE, flags);
5862
if (r) {
5963
printk(KERN_ERR "kvm_iommu_map_address:"
6064
"iommu failed to map pfn=%lx\n", pfn);
@@ -88,7 +92,7 @@ int kvm_assign_device(struct kvm *kvm,
8892
{
8993
struct pci_dev *pdev = NULL;
9094
struct iommu_domain *domain = kvm->arch.iommu_domain;
91-
int r;
95+
int r, last_flags;
9296

9397
/* check if iommu exists and in use */
9498
if (!domain)
@@ -107,12 +111,29 @@ int kvm_assign_device(struct kvm *kvm,
107111
return r;
108112
}
109113

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+
110128
printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n",
111129
assigned_dev->host_busnr,
112130
PCI_SLOT(assigned_dev->host_devfn),
113131
PCI_FUNC(assigned_dev->host_devfn));
114132

115133
return 0;
134+
out_unmap:
135+
kvm_iommu_unmap_memslots(kvm);
136+
return r;
116137
}
117138

118139
int kvm_deassign_device(struct kvm *kvm,

0 commit comments

Comments
 (0)