[PATCH v1 4/6] KVM: arm64: Use per guest ID register for ID_AA64DFR0_EL1.PMUVer
Jing Zhang
jingzhangos at google.com
Thu Feb 9 13:25:30 PST 2023
On Mon, Feb 6, 2023 at 9:30 PM Reiji Watanabe <reijiw at google.com> wrote:
>
> Hi Jing,
>
> On Tue, Jan 31, 2023 at 6:51 PM Jing Zhang <jingzhangos at google.com> wrote:
> >
> > With per guest ID registers, PMUver settings from userspace
> > can be stored in its corresponding ID register.
> >
> > No functional change intended.
> >
> > Signed-off-by: Jing Zhang <jingzhangos at google.com>
> > ---
> > arch/arm64/include/asm/kvm_host.h | 5 -----
> > arch/arm64/kvm/arm.c | 6 ------
> > arch/arm64/kvm/id_regs.c | 33 ++++++++++++++++++++-----------
> > include/kvm/arm_pmu.h | 6 ++++--
> > 4 files changed, 25 insertions(+), 25 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index fabb30185a4a..1ab443b52c46 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -225,11 +225,6 @@ struct kvm_arch {
> >
> > cpumask_var_t supported_cpus;
> >
> > - struct {
> > - u8 imp:4;
> > - u8 unimp:4;
> > - } dfr0_pmuver;
> > -
> > /* Hypercall features firmware registers' descriptor */
> > struct kvm_smccc_features smccc_feat;
> >
> > diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> > index d8ba5106bf51..25bd95650223 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -138,12 +138,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> > kvm_arm_set_default_id_regs(kvm);
> > kvm_arm_init_hypercalls(kvm);
> >
> > - /*
> > - * Initialise the default PMUver before there is a chance to
> > - * create an actual PMU.
> > - */
> > - kvm->arch.dfr0_pmuver.imp = kvm_arm_pmu_get_pmuver_limit();
> > -
> > return 0;
> >
> > err_free_cpumask:
> > diff --git a/arch/arm64/kvm/id_regs.c b/arch/arm64/kvm/id_regs.c
> > index bc5d9bc84eb1..5eade7d380af 100644
> > --- a/arch/arm64/kvm/id_regs.c
> > +++ b/arch/arm64/kvm/id_regs.c
> > @@ -19,10 +19,12 @@
> >
> > static u8 vcpu_pmuver(const struct kvm_vcpu *vcpu)
> > {
> > - if (kvm_vcpu_has_pmu(vcpu))
> > - return vcpu->kvm->arch.dfr0_pmuver.imp;
> > -
> > - return vcpu->kvm->arch.dfr0_pmuver.unimp;
> > + u8 pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer),
> > + IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1));
> > + if (kvm_vcpu_has_pmu(vcpu) || pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
> > + return pmuver;
> > + else
> > + return 0;
> > }
> >
> > static u8 perfmon_to_pmuver(u8 perfmon)
> > @@ -263,10 +265,9 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
> > if (val)
> > return -EINVAL;
> >
> > - if (valid_pmu)
> > - vcpu->kvm->arch.dfr0_pmuver.imp = pmuver;
> > - else
> > - vcpu->kvm->arch.dfr0_pmuver.unimp = pmuver;
> > + IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1) &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer);
> > + IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1) |=
> > + FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), pmuver);
>
> Did you consider there could be guests that have vCPUs with and
> without PMU ? It looks like the code doesn't work for such guests.
> (e.g. for such guests, if setting the register is done for vCPUs
> without PMU, this code seems to make PMUVer zero or 0xf
> even for vCPUs with PMU)
Yes, I did. The PMUVer field is a per-VCPU field, whose value was
determined on the fly in the get_user function. Check the function
kvm_arm_read_id_reg_with_encoding, vcpu_pmuver is called to set the
real value for the VCPU.
The perVM ID registers array we put in the kvm structure save
correctly only for those perVM field, for those pre-VCPU filed, their
real value is determined on the fly during the register reading
(get_user).
>
> Thanks,
> Reiji
>
> >
> > return 0;
> > }
> > @@ -303,10 +304,9 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
> > if (val)
> > return -EINVAL;
> >
> > - if (valid_pmu)
> > - vcpu->kvm->arch.dfr0_pmuver.imp = perfmon_to_pmuver(perfmon);
> > - else
> > - vcpu->kvm->arch.dfr0_pmuver.unimp = perfmon_to_pmuver(perfmon);
> > + IDREG(vcpu->kvm, SYS_ID_DFR0_EL1) &= ~ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon);
> > + IDREG(vcpu->kvm, SYS_ID_DFR0_EL1) |=
> > + FIELD_PREP(ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon), perfmon_to_pmuver(perfmon));
> >
> > return 0;
> > }
> > @@ -530,4 +530,13 @@ void kvm_arm_set_default_id_regs(struct kvm *kvm)
> > }
> >
> > IDREG(kvm, SYS_ID_AA64PFR0_EL1) = val;
> > +
> > + /*
> > + * Initialise the default PMUver before there is a chance to
> > + * create an actual PMU.
> > + */
> > + IDREG(kvm, SYS_ID_AA64DFR0_EL1) &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer);
> > + IDREG(kvm, SYS_ID_AA64DFR0_EL1) |=
> > + FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer),
> > + kvm_arm_pmu_get_pmuver_limit());
> > }
> > diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> > index 628775334d5e..eef67b7d9751 100644
> > --- a/include/kvm/arm_pmu.h
> > +++ b/include/kvm/arm_pmu.h
> > @@ -92,8 +92,10 @@ void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
> > /*
> > * Evaluates as true when emulating PMUv3p5, and false otherwise.
> > */
> > -#define kvm_pmu_is_3p5(vcpu) \
> > - (vcpu->kvm->arch.dfr0_pmuver.imp >= ID_AA64DFR0_EL1_PMUVer_V3P5)
> > +#define kvm_pmu_is_3p5(vcpu) \
> > + (kvm_vcpu_has_pmu(vcpu) && \
> > + FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), \
> > + IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1)) >= ID_AA64DFR0_EL1_PMUVer_V3P5)
> >
> > u8 kvm_arm_pmu_get_pmuver_limit(void);
> >
> > --
> > 2.39.1.456.gfc5497dd1b-goog
> >
More information about the linux-arm-kernel
mailing list