diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2014-06-02 11:34:09 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-06-18 11:46:18 -0400 |
commit | 67f4d4288c353734d29c45f6725971c71af96791 (patch) | |
tree | 6cec4548ccd3e2357512aa028c4ab8f1f61b9ffc | |
parent | 3b32004a66e96e17d2a031c08d3304245c506dfc (diff) |
KVM: x86: rdpmc emulation checks the counter incorrectly
The rdpmc emulation checks that the counter (ECX) is not higher than 2, without
taking into considerations bits 30:31 role (e.g., bit 30 marks whether the
counter is fixed). The fix uses the pmu information for checking the validity
of the pmu counter.
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 2 | ||||
-rw-r--r-- | arch/x86/kvm/pmu.c | 9 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 7 |
5 files changed, 19 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index a04fe4eb237d..ffa2671a7f2f 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -194,6 +194,7 @@ struct x86_emulate_ops { | |||
194 | int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value); | 194 | int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value); |
195 | int (*set_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data); | 195 | int (*set_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data); |
196 | int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); | 196 | int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata); |
197 | int (*check_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc); | ||
197 | int (*read_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc, u64 *pdata); | 198 | int (*read_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc, u64 *pdata); |
198 | void (*halt)(struct x86_emulate_ctxt *ctxt); | 199 | void (*halt)(struct x86_emulate_ctxt *ctxt); |
199 | void (*wbinvd)(struct x86_emulate_ctxt *ctxt); | 200 | void (*wbinvd)(struct x86_emulate_ctxt *ctxt); |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 49314155b66c..63e020be3da7 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -1070,6 +1070,7 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu); | |||
1070 | bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr); | 1070 | bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr); |
1071 | int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data); | 1071 | int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data); |
1072 | int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); | 1072 | int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); |
1073 | int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc); | ||
1073 | int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); | 1074 | int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); |
1074 | void kvm_handle_pmu_event(struct kvm_vcpu *vcpu); | 1075 | void kvm_handle_pmu_event(struct kvm_vcpu *vcpu); |
1075 | void kvm_deliver_pmi(struct kvm_vcpu *vcpu); | 1076 | void kvm_deliver_pmi(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index be3f7645e39d..3da8d82acb31 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -3507,7 +3507,7 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt) | |||
3507 | u64 rcx = reg_read(ctxt, VCPU_REGS_RCX); | 3507 | u64 rcx = reg_read(ctxt, VCPU_REGS_RCX); |
3508 | 3508 | ||
3509 | if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || | 3509 | if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || |
3510 | (rcx > 3)) | 3510 | ctxt->ops->check_pmc(ctxt, rcx)) |
3511 | return emulate_gp(ctxt, 0); | 3511 | return emulate_gp(ctxt, 0); |
3512 | 3512 | ||
3513 | return X86EMUL_CONTINUE; | 3513 | return X86EMUL_CONTINUE; |
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index cbecaa90399c..3dd6accb64ec 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c | |||
@@ -428,6 +428,15 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) | |||
428 | return 1; | 428 | return 1; |
429 | } | 429 | } |
430 | 430 | ||
431 | int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc) | ||
432 | { | ||
433 | struct kvm_pmu *pmu = &vcpu->arch.pmu; | ||
434 | bool fixed = pmc & (1u << 30); | ||
435 | pmc &= ~(3u << 30); | ||
436 | return (!fixed && pmc >= pmu->nr_arch_gp_counters) || | ||
437 | (fixed && pmc >= pmu->nr_arch_fixed_counters); | ||
438 | } | ||
439 | |||
431 | int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data) | 440 | int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data) |
432 | { | 441 | { |
433 | struct kvm_pmu *pmu = &vcpu->arch.pmu; | 442 | struct kvm_pmu *pmu = &vcpu->arch.pmu; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f32a02578c0d..451d6acea808 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4762,6 +4762,12 @@ static int emulator_set_msr(struct x86_emulate_ctxt *ctxt, | |||
4762 | return kvm_set_msr(emul_to_vcpu(ctxt), &msr); | 4762 | return kvm_set_msr(emul_to_vcpu(ctxt), &msr); |
4763 | } | 4763 | } |
4764 | 4764 | ||
4765 | static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt, | ||
4766 | u32 pmc) | ||
4767 | { | ||
4768 | return kvm_pmu_check_pmc(emul_to_vcpu(ctxt), pmc); | ||
4769 | } | ||
4770 | |||
4765 | static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt, | 4771 | static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt, |
4766 | u32 pmc, u64 *pdata) | 4772 | u32 pmc, u64 *pdata) |
4767 | { | 4773 | { |
@@ -4838,6 +4844,7 @@ static const struct x86_emulate_ops emulate_ops = { | |||
4838 | .set_dr = emulator_set_dr, | 4844 | .set_dr = emulator_set_dr, |
4839 | .set_msr = emulator_set_msr, | 4845 | .set_msr = emulator_set_msr, |
4840 | .get_msr = emulator_get_msr, | 4846 | .get_msr = emulator_get_msr, |
4847 | .check_pmc = emulator_check_pmc, | ||
4841 | .read_pmc = emulator_read_pmc, | 4848 | .read_pmc = emulator_read_pmc, |
4842 | .halt = emulator_halt, | 4849 | .halt = emulator_halt, |
4843 | .wbinvd = emulator_wbinvd, | 4850 | .wbinvd = emulator_wbinvd, |