[PATCH v2 1/6] KVM: arm64: Move CPU ID feature registers emulation into a separate file

Jing Zhang jingzhangos at google.com
Sun Feb 26 18:54:51 PST 2023


Hi Reiji, Marc,

On Thu, Feb 23, 2023 at 5:02 PM Reiji Watanabe <reijiw at google.com> wrote:
>
> Hi Jing,
>
> On Sun, Feb 12, 2023 at 1:58 PM Jing Zhang <jingzhangos at google.com> wrote:
> >
> > Create a new file id_regs.c for CPU ID feature registers emulation code,
> > which are moved from sys_regs.c and tweak sys_regs code accordingly.
> >
> > No functional change intended.
> >
> > Signed-off-by: Jing Zhang <jingzhangos at google.com>
> > ---
> >  arch/arm64/kvm/Makefile   |   2 +-
> >  arch/arm64/kvm/id_regs.c  | 486 ++++++++++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/sys_regs.c | 463 ++----------------------------------
> >  arch/arm64/kvm/sys_regs.h |  28 +++
> >  4 files changed, 541 insertions(+), 438 deletions(-)
> >  create mode 100644 arch/arm64/kvm/id_regs.c
> >
> > diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> > index c0c050e53157..a6a315fcd81e 100644
> > --- a/arch/arm64/kvm/Makefile
> > +++ b/arch/arm64/kvm/Makefile
> > @@ -13,7 +13,7 @@ obj-$(CONFIG_KVM) += hyp/
> >  kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
> >          inject_fault.o va_layout.o handle_exit.o \
> >          guest.o debug.o reset.o sys_regs.o stacktrace.o \
> > -        vgic-sys-reg-v3.o fpsimd.o pkvm.o \
> > +        vgic-sys-reg-v3.o fpsimd.o pkvm.o id_regs.o \
> >          arch_timer.o trng.o vmid.o emulate-nested.o nested.o \
> >          vgic/vgic.o vgic/vgic-init.o \
> >          vgic/vgic-irqfd.o vgic/vgic-v2.o \
> > diff --git a/arch/arm64/kvm/id_regs.c b/arch/arm64/kvm/id_regs.c
> > new file mode 100644
> > index 000000000000..7f30d683de21
> > --- /dev/null
> > +++ b/arch/arm64/kvm/id_regs.c
> > @@ -0,0 +1,486 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2023 - Google LLC
> > + * Author: Jing Zhang <jingzhangos at google.com>
> > + *
> > + * Moved from arch/arm64/kvm/sys_regs.c
> > + * Copyright (C) 2012,2013 - ARM Ltd
> > + * Author: Marc Zyngier <marc.zyngier at arm.com>
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/bsearch.h>
> > +#include <linux/kvm_host.h>
> > +#include <asm/kvm_emulate.h>
> > +#include <asm/sysreg.h>
> > +#include <asm/cpufeature.h>
> > +#include <asm/kvm_nested.h>
> > +
> > +#include "sys_regs.h"
> > +
> > +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;
> > +}
> > +
> > +static u8 perfmon_to_pmuver(u8 perfmon)
> > +{
> > +       switch (perfmon) {
> > +       case ID_DFR0_EL1_PerfMon_PMUv3:
> > +               return ID_AA64DFR0_EL1_PMUVer_IMP;
> > +       case ID_DFR0_EL1_PerfMon_IMPDEF:
> > +               return ID_AA64DFR0_EL1_PMUVer_IMP_DEF;
> > +       default:
> > +               /* Anything ARMv8.1+ and NI have the same value. For now. */
> > +               return perfmon;
> > +       }
> > +}
> > +
> > +static u8 pmuver_to_perfmon(u8 pmuver)
> > +{
> > +       switch (pmuver) {
> > +       case ID_AA64DFR0_EL1_PMUVer_IMP:
> > +               return ID_DFR0_EL1_PerfMon_PMUv3;
> > +       case ID_AA64DFR0_EL1_PMUVer_IMP_DEF:
> > +               return ID_DFR0_EL1_PerfMon_IMPDEF;
> > +       default:
> > +               /* Anything ARMv8.1+ and NI have the same value. For now. */
> > +               return pmuver;
> > +       }
> > +}
> > +
> > +/* Read a sanitised cpufeature ID register by sys_reg_desc */
> > +static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r)
> > +{
> > +       u32 id = reg_to_encoding(r);
> > +       u64 val;
> > +
> > +       if (sysreg_visible_as_raz(vcpu, r))
> > +               return 0;
> > +
> > +       val = read_sanitised_ftr_reg(id);
> > +
> > +       switch (id) {
> > +       case SYS_ID_AA64PFR0_EL1:
> > +               if (!vcpu_has_sve(vcpu))
> > +                       val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE);
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AMU);
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2);
> > +               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2),
> > +                                 (u64)vcpu->kvm->arch.pfr0_csv2);
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3);
> > +               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3),
> > +                                 (u64)vcpu->kvm->arch.pfr0_csv3);
> > +               if (kvm_vgic_global_state.type == VGIC_V3) {
> > +                       val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC);
> > +                       val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC), 1);
> > +               }
> > +               break;
> > +       case SYS_ID_AA64PFR1_EL1:
> > +               if (!kvm_has_mte(vcpu->kvm))
> > +                       val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
> > +
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
> > +               break;
> > +       case SYS_ID_AA64ISAR1_EL1:
> > +               if (!vcpu_has_ptrauth(vcpu))
> > +                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) |
> > +                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) |
> > +                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) |
> > +                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI));
> > +               break;
> > +       case SYS_ID_AA64ISAR2_EL1:
> > +               if (!vcpu_has_ptrauth(vcpu))
> > +                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) |
> > +                                ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3));
> > +               if (!cpus_have_final_cap(ARM64_HAS_WFXT))
> > +                       val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT);
> > +               break;
> > +       case SYS_ID_AA64DFR0_EL1:
> > +               /* Limit debug to ARMv8.0 */
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DebugVer);
> > +               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DebugVer), 6);
> > +               /* Set PMUver to the required version */
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer);
> > +               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer),
> > +                                 vcpu_pmuver(vcpu));
> > +               /* Hide SPE from guests */
> > +               val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMSVer);
> > +               break;
> > +       case SYS_ID_DFR0_EL1:
> > +               val &= ~ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon);
> > +               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon),
> > +                                 pmuver_to_perfmon(vcpu_pmuver(vcpu)));
> > +               break;
> > +       case SYS_ID_AA64MMFR2_EL1:
> > +               val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
> > +               break;
> > +       case SYS_ID_MMFR4_EL1:
> > +               val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX);
> > +               break;
> > +       }
> > +
> > +       return val;
> > +}
> > +
> > +/* cpufeature ID register access trap handlers */
> > +
> > +static bool access_id_reg(struct kvm_vcpu *vcpu,
> > +                         struct sys_reg_params *p,
> > +                         const struct sys_reg_desc *r)
> > +{
> > +       if (p->is_write)
> > +               return write_to_read_only(vcpu, p, r);
> > +
> > +       p->regval = read_id_reg(vcpu, r);
> > +       if (vcpu_has_nv(vcpu))
> > +               access_nested_id_reg(vcpu, p, r);
> > +
> > +       return true;
> > +}
> > +
> > +/*
> > + * cpufeature ID register user accessors
> > + *
> > + * For now, these registers are immutable for userspace, so no values
> > + * are stored, and for set_id_reg() we don't allow the effective value
> > + * to be changed.
> > + */
> > +static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> > +                     u64 *val)
> > +{
> > +       *val = read_id_reg(vcpu, rd);
> > +       return 0;
> > +}
> > +
> > +static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> > +                     u64 val)
> > +{
> > +       /* This is what we mean by invariant: you can't change it. */
> > +       if (val != read_id_reg(vcpu, rd))
> > +               return -EINVAL;
> > +
> > +       return 0;
> > +}
> > +
> > +static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
> > +                                 const struct sys_reg_desc *r)
> > +{
> > +       u32 id = reg_to_encoding(r);
> > +
> > +       switch (id) {
> > +       case SYS_ID_AA64ZFR0_EL1:
> > +               if (!vcpu_has_sve(vcpu))
> > +                       return REG_RAZ;
> > +               break;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static unsigned int aa32_id_visibility(const struct kvm_vcpu *vcpu,
> > +                                      const struct sys_reg_desc *r)
> > +{
> > +       /*
> > +        * AArch32 ID registers are UNKNOWN if AArch32 isn't implemented at any
> > +        * EL. Promote to RAZ/WI in order to guarantee consistency between
> > +        * systems.
> > +        */
> > +       if (!kvm_supports_32bit_el0())
> > +               return REG_RAZ | REG_USER_WI;
> > +
> > +       return id_visibility(vcpu, r);
> > +}
> > +
> > +static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
> > +                              const struct sys_reg_desc *rd,
> > +                              u64 val)
> > +{
> > +       u8 csv2, csv3;
> > +
> > +       /*
> > +        * Allow AA64PFR0_EL1.CSV2 to be set from userspace as long as
> > +        * it doesn't promise more than what is actually provided (the
> > +        * guest could otherwise be covered in ectoplasmic residue).
> > +        */
> > +       csv2 = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_EL1_CSV2_SHIFT);
> > +       if (csv2 > 1 ||
> > +           (csv2 && arm64_get_spectre_v2_state() != SPECTRE_UNAFFECTED))
> > +               return -EINVAL;
> > +
> > +       /* Same thing for CSV3 */
> > +       csv3 = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_EL1_CSV3_SHIFT);
> > +       if (csv3 > 1 ||
> > +           (csv3 && arm64_get_meltdown_state() != SPECTRE_UNAFFECTED))
> > +               return -EINVAL;
> > +
> > +       /* We can only differ with CSV[23], and anything else is an error */
> > +       val ^= read_id_reg(vcpu, rd);
> > +       val &= ~(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) |
> > +                ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3));
> > +       if (val)
> > +               return -EINVAL;
> > +
> > +       vcpu->kvm->arch.pfr0_csv2 = csv2;
> > +       vcpu->kvm->arch.pfr0_csv3 = csv3;
> > +
> > +       return 0;
> > +}
> > +
> > +static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
> > +                              const struct sys_reg_desc *rd,
> > +                              u64 val)
> > +{
> > +       u8 pmuver, host_pmuver;
> > +       bool valid_pmu;
> > +
> > +       host_pmuver = kvm_arm_pmu_get_pmuver_limit();
> > +
> > +       /*
> > +        * Allow AA64DFR0_EL1.PMUver to be set from userspace as long
> > +        * as it doesn't promise more than what the HW gives us. We
> > +        * allow an IMPDEF PMU though, only if no PMU is supported
> > +        * (KVM backward compatibility handling).
> > +        */
> > +       pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), val);
> > +       if ((pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF && pmuver > host_pmuver))
> > +               return -EINVAL;
> > +
> > +       valid_pmu = (pmuver != 0 && pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF);
> > +
> > +       /* Make sure view register and PMU support do match */
> > +       if (kvm_vcpu_has_pmu(vcpu) != valid_pmu)
> > +               return -EINVAL;
> > +
> > +       /* We can only differ with PMUver, and anything else is an error */
> > +       val ^= read_id_reg(vcpu, rd);
> > +       val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer);
> > +       if (val)
> > +               return -EINVAL;
> > +
> > +       if (valid_pmu)
> > +               vcpu->kvm->arch.dfr0_pmuver.imp = pmuver;
> > +       else
> > +               vcpu->kvm->arch.dfr0_pmuver.unimp = pmuver;
> > +
> > +       return 0;
> > +}
> > +
> > +static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
> > +                          const struct sys_reg_desc *rd,
> > +                          u64 val)
> > +{
> > +       u8 perfmon, host_perfmon;
> > +       bool valid_pmu;
> > +
> > +       host_perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
> > +
> > +       /*
> > +        * Allow DFR0_EL1.PerfMon to be set from userspace as long as
> > +        * it doesn't promise more than what the HW gives us on the
> > +        * AArch64 side (as everything is emulated with that), and
> > +        * that this is a PMUv3.
> > +        */
> > +       perfmon = FIELD_GET(ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon), val);
> > +       if ((perfmon != ID_DFR0_EL1_PerfMon_IMPDEF && perfmon > host_perfmon) ||
> > +           (perfmon != 0 && perfmon < ID_DFR0_EL1_PerfMon_PMUv3))
> > +               return -EINVAL;
> > +
> > +       valid_pmu = (perfmon != 0 && perfmon != ID_DFR0_EL1_PerfMon_IMPDEF);
> > +
> > +       /* Make sure view register and PMU support do match */
> > +       if (kvm_vcpu_has_pmu(vcpu) != valid_pmu)
> > +               return -EINVAL;
> > +
> > +       /* We can only differ with PerfMon, and anything else is an error */
> > +       val ^= read_id_reg(vcpu, rd);
> > +       val &= ~ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon);
> > +       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);
> > +
> > +       return 0;
> > +}
> > +
> > +/* sys_reg_desc initialiser for known cpufeature ID registers */
> > +#define ID_SANITISED(name) {                   \
> > +       SYS_DESC(SYS_##name),                   \
> > +       .access = access_id_reg,                \
> > +       .get_user = get_id_reg,                 \
> > +       .set_user = set_id_reg,                 \
> > +       .visibility = id_visibility,            \
> > +}
> > +
> > +/* sys_reg_desc initialiser for known cpufeature ID registers */
> > +#define AA32_ID_SANITISED(name) {              \
> > +       SYS_DESC(SYS_##name),                   \
> > +       .access = access_id_reg,                \
> > +       .get_user = get_id_reg,                 \
> > +       .set_user = set_id_reg,                 \
> > +       .visibility = aa32_id_visibility,       \
> > +}
> > +
> > +/*
> > + * sys_reg_desc initialiser for architecturally unallocated cpufeature ID
> > + * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
> > + * (1 <= crm < 8, 0 <= Op2 < 8).
> > + */
> > +#define ID_UNALLOCATED(crm, op2) {                     \
> > +       Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2),     \
> > +       .access = access_id_reg,                        \
> > +       .get_user = get_id_reg,                         \
> > +       .set_user = set_id_reg,                         \
> > +       .visibility = raz_visibility                    \
> > +}
> > +
> > +/*
> > + * sys_reg_desc initialiser for known ID registers that we hide from guests.
> > + * For now, these are exposed just like unallocated ID regs: they appear
> > + * RAZ for the guest.
> > + */
> > +#define ID_HIDDEN(name) {                      \
> > +       SYS_DESC(SYS_##name),                   \
> > +       .access = access_id_reg,                \
> > +       .get_user = get_id_reg,                 \
> > +       .set_user = set_id_reg,                 \
> > +       .visibility = raz_visibility,           \
> > +}
> > +
> > +static const struct sys_reg_desc id_reg_descs[] = {
> > +       /*
> > +        * ID regs: all ID_SANITISED() entries here must have corresponding
> > +        * entries in arm64_ftr_regs[].
> > +        */
> > +
> > +       /* AArch64 mappings of the AArch32 ID registers */
> > +       /* CRm=1 */
> > +       AA32_ID_SANITISED(ID_PFR0_EL1),
> > +       AA32_ID_SANITISED(ID_PFR1_EL1),
> > +       { SYS_DESC(SYS_ID_DFR0_EL1), .access = access_id_reg,
> > +         .get_user = get_id_reg, .set_user = set_id_dfr0_el1,
> > +         .visibility = aa32_id_visibility, },
> > +       ID_HIDDEN(ID_AFR0_EL1),
> > +       AA32_ID_SANITISED(ID_MMFR0_EL1),
> > +       AA32_ID_SANITISED(ID_MMFR1_EL1),
> > +       AA32_ID_SANITISED(ID_MMFR2_EL1),
> > +       AA32_ID_SANITISED(ID_MMFR3_EL1),
> > +
> > +       /* CRm=2 */
> > +       AA32_ID_SANITISED(ID_ISAR0_EL1),
> > +       AA32_ID_SANITISED(ID_ISAR1_EL1),
> > +       AA32_ID_SANITISED(ID_ISAR2_EL1),
> > +       AA32_ID_SANITISED(ID_ISAR3_EL1),
> > +       AA32_ID_SANITISED(ID_ISAR4_EL1),
> > +       AA32_ID_SANITISED(ID_ISAR5_EL1),
> > +       AA32_ID_SANITISED(ID_MMFR4_EL1),
> > +       AA32_ID_SANITISED(ID_ISAR6_EL1),
> > +
> > +       /* CRm=3 */
> > +       AA32_ID_SANITISED(MVFR0_EL1),
> > +       AA32_ID_SANITISED(MVFR1_EL1),
> > +       AA32_ID_SANITISED(MVFR2_EL1),
> > +       ID_UNALLOCATED(3, 3),
> > +       AA32_ID_SANITISED(ID_PFR2_EL1),
> > +       ID_HIDDEN(ID_DFR1_EL1),
> > +       AA32_ID_SANITISED(ID_MMFR5_EL1),
> > +       ID_UNALLOCATED(3, 7),
> > +
> > +       /* AArch64 ID registers */
> > +       /* CRm=4 */
> > +       { SYS_DESC(SYS_ID_AA64PFR0_EL1), .access = access_id_reg,
> > +         .get_user = get_id_reg, .set_user = set_id_aa64pfr0_el1, },
> > +       ID_SANITISED(ID_AA64PFR1_EL1),
> > +       ID_UNALLOCATED(4, 2),
> > +       ID_UNALLOCATED(4, 3),
> > +       ID_SANITISED(ID_AA64ZFR0_EL1),
> > +       ID_HIDDEN(ID_AA64SMFR0_EL1),
> > +       ID_UNALLOCATED(4, 6),
> > +       ID_UNALLOCATED(4, 7),
> > +
> > +       /* CRm=5 */
> > +       { SYS_DESC(SYS_ID_AA64DFR0_EL1), .access = access_id_reg,
> > +         .get_user = get_id_reg, .set_user = set_id_aa64dfr0_el1, },
> > +       ID_SANITISED(ID_AA64DFR1_EL1),
> > +       ID_UNALLOCATED(5, 2),
> > +       ID_UNALLOCATED(5, 3),
> > +       ID_HIDDEN(ID_AA64AFR0_EL1),
> > +       ID_HIDDEN(ID_AA64AFR1_EL1),
> > +       ID_UNALLOCATED(5, 6),
> > +       ID_UNALLOCATED(5, 7),
> > +
> > +       /* CRm=6 */
> > +       ID_SANITISED(ID_AA64ISAR0_EL1),
> > +       ID_SANITISED(ID_AA64ISAR1_EL1),
> > +       ID_SANITISED(ID_AA64ISAR2_EL1),
> > +       ID_UNALLOCATED(6, 3),
> > +       ID_UNALLOCATED(6, 4),
> > +       ID_UNALLOCATED(6, 5),
> > +       ID_UNALLOCATED(6, 6),
> > +       ID_UNALLOCATED(6, 7),
> > +
> > +       /* CRm=7 */
> > +       ID_SANITISED(ID_AA64MMFR0_EL1),
> > +       ID_SANITISED(ID_AA64MMFR1_EL1),
> > +       ID_SANITISED(ID_AA64MMFR2_EL1),
> > +       ID_UNALLOCATED(7, 3),
> > +       ID_UNALLOCATED(7, 4),
> > +       ID_UNALLOCATED(7, 5),
> > +       ID_UNALLOCATED(7, 6),
> > +       ID_UNALLOCATED(7, 7),
> > +};
> > +
> > +const struct sys_reg_desc *kvm_arm_find_id_reg(const struct sys_reg_params *params)
> > +{
>
> You might want to check if the param indicates the ID register,
> before running the binary search for the ID register table.
> (I have the same comment to kvm_arm_get_id_reg() and
> kvm_arm_set_id_reg()).
>
The check  (is_id_reg()) was added in the 5th commit when ID register
descriptor was added.
> > +       return find_reg(params, id_reg_descs, ARRAY_SIZE(id_reg_descs));
> > +}
> > +
> > +void kvm_arm_reset_id_regs(struct kvm_vcpu *vcpu)
> > +{
> > +       unsigned long i;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(id_reg_descs); i++)
> > +               if (id_reg_descs[i].reset)
> > +                       id_reg_descs[i].reset(vcpu, &id_reg_descs[i]);
> > +}
> > +
> > +int kvm_arm_get_id_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +       return kvm_sys_reg_get_user(vcpu, reg,
> > +                                   id_reg_descs, ARRAY_SIZE(id_reg_descs));
> > +}
> > +
> > +int kvm_arm_set_id_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +       return kvm_sys_reg_set_user(vcpu, reg,
> > +                                   id_reg_descs, ARRAY_SIZE(id_reg_descs));
> > +}
> > +
> > +bool kvm_arm_check_idreg_table(void)
> > +{
> > +       return check_sysreg_table(id_reg_descs, ARRAY_SIZE(id_reg_descs), false);
> > +}
> > +
> > +/* Assumed ordered tables, see kvm_sys_reg_table_init. */
>
> I don't think we need this comment, as the code doesn't seem to assume that.
>
Sure, will remove it.
> > +int kvm_arm_walk_id_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
> > +{
> > +       const struct sys_reg_desc *i2, *end2;
> > +       unsigned int total = 0;
> > +       int err;
> > +
> > +       i2 = id_reg_descs;
> > +       end2 = id_reg_descs + ARRAY_SIZE(id_reg_descs);
> > +
> > +       while (i2 != end2) {
> > +               err = walk_one_sys_reg(vcpu, i2++, &uind, &total);
> > +               if (err)
> > +                       return err;
> > +       }
> > +       return total;
> > +}
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index 53749d3a0996..3b23b7a67eb5 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -53,16 +53,6 @@ static bool read_from_write_only(struct kvm_vcpu *vcpu,
> >         return false;
> >  }
> >
> > -static bool write_to_read_only(struct kvm_vcpu *vcpu,
> > -                              struct sys_reg_params *params,
> > -                              const struct sys_reg_desc *r)
> > -{
> > -       WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n");
> > -       print_sys_reg_instr(params);
> > -       kvm_inject_undefined(vcpu);
> > -       return false;
> > -}
> > -
> >  u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
> >  {
> >         u64 val = 0x8badf00d8badf00d;
> > @@ -1153,163 +1143,6 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
> >         return true;
> >  }
> >
> > -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;
> > -}
> > -
> > -static u8 perfmon_to_pmuver(u8 perfmon)
> > -{
> > -       switch (perfmon) {
> > -       case ID_DFR0_EL1_PerfMon_PMUv3:
> > -               return ID_AA64DFR0_EL1_PMUVer_IMP;
> > -       case ID_DFR0_EL1_PerfMon_IMPDEF:
> > -               return ID_AA64DFR0_EL1_PMUVer_IMP_DEF;
> > -       default:
> > -               /* Anything ARMv8.1+ and NI have the same value. For now. */
> > -               return perfmon;
> > -       }
> > -}
> > -
> > -static u8 pmuver_to_perfmon(u8 pmuver)
> > -{
> > -       switch (pmuver) {
> > -       case ID_AA64DFR0_EL1_PMUVer_IMP:
> > -               return ID_DFR0_EL1_PerfMon_PMUv3;
> > -       case ID_AA64DFR0_EL1_PMUVer_IMP_DEF:
> > -               return ID_DFR0_EL1_PerfMon_IMPDEF;
> > -       default:
> > -               /* Anything ARMv8.1+ and NI have the same value. For now. */
> > -               return pmuver;
> > -       }
> > -}
> > -
> > -/* Read a sanitised cpufeature ID register by sys_reg_desc */
> > -static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r)
> > -{
> > -       u32 id = reg_to_encoding(r);
> > -       u64 val;
> > -
> > -       if (sysreg_visible_as_raz(vcpu, r))
> > -               return 0;
> > -
> > -       val = read_sanitised_ftr_reg(id);
> > -
> > -       switch (id) {
> > -       case SYS_ID_AA64PFR0_EL1:
> > -               if (!vcpu_has_sve(vcpu))
> > -                       val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE);
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AMU);
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2);
> > -               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2), (u64)vcpu->kvm->arch.pfr0_csv2);
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3);
> > -               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3), (u64)vcpu->kvm->arch.pfr0_csv3);
> > -               if (kvm_vgic_global_state.type == VGIC_V3) {
> > -                       val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC);
> > -                       val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC), 1);
> > -               }
> > -               break;
> > -       case SYS_ID_AA64PFR1_EL1:
> > -               if (!kvm_has_mte(vcpu->kvm))
> > -                       val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
> > -
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
> > -               break;
> > -       case SYS_ID_AA64ISAR1_EL1:
> > -               if (!vcpu_has_ptrauth(vcpu))
> > -                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) |
> > -                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) |
> > -                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) |
> > -                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI));
> > -               break;
> > -       case SYS_ID_AA64ISAR2_EL1:
> > -               if (!vcpu_has_ptrauth(vcpu))
> > -                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) |
> > -                                ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3));
> > -               if (!cpus_have_final_cap(ARM64_HAS_WFXT))
> > -                       val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT);
> > -               break;
> > -       case SYS_ID_AA64DFR0_EL1:
> > -               /* Limit debug to ARMv8.0 */
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DebugVer);
> > -               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DebugVer), 6);
> > -               /* Set PMUver to the required version */
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer);
> > -               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer),
> > -                                 vcpu_pmuver(vcpu));
> > -               /* Hide SPE from guests */
> > -               val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMSVer);
> > -               break;
> > -       case SYS_ID_DFR0_EL1:
> > -               val &= ~ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon);
> > -               val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon),
> > -                                 pmuver_to_perfmon(vcpu_pmuver(vcpu)));
> > -               break;
> > -       case SYS_ID_AA64MMFR2_EL1:
> > -               val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
> > -               break;
> > -       case SYS_ID_MMFR4_EL1:
> > -               val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX);
> > -               break;
> > -       }
> > -
> > -       return val;
> > -}
> > -
> > -static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
> > -                                 const struct sys_reg_desc *r)
> > -{
> > -       u32 id = reg_to_encoding(r);
> > -
> > -       switch (id) {
> > -       case SYS_ID_AA64ZFR0_EL1:
> > -               if (!vcpu_has_sve(vcpu))
> > -                       return REG_RAZ;
> > -               break;
> > -       }
> > -
> > -       return 0;
> > -}
> > -
> > -static unsigned int aa32_id_visibility(const struct kvm_vcpu *vcpu,
> > -                                      const struct sys_reg_desc *r)
> > -{
> > -       /*
> > -        * AArch32 ID registers are UNKNOWN if AArch32 isn't implemented at any
> > -        * EL. Promote to RAZ/WI in order to guarantee consistency between
> > -        * systems.
> > -        */
> > -       if (!kvm_supports_32bit_el0())
> > -               return REG_RAZ | REG_USER_WI;
> > -
> > -       return id_visibility(vcpu, r);
> > -}
> > -
> > -static unsigned int raz_visibility(const struct kvm_vcpu *vcpu,
> > -                                  const struct sys_reg_desc *r)
> > -{
> > -       return REG_RAZ;
> > -}
> > -
> > -/* cpufeature ID register access trap handlers */
> > -
> > -static bool access_id_reg(struct kvm_vcpu *vcpu,
> > -                         struct sys_reg_params *p,
> > -                         const struct sys_reg_desc *r)
> > -{
> > -       if (p->is_write)
> > -               return write_to_read_only(vcpu, p, r);
> > -
> > -       p->regval = read_id_reg(vcpu, r);
> > -       if (vcpu_has_nv(vcpu))
> > -               access_nested_id_reg(vcpu, p, r);
> > -
> > -       return true;
> > -}
> > -
> >  /* Visibility overrides for SVE-specific control registers */
> >  static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
> >                                    const struct sys_reg_desc *rd)
> > @@ -1320,144 +1153,6 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
> >         return REG_HIDDEN;
> >  }
> >
> > -static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
> > -                              const struct sys_reg_desc *rd,
> > -                              u64 val)
> > -{
> > -       u8 csv2, csv3;
> > -
> > -       /*
> > -        * Allow AA64PFR0_EL1.CSV2 to be set from userspace as long as
> > -        * it doesn't promise more than what is actually provided (the
> > -        * guest could otherwise be covered in ectoplasmic residue).
> > -        */
> > -       csv2 = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_EL1_CSV2_SHIFT);
> > -       if (csv2 > 1 ||
> > -           (csv2 && arm64_get_spectre_v2_state() != SPECTRE_UNAFFECTED))
> > -               return -EINVAL;
> > -
> > -       /* Same thing for CSV3 */
> > -       csv3 = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_EL1_CSV3_SHIFT);
> > -       if (csv3 > 1 ||
> > -           (csv3 && arm64_get_meltdown_state() != SPECTRE_UNAFFECTED))
> > -               return -EINVAL;
> > -
> > -       /* We can only differ with CSV[23], and anything else is an error */
> > -       val ^= read_id_reg(vcpu, rd);
> > -       val &= ~(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) |
> > -                ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3));
> > -       if (val)
> > -               return -EINVAL;
> > -
> > -       vcpu->kvm->arch.pfr0_csv2 = csv2;
> > -       vcpu->kvm->arch.pfr0_csv3 = csv3;
> > -
> > -       return 0;
> > -}
> > -
> > -static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
> > -                              const struct sys_reg_desc *rd,
> > -                              u64 val)
> > -{
> > -       u8 pmuver, host_pmuver;
> > -       bool valid_pmu;
> > -
> > -       host_pmuver = kvm_arm_pmu_get_pmuver_limit();
> > -
> > -       /*
> > -        * Allow AA64DFR0_EL1.PMUver to be set from userspace as long
> > -        * as it doesn't promise more than what the HW gives us. We
> > -        * allow an IMPDEF PMU though, only if no PMU is supported
> > -        * (KVM backward compatibility handling).
> > -        */
> > -       pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), val);
> > -       if ((pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF && pmuver > host_pmuver))
> > -               return -EINVAL;
> > -
> > -       valid_pmu = (pmuver != 0 && pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF);
> > -
> > -       /* Make sure view register and PMU support do match */
> > -       if (kvm_vcpu_has_pmu(vcpu) != valid_pmu)
> > -               return -EINVAL;
> > -
> > -       /* We can only differ with PMUver, and anything else is an error */
> > -       val ^= read_id_reg(vcpu, rd);
> > -       val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer);
> > -       if (val)
> > -               return -EINVAL;
> > -
> > -       if (valid_pmu)
> > -               vcpu->kvm->arch.dfr0_pmuver.imp = pmuver;
> > -       else
> > -               vcpu->kvm->arch.dfr0_pmuver.unimp = pmuver;
> > -
> > -       return 0;
> > -}
> > -
> > -static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
> > -                          const struct sys_reg_desc *rd,
> > -                          u64 val)
> > -{
> > -       u8 perfmon, host_perfmon;
> > -       bool valid_pmu;
> > -
> > -       host_perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
> > -
> > -       /*
> > -        * Allow DFR0_EL1.PerfMon to be set from userspace as long as
> > -        * it doesn't promise more than what the HW gives us on the
> > -        * AArch64 side (as everything is emulated with that), and
> > -        * that this is a PMUv3.
> > -        */
> > -       perfmon = FIELD_GET(ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon), val);
> > -       if ((perfmon != ID_DFR0_EL1_PerfMon_IMPDEF && perfmon > host_perfmon) ||
> > -           (perfmon != 0 && perfmon < ID_DFR0_EL1_PerfMon_PMUv3))
> > -               return -EINVAL;
> > -
> > -       valid_pmu = (perfmon != 0 && perfmon != ID_DFR0_EL1_PerfMon_IMPDEF);
> > -
> > -       /* Make sure view register and PMU support do match */
> > -       if (kvm_vcpu_has_pmu(vcpu) != valid_pmu)
> > -               return -EINVAL;
> > -
> > -       /* We can only differ with PerfMon, and anything else is an error */
> > -       val ^= read_id_reg(vcpu, rd);
> > -       val &= ~ARM64_FEATURE_MASK(ID_DFR0_EL1_PerfMon);
> > -       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);
> > -
> > -       return 0;
> > -}
> > -
> > -/*
> > - * cpufeature ID register user accessors
> > - *
> > - * For now, these registers are immutable for userspace, so no values
> > - * are stored, and for set_id_reg() we don't allow the effective value
> > - * to be changed.
> > - */
> > -static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> > -                     u64 *val)
> > -{
> > -       *val = read_id_reg(vcpu, rd);
> > -       return 0;
> > -}
> > -
> > -static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> > -                     u64 val)
> > -{
> > -       /* This is what we mean by invariant: you can't change it. */
> > -       if (val != read_id_reg(vcpu, rd))
> > -               return -EINVAL;
> > -
> > -       return 0;
> > -}
> > -
> >  static int get_raz_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> >                        u64 *val)
> >  {
> > @@ -1642,50 +1337,6 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
> >         .visibility = elx2_visibility,          \
> >  }
> >
> > -/* sys_reg_desc initialiser for known cpufeature ID registers */
> > -#define ID_SANITISED(name) {                   \
> > -       SYS_DESC(SYS_##name),                   \
> > -       .access = access_id_reg,                \
> > -       .get_user = get_id_reg,                 \
> > -       .set_user = set_id_reg,                 \
> > -       .visibility = id_visibility,            \
> > -}
> > -
> > -/* sys_reg_desc initialiser for known cpufeature ID registers */
> > -#define AA32_ID_SANITISED(name) {              \
> > -       SYS_DESC(SYS_##name),                   \
> > -       .access = access_id_reg,                \
> > -       .get_user = get_id_reg,                 \
> > -       .set_user = set_id_reg,                 \
> > -       .visibility = aa32_id_visibility,       \
> > -}
> > -
> > -/*
> > - * sys_reg_desc initialiser for architecturally unallocated cpufeature ID
> > - * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
> > - * (1 <= crm < 8, 0 <= Op2 < 8).
> > - */
> > -#define ID_UNALLOCATED(crm, op2) {                     \
> > -       Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2),     \
> > -       .access = access_id_reg,                        \
> > -       .get_user = get_id_reg,                         \
> > -       .set_user = set_id_reg,                         \
> > -       .visibility = raz_visibility                    \
> > -}
> > -
> > -/*
> > - * sys_reg_desc initialiser for known ID registers that we hide from guests.
> > - * For now, these are exposed just like unallocated ID regs: they appear
> > - * RAZ for the guest.
> > - */
> > -#define ID_HIDDEN(name) {                      \
> > -       SYS_DESC(SYS_##name),                   \
> > -       .access = access_id_reg,                \
> > -       .get_user = get_id_reg,                 \
> > -       .set_user = set_id_reg,                 \
> > -       .visibility = raz_visibility,           \
> > -}
> > -
> >  static bool access_sp_el1(struct kvm_vcpu *vcpu,
> >                           struct sys_reg_params *p,
> >                           const struct sys_reg_desc *r)
> > @@ -1776,87 +1427,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >
> >         { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
> >
> > -       /*
> > -        * ID regs: all ID_SANITISED() entries here must have corresponding
> > -        * entries in arm64_ftr_regs[].
> > -        */
> > -
> > -       /* AArch64 mappings of the AArch32 ID registers */
> > -       /* CRm=1 */
> > -       AA32_ID_SANITISED(ID_PFR0_EL1),
> > -       AA32_ID_SANITISED(ID_PFR1_EL1),
> > -       { SYS_DESC(SYS_ID_DFR0_EL1), .access = access_id_reg,
> > -         .get_user = get_id_reg, .set_user = set_id_dfr0_el1,
> > -         .visibility = aa32_id_visibility, },
> > -       ID_HIDDEN(ID_AFR0_EL1),
> > -       AA32_ID_SANITISED(ID_MMFR0_EL1),
> > -       AA32_ID_SANITISED(ID_MMFR1_EL1),
> > -       AA32_ID_SANITISED(ID_MMFR2_EL1),
> > -       AA32_ID_SANITISED(ID_MMFR3_EL1),
> > -
> > -       /* CRm=2 */
> > -       AA32_ID_SANITISED(ID_ISAR0_EL1),
> > -       AA32_ID_SANITISED(ID_ISAR1_EL1),
> > -       AA32_ID_SANITISED(ID_ISAR2_EL1),
> > -       AA32_ID_SANITISED(ID_ISAR3_EL1),
> > -       AA32_ID_SANITISED(ID_ISAR4_EL1),
> > -       AA32_ID_SANITISED(ID_ISAR5_EL1),
> > -       AA32_ID_SANITISED(ID_MMFR4_EL1),
> > -       AA32_ID_SANITISED(ID_ISAR6_EL1),
> > -
> > -       /* CRm=3 */
> > -       AA32_ID_SANITISED(MVFR0_EL1),
> > -       AA32_ID_SANITISED(MVFR1_EL1),
> > -       AA32_ID_SANITISED(MVFR2_EL1),
> > -       ID_UNALLOCATED(3,3),
> > -       AA32_ID_SANITISED(ID_PFR2_EL1),
> > -       ID_HIDDEN(ID_DFR1_EL1),
> > -       AA32_ID_SANITISED(ID_MMFR5_EL1),
> > -       ID_UNALLOCATED(3,7),
> > -
> > -       /* AArch64 ID registers */
> > -       /* CRm=4 */
> > -       { SYS_DESC(SYS_ID_AA64PFR0_EL1), .access = access_id_reg,
> > -         .get_user = get_id_reg, .set_user = set_id_aa64pfr0_el1, },
> > -       ID_SANITISED(ID_AA64PFR1_EL1),
> > -       ID_UNALLOCATED(4,2),
> > -       ID_UNALLOCATED(4,3),
> > -       ID_SANITISED(ID_AA64ZFR0_EL1),
> > -       ID_HIDDEN(ID_AA64SMFR0_EL1),
> > -       ID_UNALLOCATED(4,6),
> > -       ID_UNALLOCATED(4,7),
> > -
> > -       /* CRm=5 */
> > -       { SYS_DESC(SYS_ID_AA64DFR0_EL1), .access = access_id_reg,
> > -         .get_user = get_id_reg, .set_user = set_id_aa64dfr0_el1, },
> > -       ID_SANITISED(ID_AA64DFR1_EL1),
> > -       ID_UNALLOCATED(5,2),
> > -       ID_UNALLOCATED(5,3),
> > -       ID_HIDDEN(ID_AA64AFR0_EL1),
> > -       ID_HIDDEN(ID_AA64AFR1_EL1),
> > -       ID_UNALLOCATED(5,6),
> > -       ID_UNALLOCATED(5,7),
> > -
> > -       /* CRm=6 */
> > -       ID_SANITISED(ID_AA64ISAR0_EL1),
> > -       ID_SANITISED(ID_AA64ISAR1_EL1),
> > -       ID_SANITISED(ID_AA64ISAR2_EL1),
> > -       ID_UNALLOCATED(6,3),
> > -       ID_UNALLOCATED(6,4),
> > -       ID_UNALLOCATED(6,5),
> > -       ID_UNALLOCATED(6,6),
> > -       ID_UNALLOCATED(6,7),
> > -
> > -       /* CRm=7 */
> > -       ID_SANITISED(ID_AA64MMFR0_EL1),
> > -       ID_SANITISED(ID_AA64MMFR1_EL1),
> > -       ID_SANITISED(ID_AA64MMFR2_EL1),
> > -       ID_UNALLOCATED(7,3),
> > -       ID_UNALLOCATED(7,4),
> > -       ID_UNALLOCATED(7,5),
> > -       ID_UNALLOCATED(7,6),
> > -       ID_UNALLOCATED(7,7),
> > -
> >         { SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
> >         { SYS_DESC(SYS_ACTLR_EL1), access_actlr, reset_actlr, ACTLR_EL1 },
> >         { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> > @@ -2531,8 +2101,8 @@ static const struct sys_reg_desc cp15_64_regs[] = {
> >         { SYS_DESC(SYS_AARCH32_CNTP_CVAL),    access_arch_timer },
> >  };
> >
> > -static bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
> > -                              bool is_32)
> > +bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
> > +                       bool is_32)
> >  {
> >         unsigned int i;
> >
> > @@ -2883,7 +2453,9 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu,
> >  {
> >         const struct sys_reg_desc *r;
> >
> > -       r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
> > +       r = kvm_arm_find_id_reg(params);
>
> It appears that this is the only one code that enforces id_regs.c
> to expose sys_reg_desc of ID registers. Although I'm not sure your
> intention, you might want to create emulate_id_reg(), instead of
> exposing that unnecessarily ?
Sure, will use emulate_id_reg which would be used in kvm_handle_sys_reg.
>
> Thank you,
> Reiji
>
> > +       if (!r)
> > +               r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
> >
> >         if (likely(r)) {
> >                 perform_access(vcpu, params, r);
> > @@ -2912,6 +2484,8 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
> >  {
> >         unsigned long i;
> >
> > +       kvm_arm_reset_id_regs(vcpu);
> > +
> >         for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++)
> >                 if (sys_reg_descs[i].reset)
> >                         sys_reg_descs[i].reset(vcpu, &sys_reg_descs[i]);
> > @@ -3160,6 +2734,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
> >         if (err != -ENOENT)
> >                 return err;
> >
> > +       err = kvm_arm_get_id_reg(vcpu, reg);
> > +       if (err != -ENOENT)
> > +               return err;
> > +
> >         return kvm_sys_reg_get_user(vcpu, reg,
> >                                     sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
> >  }
> > @@ -3204,6 +2782,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
> >         if (err != -ENOENT)
> >                 return err;
> >
> > +       err = kvm_arm_set_id_reg(vcpu, reg);
> > +       if (err != -ENOENT)
> > +               return err;
> > +
> >         return kvm_sys_reg_set_user(vcpu, reg,
> >                                     sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
> >  }
> > @@ -3250,10 +2832,10 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
> >         return true;
> >  }
> >
> > -static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
> > -                           const struct sys_reg_desc *rd,
> > -                           u64 __user **uind,
> > -                           unsigned int *total)
> > +int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
> > +                    const struct sys_reg_desc *rd,
> > +                    u64 __user **uind,
> > +                    unsigned int *total)
> >  {
> >         /*
> >          * Ignore registers we trap but don't save,
> > @@ -3294,6 +2876,7 @@ unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
> >  {
> >         return ARRAY_SIZE(invariant_sys_regs)
> >                 + num_demux_regs()
> > +               + kvm_arm_walk_id_regs(vcpu, (u64 __user *)NULL)
> >                 + walk_sys_regs(vcpu, (u64 __user *)NULL);
> >  }
> >
> > @@ -3309,6 +2892,11 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >                 uindices++;
> >         }
> >
> > +       err = kvm_arm_walk_id_regs(vcpu, uindices);
> > +       if (err < 0)
> > +               return err;
> > +       uindices += err;
> > +
> >         err = walk_sys_regs(vcpu, uindices);
> >         if (err < 0)
> >                 return err;
> > @@ -3323,6 +2911,7 @@ int __init kvm_sys_reg_table_init(void)
> >         unsigned int i;
> >
> >         /* Make sure tables are unique and in order. */
> > +       valid &= kvm_arm_check_idreg_table();
> >         valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false);
> >         valid &= check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs), true);
> >         valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), true);
> > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> > index 6b11f2cc7146..96a52936d130 100644
> > --- a/arch/arm64/kvm/sys_regs.h
> > +++ b/arch/arm64/kvm/sys_regs.h
> > @@ -210,6 +210,22 @@ find_reg(const struct sys_reg_params *params, const struct sys_reg_desc table[],
> >         return __inline_bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
> >  }
> >
> > +static inline unsigned int raz_visibility(const struct kvm_vcpu *vcpu,
> > +                                         const struct sys_reg_desc *r)
> > +{
> > +       return REG_RAZ;
> > +}
> > +
> > +static inline bool write_to_read_only(struct kvm_vcpu *vcpu,
> > +                                     struct sys_reg_params *params,
> > +                                     const struct sys_reg_desc *r)
> > +{
> > +       WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n");
> > +       print_sys_reg_instr(params);
> > +       kvm_inject_undefined(vcpu);
> > +       return false;
> > +}
> > +
> >  const struct sys_reg_desc *get_reg_by_id(u64 id,
> >                                          const struct sys_reg_desc table[],
> >                                          unsigned int num);
> > @@ -220,6 +236,18 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
> >                          const struct sys_reg_desc table[], unsigned int num);
> >  int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
> >                          const struct sys_reg_desc table[], unsigned int num);
> > +bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
> > +                       bool is_32);
> > +int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
> > +                    const struct sys_reg_desc *rd,
> > +                    u64 __user **uind,
> > +                    unsigned int *total);
> > +const struct sys_reg_desc *kvm_arm_find_id_reg(const struct sys_reg_params *params);
> > +void kvm_arm_reset_id_regs(struct kvm_vcpu *vcpu);
> > +int kvm_arm_get_id_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
> > +int kvm_arm_set_id_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
> > +bool kvm_arm_check_idreg_table(void);
> > +int kvm_arm_walk_id_regs(struct kvm_vcpu *vcpu, u64 __user *uind);
> >
> >  #define AA32(_x)       .aarch32_map = AA32_##_x
> >  #define Op0(_x)        .Op0 = _x
> > --
> > 2.39.1.581.gbfd45094c4-goog
> >

Thanks,
Jing



More information about the linux-arm-kernel mailing list