Skip to content

Commit c8823e5

Browse files
author
Marc Zyngier
committed
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>
1 parent f12b54d commit c8823e5

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

arch/arm64/kvm/pmu-emul.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1027,12 +1027,30 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
10271027
return bitmap_weight(arm_pmu->cntr_mask, ARMV8_PMU_MAX_GENERAL_COUNTERS);
10281028
}
10291029

1030+
static void kvm_arm_set_nr_counters(struct kvm *kvm, unsigned int nr)
1031+
{
1032+
kvm->arch.nr_pmu_counters = nr;
1033+
1034+
/* Reset MDCR_EL2.HPMN behind the vcpus' back... */
1035+
if (test_bit(KVM_ARM_VCPU_HAS_EL2, kvm->arch.vcpu_features)) {
1036+
struct kvm_vcpu *vcpu;
1037+
unsigned long i;
1038+
1039+
kvm_for_each_vcpu(i, vcpu, kvm) {
1040+
u64 val = __vcpu_sys_reg(vcpu, MDCR_EL2);
1041+
val &= ~MDCR_EL2_HPMN;
1042+
val |= FIELD_PREP(MDCR_EL2_HPMN, kvm->arch.nr_pmu_counters);
1043+
__vcpu_sys_reg(vcpu, MDCR_EL2) = val;
1044+
}
1045+
}
1046+
}
1047+
10301048
static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
10311049
{
10321050
lockdep_assert_held(&kvm->arch.config_lock);
10331051

10341052
kvm->arch.arm_pmu = arm_pmu;
1035-
kvm->arch.nr_pmu_counters = kvm_arm_pmu_get_max_counters(kvm);
1053+
kvm_arm_set_nr_counters(kvm, kvm_arm_pmu_get_max_counters(kvm));
10361054
}
10371055

10381056
/**

arch/arm64/kvm/sys_regs.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2698,6 +2698,12 @@ static int set_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
26982698
.set_user = set_imp_id_reg, \
26992699
.reset = reset_imp_id_reg, \
27002700
.val = mask, \
2701+
}
2702+
2703+
static u64 reset_mdcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
2704+
{
2705+
__vcpu_sys_reg(vcpu, r->reg) = vcpu->kvm->arch.nr_pmu_counters;
2706+
return vcpu->kvm->arch.nr_pmu_counters;
27012707
}
27022708

27032709
/*
@@ -3243,7 +3249,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
32433249
EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
32443250
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
32453251
EL2_REG_VNCR(HCR_EL2, reset_hcr, 0),
3246-
EL2_REG(MDCR_EL2, access_mdcr, reset_val, 0),
3252+
EL2_REG(MDCR_EL2, access_mdcr, reset_mdcr, 0),
32473253
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
32483254
EL2_REG_VNCR(HSTR_EL2, reset_val, 0),
32493255
EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0),

0 commit comments

Comments
 (0)