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>
This commit is contained in:
parent
3b32004a66
commit
67f4d4288c
5 changed files with 19 additions and 1 deletions
|
@ -194,6 +194,7 @@ struct x86_emulate_ops {
|
|||
int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
|
||||
int (*set_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data);
|
||||
int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata);
|
||||
int (*check_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc);
|
||||
int (*read_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc, u64 *pdata);
|
||||
void (*halt)(struct x86_emulate_ctxt *ctxt);
|
||||
void (*wbinvd)(struct x86_emulate_ctxt *ctxt);
|
||||
|
|
|
@ -1070,6 +1070,7 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu);
|
|||
bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr);
|
||||
int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
|
||||
int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
|
||||
int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc);
|
||||
int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
|
||||
void kvm_handle_pmu_event(struct kvm_vcpu *vcpu);
|
||||
void kvm_deliver_pmi(struct kvm_vcpu *vcpu);
|
||||
|
|
|
@ -3507,7 +3507,7 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt)
|
|||
u64 rcx = reg_read(ctxt, VCPU_REGS_RCX);
|
||||
|
||||
if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) ||
|
||||
(rcx > 3))
|
||||
ctxt->ops->check_pmc(ctxt, rcx))
|
||||
return emulate_gp(ctxt, 0);
|
||||
|
||||
return X86EMUL_CONTINUE;
|
||||
|
|
|
@ -428,6 +428,15 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc)
|
||||
{
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
bool fixed = pmc & (1u << 30);
|
||||
pmc &= ~(3u << 30);
|
||||
return (!fixed && pmc >= pmu->nr_arch_gp_counters) ||
|
||||
(fixed && pmc >= pmu->nr_arch_fixed_counters);
|
||||
}
|
||||
|
||||
int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data)
|
||||
{
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
|
|
|
@ -4762,6 +4762,12 @@ static int emulator_set_msr(struct x86_emulate_ctxt *ctxt,
|
|||
return kvm_set_msr(emul_to_vcpu(ctxt), &msr);
|
||||
}
|
||||
|
||||
static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt,
|
||||
u32 pmc)
|
||||
{
|
||||
return kvm_pmu_check_pmc(emul_to_vcpu(ctxt), pmc);
|
||||
}
|
||||
|
||||
static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt,
|
||||
u32 pmc, u64 *pdata)
|
||||
{
|
||||
|
@ -4838,6 +4844,7 @@ static const struct x86_emulate_ops emulate_ops = {
|
|||
.set_dr = emulator_set_dr,
|
||||
.set_msr = emulator_set_msr,
|
||||
.get_msr = emulator_get_msr,
|
||||
.check_pmc = emulator_check_pmc,
|
||||
.read_pmc = emulator_read_pmc,
|
||||
.halt = emulator_halt,
|
||||
.wbinvd = emulator_wbinvd,
|
||||
|
|
Loading…
Reference in a new issue