aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNadav Amit <namit@cs.technion.ac.il>2014-06-02 11:34:09 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-06-18 11:46:18 -0400
commit67f4d4288c353734d29c45f6725971c71af96791 (patch)
tree6cec4548ccd3e2357512aa028c4ab8f1f61b9ffc
parent3b32004a66e96e17d2a031c08d3304245c506dfc (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.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/emulate.c2
-rw-r--r--arch/x86/kvm/pmu.c9
-rw-r--r--arch/x86/kvm/x86.c7
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);
1070bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr); 1070bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr);
1071int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data); 1071int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
1072int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); 1072int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
1073int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc);
1073int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); 1074int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
1074void kvm_handle_pmu_event(struct kvm_vcpu *vcpu); 1075void kvm_handle_pmu_event(struct kvm_vcpu *vcpu);
1075void kvm_deliver_pmi(struct kvm_vcpu *vcpu); 1076void 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
431int 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
431int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data) 440int 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
4765static 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
4765static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt, 4771static 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,