[pve-devel] [PATCH] kvm mttr fixes (pci passthrough)
Alexandre Derumier
aderumier at odiso.com
Wed Dec 30 09:58:05 CET 2015
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
0001-mttr.patch | 34 +++++++++++++++++++++++++
0002-mttr.patch | 61 ++++++++++++++++++++++++++++++++++++++++++++
0003-mttr.patch | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Makefile | 5 ++++
4 files changed, 178 insertions(+)
create mode 100644 0001-mttr.patch
create mode 100644 0002-mttr.patch
create mode 100644 0003-mttr.patch
diff --git a/0001-mttr.patch b/0001-mttr.patch
new file mode 100644
index 0000000..6ffbe38
--- /dev/null
+++ b/0001-mttr.patch
@@ -0,0 +1,34 @@
+From a7f2d7865720ff13d5b0f2a3bb1fd80dc3d7a73f Mon Sep 17 00:00:00 2001
+From: Alexis Dambricourt <alexis.dambricourt at gmail.com>
+Date: Mon, 14 Dec 2015 15:39:34 +0100
+Subject: KVM: MTRR: fix fixed MTRR segment look up
+
+This fixes the slow-down of VM running with pci-passthrough, since some MTRR
+range changed from MTRR_TYPE_WRBACK to MTRR_TYPE_UNCACHABLE. Memory in the
+0K-640K range was incorrectly treated as uncacheable.
+
+Fixes: f7bfb57b3e89ff89c0da9f93dedab89f68d6ca27
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=107561
+Cc: qemu-stable at nongnu.org
+Signed-off-by: Alexis Dambricourt <alexis.dambricourt at gmail.com>
+[Use correct BZ for "Fixes" annotation. - Paolo]
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ arch/x86/kvm/mtrr.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
+index 9e8bf13..adc54e1 100644
+--- a/arch/x86/kvm/mtrr.c
++++ b/arch/x86/kvm/mtrr.c
+@@ -267,7 +267,7 @@ static int fixed_mtrr_addr_to_seg(u64 addr)
+
+ for (seg = 0; seg < seg_num; seg++) {
+ mtrr_seg = &fixed_seg_table[seg];
+- if (mtrr_seg->start >= addr && addr < mtrr_seg->end)
++ if (mtrr_seg->start <= addr && addr < mtrr_seg->end)
+ return seg;
+ }
+
+--
+cgit v0.11.2
diff --git a/0002-mttr.patch b/0002-mttr.patch
new file mode 100644
index 0000000..fe1c420
--- /dev/null
+++ b/0002-mttr.patch
@@ -0,0 +1,61 @@
+From fa7c4ebd5ae0c22f9908436303106a9ffcf0cf42 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Mon, 14 Dec 2015 16:57:31 +0100
+Subject: KVM: MTRR: observe maxphyaddr from guest CPUID, not host
+
+Conversion of MTRRs to ranges used the maxphyaddr from the boot CPU.
+This is wrong, because var_mtrr_range's mask variable then is discontiguous
+(like FF00FFFF000, where the first run of 0s corresponds to the bits
+between host and guest maxphyaddr). Instead always set up the masks
+to be full 64-bit values---we know that the reserved bits at the top
+are zero, and we can restore them when reading the MSR. This way
+var_mtrr_range gets a mask that just works.
+
+Fixes: a13842dc668b40daef4327294a6d3bdc8bd30276
+Cc: qemu-stable at nongnu.org
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=107561
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ arch/x86/kvm/mtrr.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
+index adc54e1..7747b6d 100644
+--- a/arch/x86/kvm/mtrr.c
++++ b/arch/x86/kvm/mtrr.c
+@@ -300,7 +300,6 @@ static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end)
+ *start = range->base & PAGE_MASK;
+
+ mask = range->mask & PAGE_MASK;
+- mask |= ~0ULL << boot_cpu_data.x86_phys_bits;
+
+ /* This cannot overflow because writing to the reserved bits of
+ * variable MTRRs causes a #GP.
+@@ -356,10 +355,14 @@ static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+ if (var_mtrr_range_is_valid(cur))
+ list_del(&mtrr_state->var_ranges[index].node);
+
++ /* Extend the mask with all 1 bits to the left, since those
++ * bits must implicitly be 0. The bits are then cleared
++ * when reading them.
++ */
+ if (!is_mtrr_mask)
+ cur->base = data;
+ else
+- cur->mask = data;
++ cur->mask = data | (-1LL << cpuid_maxphyaddr(vcpu));
+
+ /* add it to the list if it's enabled. */
+ if (var_mtrr_range_is_valid(cur)) {
+@@ -426,6 +429,8 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+ *pdata = vcpu->arch.mtrr_state.var_ranges[index].base;
+ else
+ *pdata = vcpu->arch.mtrr_state.var_ranges[index].mask;
++
++ *pdata &= (1ULL << cpuid_maxphyaddr(vcpu)) - 1;
+ }
+
+ return 0;
+--
+cgit v0.11.2
+
diff --git a/0003-mttr.patch b/0003-mttr.patch
new file mode 100644
index 0000000..61606e4
--- /dev/null
+++ b/0003-mttr.patch
@@ -0,0 +1,78 @@
+From e24dea2afc6a0852983dc741072d8e96155e13f5 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Tue, 22 Dec 2015 15:20:00 +0100
+Subject: KVM: MTRR: treat memory as writeback if MTRR is disabled in guest
+ CPUID
+
+Virtual machines can be run with CPUID such that there are no MTRRs.
+In that case, the firmware will never enable MTRRs and it is obviously
+undesirable to run the guest entirely with UC memory. Check out guest
+CPUID, and use WB memory if MTRR do not exist.
+
+Cc: qemu-stable at nongnu.org
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=107561
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ arch/x86/kvm/cpuid.h | 8 ++++++++
+ arch/x86/kvm/mtrr.c | 14 +++++++++++---
+ 2 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
+index 06332cb..3f5c48d 100644
+--- a/arch/x86/kvm/cpuid.h
++++ b/arch/x86/kvm/cpuid.h
+@@ -38,6 +38,14 @@ static inline bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
+ return best && (best->ecx & bit(X86_FEATURE_XSAVE));
+ }
+
++static inline bool guest_cpuid_has_mtrr(struct kvm_vcpu *vcpu)
++{
++ struct kvm_cpuid_entry2 *best;
++
++ best = kvm_find_cpuid_entry(vcpu, 1, 0);
++ return best && (best->edx & bit(X86_FEATURE_MTRR));
++}
++
+ static inline bool guest_cpuid_has_tsc_adjust(struct kvm_vcpu *vcpu)
+ {
+ struct kvm_cpuid_entry2 *best;
+diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
+index 7747b6d..3f8c732 100644
+--- a/arch/x86/kvm/mtrr.c
++++ b/arch/x86/kvm/mtrr.c
+@@ -120,14 +120,22 @@ static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
+ return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
+ }
+
+-static u8 mtrr_disabled_type(void)
++static u8 mtrr_disabled_type(struct kvm_vcpu *vcpu)
+ {
+ /*
+ * Intel SDM 11.11.2.2: all MTRRs are disabled when
+ * IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC
+ * memory type is applied to all of physical memory.
++ *
++ * However, virtual machines can be run with CPUID such that
++ * there are no MTRRs. In that case, the firmware will never
++ * enable MTRRs and it is obviously undesirable to run the
++ * guest entirely with UC memory and we use WB.
+ */
+- return MTRR_TYPE_UNCACHABLE;
++ if (guest_cpuid_has_mtrr(vcpu))
++ return MTRR_TYPE_UNCACHABLE;
++ else
++ return MTRR_TYPE_WRBACK;
+ }
+
+ /*
+@@ -675,7 +683,7 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
+ }
+
+ if (iter.mtrr_disabled)
+- return mtrr_disabled_type();
++ return mtrr_disabled_type(vcpu);
+
+ /* not contained in any MTRRs. */
+ if (type == -1)
+--
+cgit v0.11.2
diff --git a/Makefile b/Makefile
index ce86bc2..ca3c00a 100644
--- a/Makefile
+++ b/Makefile
@@ -249,6 +249,11 @@ ${KERNEL_SRC}/README ${KERNEL_CFG_ORG}: ${KERNELSRCTAR}
cd ${KERNEL_SRC}; patch -p1 <../0007-aacraid-ioctl-fix.patch
cd ${KERNEL_SRC}; patch -p1 <../0008-aacraid-use-pci-enable-msix-range.patch
cd ${KERNEL_SRC}; patch -p1 <../0009-aacraid-update-driver-version.patch
+ # backport MTTR kvm fixed (pci passthrough bug) from kernel 4.4rc7
+ cd ${KERNEL_SRC}; patch -p1 <../0001-mttr.patch
+ cd ${KERNEL_SRC}; patch -p1 <../0002-mttr.patch
+ cd ${KERNEL_SRC}; patch -p1 <../0003-mttr.patch
+
sed -i ${KERNEL_SRC}/Makefile -e 's/^EXTRAVERSION.*$$/EXTRAVERSION=${EXTRAVERSION}/'
touch $@
--
2.1.4
More information about the pve-devel
mailing list