]>
Commit | Line | Data |
---|---|---|
2b10ecdc AD |
1 | From fa7c4ebd5ae0c22f9908436303106a9ffcf0cf42 Mon Sep 17 00:00:00 2001 |
2 | From: Paolo Bonzini <pbonzini@redhat.com> | |
3 | Date: Mon, 14 Dec 2015 16:57:31 +0100 | |
4 | Subject: KVM: MTRR: observe maxphyaddr from guest CPUID, not host | |
5 | ||
6 | Conversion of MTRRs to ranges used the maxphyaddr from the boot CPU. | |
7 | This is wrong, because var_mtrr_range's mask variable then is discontiguous | |
8 | (like FF00FFFF000, where the first run of 0s corresponds to the bits | |
9 | between host and guest maxphyaddr). Instead always set up the masks | |
10 | to be full 64-bit values---we know that the reserved bits at the top | |
11 | are zero, and we can restore them when reading the MSR. This way | |
12 | var_mtrr_range gets a mask that just works. | |
13 | ||
14 | Fixes: a13842dc668b40daef4327294a6d3bdc8bd30276 | |
15 | Cc: qemu-stable@nongnu.org | |
16 | Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=107561 | |
17 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
18 | --- | |
19 | arch/x86/kvm/mtrr.c | 9 +++++++-- | |
20 | 1 file changed, 7 insertions(+), 2 deletions(-) | |
21 | ||
22 | diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c | |
23 | index adc54e1..7747b6d 100644 | |
24 | --- a/arch/x86/kvm/mtrr.c | |
25 | +++ b/arch/x86/kvm/mtrr.c | |
26 | @@ -300,7 +300,6 @@ static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end) | |
27 | *start = range->base & PAGE_MASK; | |
28 | ||
29 | mask = range->mask & PAGE_MASK; | |
30 | - mask |= ~0ULL << boot_cpu_data.x86_phys_bits; | |
31 | ||
32 | /* This cannot overflow because writing to the reserved bits of | |
33 | * variable MTRRs causes a #GP. | |
34 | @@ -356,10 +355,14 @@ static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data) | |
35 | if (var_mtrr_range_is_valid(cur)) | |
36 | list_del(&mtrr_state->var_ranges[index].node); | |
37 | ||
38 | + /* Extend the mask with all 1 bits to the left, since those | |
39 | + * bits must implicitly be 0. The bits are then cleared | |
40 | + * when reading them. | |
41 | + */ | |
42 | if (!is_mtrr_mask) | |
43 | cur->base = data; | |
44 | else | |
45 | - cur->mask = data; | |
46 | + cur->mask = data | (-1LL << cpuid_maxphyaddr(vcpu)); | |
47 | ||
48 | /* add it to the list if it's enabled. */ | |
49 | if (var_mtrr_range_is_valid(cur)) { | |
50 | @@ -426,6 +429,8 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) | |
51 | *pdata = vcpu->arch.mtrr_state.var_ranges[index].base; | |
52 | else | |
53 | *pdata = vcpu->arch.mtrr_state.var_ranges[index].mask; | |
54 | + | |
55 | + *pdata &= (1ULL << cpuid_maxphyaddr(vcpu)) - 1; | |
56 | } | |
57 | ||
58 | return 0; | |
59 | -- | |
60 | cgit v0.11.2 | |
61 |