Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67f4d428 authored by Nadav Amit's avatar Nadav Amit Committed by Paolo Bonzini
Browse files

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: default avatarNadav Amit <namit@cs.technion.ac.il>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 3b32004a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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;
+9 −0
Original line number Diff line number Diff line
@@ -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;
+7 −0
Original line number Diff line number Diff line
@@ -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,