[PATCH v2 10/14] KVM: arm64: PMU: Move the ID_AA64DFR0_EL1.PMUver limit to VM creation

Marc Zyngier maz at kernel.org
Thu Nov 3 01:44:04 PDT 2022


Hi Reiji,

On Thu, 03 Nov 2022 04:55:52 +0000,
Reiji Watanabe <reijiw at google.com> wrote:
> 
> Hi Marc,
> 
> On Fri, Oct 28, 2022 at 4:16 AM Marc Zyngier <maz at kernel.org> wrote:
> >
> >         case SYS_ID_DFR0_EL1:
> > -               /* Limit guests to PMUv3 for ARMv8.4 */
> > -               val = cpuid_feature_cap_perfmon_field(val,
> > -                                                     ID_DFR0_PERFMON_SHIFT,
> > -                                                     kvm_vcpu_has_pmu(vcpu) ? ID_DFR0_PERFMON_8_4 : 0);
> > +               val &= ~ARM64_FEATURE_MASK(ID_DFR0_PERFMON);
> > +               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_DFR0_PERFMON),
> > +                                 pmuver_to_perfmon(vcpu_pmuver(vcpu)));
> 
> Shouldn't KVM expose the sanitized value as it is when AArch32 is
> not supported at EL0 ? Since the register value is UNKNOWN when AArch32
> is not supported at EL0, I would think this code might change the PERFMON
> field value on such systems (could cause live migration to fail).

I'm not sure this would cause anything to fail as we now treat all
AArch32 idregs as RAZ/WI when AArch32 isn't supported (and the
visibility callback still applies here).

But it doesn't hurt to make pmuver_to_perfmon() return 0 when AArch32
isn't supported, and it will at least make the ID register consistent
from a guest perspective.

I plan to squash the following (untested) hack in:

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 8f4412cd4bf6..3b28ef48a525 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1094,6 +1094,10 @@ static u8 perfmon_to_pmuver(u8 perfmon)
 
 static u8 pmuver_to_perfmon(u8 pmuver)
 {
+       /* If no AArch32, make the field RAZ */
+       if (!kvm_supports_32bit_el0())
+               return 0;
+
        switch (pmuver) {
        case ID_AA64DFR0_EL1_PMUVer_IMP:
                return ID_DFR0_PERFMON_8_0;
@@ -1302,10 +1306,9 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
                           const struct sys_reg_desc *rd,
                           u64 val)
 {
-       u8 perfmon, host_perfmon = 0;
+       u8 perfmon, host_perfmon;
 
-       if (system_supports_32bit_el0())
-               host_perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
+       host_perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
 
        /*
         * Allow DFR0_EL1.PerfMon to be set from userspace as long as

> I should have noticed this with the previous version...

No worries, thanks a lot for having had a look!

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.



More information about the linux-arm-kernel mailing list