KVM: arm64: Fix MDCR_EL2.HPMN reset value
The MDCR_EL2 documentation indicates that the HPMN field has the following behaviour: "On a Warm reset, this field resets to the expression NUM_PMU_COUNTERS." However, it appears we reset it to zero, which is not very useful. Add a reset helper for MDCR_EL2, and handle the case where userspace changes the target PMU, which may force us to change HPMN again. Reported-by: Joey Gouly <joey.gouly@arm.com> Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
@@ -1027,12 +1027,30 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
|
||||
return bitmap_weight(arm_pmu->cntr_mask, ARMV8_PMU_MAX_GENERAL_COUNTERS);
|
||||
}
|
||||
|
||||
static void kvm_arm_set_nr_counters(struct kvm *kvm, unsigned int nr)
|
||||
{
|
||||
kvm->arch.nr_pmu_counters = nr;
|
||||
|
||||
/* Reset MDCR_EL2.HPMN behind the vcpus' back... */
|
||||
if (test_bit(KVM_ARM_VCPU_HAS_EL2, kvm->arch.vcpu_features)) {
|
||||
struct kvm_vcpu *vcpu;
|
||||
unsigned long i;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
u64 val = __vcpu_sys_reg(vcpu, MDCR_EL2);
|
||||
val &= ~MDCR_EL2_HPMN;
|
||||
val |= FIELD_PREP(MDCR_EL2_HPMN, kvm->arch.nr_pmu_counters);
|
||||
__vcpu_sys_reg(vcpu, MDCR_EL2) = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
|
||||
{
|
||||
lockdep_assert_held(&kvm->arch.config_lock);
|
||||
|
||||
kvm->arch.arm_pmu = arm_pmu;
|
||||
kvm->arch.nr_pmu_counters = kvm_arm_pmu_get_max_counters(kvm);
|
||||
kvm_arm_set_nr_counters(kvm, kvm_arm_pmu_get_max_counters(kvm));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2698,6 +2698,12 @@ static int set_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
|
||||
.set_user = set_imp_id_reg, \
|
||||
.reset = reset_imp_id_reg, \
|
||||
.val = mask, \
|
||||
}
|
||||
|
||||
static u64 reset_mdcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
|
||||
{
|
||||
__vcpu_sys_reg(vcpu, r->reg) = vcpu->kvm->arch.nr_pmu_counters;
|
||||
return vcpu->kvm->arch.nr_pmu_counters;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3243,7 +3249,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
|
||||
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HCR_EL2, reset_hcr, 0),
|
||||
EL2_REG(MDCR_EL2, access_mdcr, reset_val, 0),
|
||||
EL2_REG(MDCR_EL2, access_mdcr, reset_mdcr, 0),
|
||||
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
|
||||
EL2_REG_VNCR(HSTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0),
|
||||
|
||||
Reference in New Issue
Block a user