Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[sfrench/cifs-2.6.git] / arch / arm64 / kvm / sys_regs.c
index 5b5d5e5449dc1357e14a74f09d824e643b6911b1..bd3431823ec547d7dc1a945e20b00fd6f87c4cae 100644 (file)
@@ -42,6 +42,8 @@
  */
 
 static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
+static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+                     u64 val);
 
 static bool read_from_write_only(struct kvm_vcpu *vcpu,
                                 struct sys_reg_params *params,
@@ -553,10 +555,11 @@ static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static void reset_bvr(struct kvm_vcpu *vcpu,
+static u64 reset_bvr(struct kvm_vcpu *vcpu,
                      const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm] = rd->val;
+       return rd->val;
 }
 
 static bool trap_bcr(struct kvm_vcpu *vcpu,
@@ -589,10 +592,11 @@ static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static void reset_bcr(struct kvm_vcpu *vcpu,
+static u64 reset_bcr(struct kvm_vcpu *vcpu,
                      const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm] = rd->val;
+       return rd->val;
 }
 
 static bool trap_wvr(struct kvm_vcpu *vcpu,
@@ -626,10 +630,11 @@ static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static void reset_wvr(struct kvm_vcpu *vcpu,
+static u64 reset_wvr(struct kvm_vcpu *vcpu,
                      const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm] = rd->val;
+       return rd->val;
 }
 
 static bool trap_wcr(struct kvm_vcpu *vcpu,
@@ -662,25 +667,28 @@ static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return 0;
 }
 
-static void reset_wcr(struct kvm_vcpu *vcpu,
+static u64 reset_wcr(struct kvm_vcpu *vcpu,
                      const struct sys_reg_desc *rd)
 {
        vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm] = rd->val;
+       return rd->val;
 }
 
-static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 amair = read_sysreg(amair_el1);
        vcpu_write_sys_reg(vcpu, amair, AMAIR_EL1);
+       return amair;
 }
 
-static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 actlr = read_sysreg(actlr_el1);
        vcpu_write_sys_reg(vcpu, actlr, ACTLR_EL1);
+       return actlr;
 }
 
-static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 mpidr;
 
@@ -694,7 +702,10 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
        mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
        mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
        mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
-       vcpu_write_sys_reg(vcpu, (1ULL << 31) | mpidr, MPIDR_EL1);
+       mpidr |= (1ULL << 31);
+       vcpu_write_sys_reg(vcpu, mpidr, MPIDR_EL1);
+
+       return mpidr;
 }
 
 static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
@@ -706,13 +717,13 @@ static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
        return REG_HIDDEN;
 }
 
-static void reset_pmu_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_pmu_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 n, mask = BIT(ARMV8_PMU_CYCLE_IDX);
 
        /* No PMU available, any PMU reg may UNDEF... */
        if (!kvm_arm_support_pmu_v3())
-               return;
+               return 0;
 
        n = read_sysreg(pmcr_el0) >> ARMV8_PMU_PMCR_N_SHIFT;
        n &= ARMV8_PMU_PMCR_N_MASK;
@@ -721,33 +732,41 @@ static void reset_pmu_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 
        reset_unknown(vcpu, r);
        __vcpu_sys_reg(vcpu, r->reg) &= mask;
+
+       return __vcpu_sys_reg(vcpu, r->reg);
 }
 
-static void reset_pmevcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_pmevcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        reset_unknown(vcpu, r);
        __vcpu_sys_reg(vcpu, r->reg) &= GENMASK(31, 0);
+
+       return __vcpu_sys_reg(vcpu, r->reg);
 }
 
-static void reset_pmevtyper(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_pmevtyper(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        reset_unknown(vcpu, r);
        __vcpu_sys_reg(vcpu, r->reg) &= ARMV8_PMU_EVTYPE_MASK;
+
+       return __vcpu_sys_reg(vcpu, r->reg);
 }
 
-static void reset_pmselr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_pmselr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        reset_unknown(vcpu, r);
        __vcpu_sys_reg(vcpu, r->reg) &= ARMV8_PMU_COUNTER_MASK;
+
+       return __vcpu_sys_reg(vcpu, r->reg);
 }
 
-static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 pmcr;
 
        /* No PMU available, PMCR_EL0 may UNDEF... */
        if (!kvm_arm_support_pmu_v3())
-               return;
+               return 0;
 
        /* Only preserve PMCR_EL0.N, and reset the rest to 0 */
        pmcr = read_sysreg(pmcr_el0) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT);
@@ -755,6 +774,8 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
                pmcr |= ARMV8_PMU_PMCR_LC;
 
        __vcpu_sys_reg(vcpu, r->reg) = pmcr;
+
+       return __vcpu_sys_reg(vcpu, r->reg);
 }
 
 static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
@@ -1187,25 +1208,89 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
        return true;
 }
 
-static u8 vcpu_pmuver(const struct kvm_vcpu *vcpu)
+static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
+                                   s64 new, s64 cur)
 {
-       if (kvm_vcpu_has_pmu(vcpu))
-               return vcpu->kvm->arch.dfr0_pmuver.imp;
+       struct arm64_ftr_bits kvm_ftr = *ftrp;
+
+       /* Some features have different safe value type in KVM than host features */
+       switch (id) {
+       case SYS_ID_AA64DFR0_EL1:
+               if (kvm_ftr.shift == ID_AA64DFR0_EL1_PMUVer_SHIFT)
+                       kvm_ftr.type = FTR_LOWER_SAFE;
+               break;
+       case SYS_ID_DFR0_EL1:
+               if (kvm_ftr.shift == ID_DFR0_EL1_PerfMon_SHIFT)
+                       kvm_ftr.type = FTR_LOWER_SAFE;
+               break;
+       }
 
-       return vcpu->kvm->arch.dfr0_pmuver.unimp;
+       return arm64_ftr_safe_value(&kvm_ftr, new, cur);
 }
 
-static u8 perfmon_to_pmuver(u8 perfmon)
+/**
+ * arm64_check_features() - Check if a feature register value constitutes
+ * a subset of features indicated by the idreg's KVM sanitised limit.
+ *
+ * This function will check if each feature field of @val is the "safe" value
+ * against idreg's KVM sanitised limit return from reset() callback.
+ * If a field value in @val is the same as the one in limit, it is always
+ * considered the safe value regardless For register fields that are not in
+ * writable, only the value in limit is considered the safe value.
+ *
+ * Return: 0 if all the fields are safe. Otherwise, return negative errno.
+ */
+static int arm64_check_features(struct kvm_vcpu *vcpu,
+                               const struct sys_reg_desc *rd,
+                               u64 val)
 {
-       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;
+       const struct arm64_ftr_reg *ftr_reg;
+       const struct arm64_ftr_bits *ftrp = NULL;
+       u32 id = reg_to_encoding(rd);
+       u64 writable_mask = rd->val;
+       u64 limit = rd->reset(vcpu, rd);
+       u64 mask = 0;
+
+       /*
+        * Hidden and unallocated ID registers may not have a corresponding
+        * struct arm64_ftr_reg. Of course, if the register is RAZ we know the
+        * only safe value is 0.
+        */
+       if (sysreg_visible_as_raz(vcpu, rd))
+               return val ? -E2BIG : 0;
+
+       ftr_reg = get_arm64_ftr_reg(id);
+       if (!ftr_reg)
+               return -EINVAL;
+
+       ftrp = ftr_reg->ftr_bits;
+
+       for (; ftrp && ftrp->width; ftrp++) {
+               s64 f_val, f_lim, safe_val;
+               u64 ftr_mask;
+
+               ftr_mask = arm64_ftr_mask(ftrp);
+               if ((ftr_mask & writable_mask) != ftr_mask)
+                       continue;
+
+               f_val = arm64_ftr_value(ftrp, val);
+               f_lim = arm64_ftr_value(ftrp, limit);
+               mask |= ftr_mask;
+
+               if (f_val == f_lim)
+                       safe_val = f_val;
+               else
+                       safe_val = kvm_arm64_ftr_safe_value(id, ftrp, f_val, f_lim);
+
+               if (safe_val != f_val)
+                       return -E2BIG;
        }
+
+       /* For fields that are not writable, values in limit are the safe values. */
+       if ((val & ~mask) != (limit & ~mask))
+               return -E2BIG;
+
+       return 0;
 }
 
 static u8 pmuver_to_perfmon(u8 pmuver)
@@ -1222,7 +1307,8 @@ static u8 pmuver_to_perfmon(u8 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)
+static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
+                                      const struct sys_reg_desc *r)
 {
        u32 id = reg_to_encoding(r);
        u64 val;
@@ -1233,19 +1319,6 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r
        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);
@@ -1267,22 +1340,6 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r
                        val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT);
                val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS);
                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;
@@ -1294,6 +1351,28 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r
        return val;
 }
 
+static u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu,
+                                    const struct sys_reg_desc *r)
+{
+       return __kvm_read_sanitised_id_reg(vcpu, r);
+}
+
+static u64 read_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+       return IDREG(vcpu->kvm, reg_to_encoding(r));
+}
+
+/*
+ * Return true if the register's (Op0, Op1, CRn, CRm, Op2) is
+ * (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
+ */
+static inline bool is_id_reg(u32 id)
+{
+       return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 &&
+               sys_reg_CRn(id) == 0 && sys_reg_CRm(id) >= 1 &&
+               sys_reg_CRm(id) < 8);
+}
+
 static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
                                  const struct sys_reg_desc *r)
 {
@@ -1355,88 +1434,113 @@ 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)
+static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
+                                         const struct sys_reg_desc *rd)
 {
-       u8 csv2, csv3;
+       u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+       if (!vcpu_has_sve(vcpu))
+               val &= ~ID_AA64PFR0_EL1_SVE_MASK;
 
        /*
-        * 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).
+        * The default is to expose CSV2 == 1 if the HW isn't affected.
+        * Although this is a per-CPU feature, we make it global because
+        * asymmetric systems are just a nuisance.
+        *
+        * Userspace can override this as long as it doesn't promise
+        * the impossible.
         */
-       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;
+       if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED) {
+               val &= ~ID_AA64PFR0_EL1_CSV2_MASK;
+               val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV2, IMP);
+       }
+       if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED) {
+               val &= ~ID_AA64PFR0_EL1_CSV3_MASK;
+               val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV3, IMP);
+       }
 
-       /* 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;
+       if (kvm_vgic_global_state.type == VGIC_V3) {
+               val &= ~ID_AA64PFR0_EL1_GIC_MASK;
+               val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
+       }
 
-       /* 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;
+       val &= ~ID_AA64PFR0_EL1_AMU_MASK;
 
-       vcpu->kvm->arch.pfr0_csv2 = csv2;
-       vcpu->kvm->arch.pfr0_csv3 = csv3;
+       return val;
+}
 
-       return 0;
+static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
+                                         const struct sys_reg_desc *rd)
+{
+       u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
+
+       /* Limit debug to ARMv8.0 */
+       val &= ~ID_AA64DFR0_EL1_DebugVer_MASK;
+       val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, IMP);
+
+       /*
+        * Only initialize the PMU version if the vCPU was configured with one.
+        */
+       val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
+       if (kvm_vcpu_has_pmu(vcpu))
+               val |= SYS_FIELD_PREP(ID_AA64DFR0_EL1, PMUVer,
+                                     kvm_arm_pmu_get_pmuver_limit());
+
+       /* Hide SPE from guests */
+       val &= ~ID_AA64DFR0_EL1_PMSVer_MASK;
+
+       return val;
 }
 
 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();
+       u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);
 
        /*
-        * 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).
+        * Prior to commit 3d0dba5764b9 ("KVM: arm64: PMU: Move the
+        * ID_AA64DFR0_EL1.PMUver limit to VM creation"), KVM erroneously
+        * exposed an IMP_DEF PMU to userspace and the guest on systems w/
+        * non-architectural PMUs. Of course, PMUv3 is the only game in town for
+        * PMU virtualization, so the IMP_DEF value was rather user-hostile.
+        *
+        * At minimum, we're on the hook to allow values that were given to
+        * userspace by KVM. Cover our tracks here and replace the IMP_DEF value
+        * with a more sensible NI. The value of an ID register changing under
+        * the nose of the guest is unfortunate, but is certainly no more
+        * surprising than an ill-guided PMU driver poking at impdef system
+        * registers that end in an UNDEF...
         */
-       pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), val);
-       if ((pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF && pmuver > host_pmuver))
-               return -EINVAL;
+       if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
+               val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
 
-       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;
+       return set_id_reg(vcpu, rd, val);
+}
 
-       /* 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;
+static u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu,
+                                     const struct sys_reg_desc *rd)
+{
+       u8 perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
+       u64 val = read_sanitised_ftr_reg(SYS_ID_DFR0_EL1);
 
-       if (valid_pmu)
-               vcpu->kvm->arch.dfr0_pmuver.imp = pmuver;
-       else
-               vcpu->kvm->arch.dfr0_pmuver.unimp = pmuver;
+       val &= ~ID_DFR0_EL1_PerfMon_MASK;
+       if (kvm_vcpu_has_pmu(vcpu))
+               val |= SYS_FIELD_PREP(ID_DFR0_EL1, PerfMon, perfmon);
 
-       return 0;
+       return val;
 }
 
 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;
+       u8 perfmon = SYS_FIELD_GET(ID_DFR0_EL1, PerfMon, val);
 
-       host_perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
+       if (perfmon == ID_DFR0_EL1_PerfMon_IMPDEF) {
+               val &= ~ID_DFR0_EL1_PerfMon_MASK;
+               perfmon = 0;
+       }
 
        /*
         * Allow DFR0_EL1.PerfMon to be set from userspace as long as
@@ -1444,29 +1548,10 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
         * 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))
+       if (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;
+       return set_id_reg(vcpu, rd, val);
 }
 
 /*
@@ -1479,18 +1564,60 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
 static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      u64 *val)
 {
+       /*
+        * Avoid locking if the VM has already started, as the ID registers are
+        * guaranteed to be invariant at that point.
+        */
+       if (kvm_vm_has_ran_once(vcpu->kvm)) {
+               *val = read_id_reg(vcpu, rd);
+               return 0;
+       }
+
+       mutex_lock(&vcpu->kvm->arch.config_lock);
        *val = read_id_reg(vcpu, rd);
+       mutex_unlock(&vcpu->kvm->arch.config_lock);
+
        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;
+       u32 id = reg_to_encoding(rd);
+       int ret;
 
-       return 0;
+       mutex_lock(&vcpu->kvm->arch.config_lock);
+
+       /*
+        * Once the VM has started the ID registers are immutable. Reject any
+        * write that does not match the final register value.
+        */
+       if (kvm_vm_has_ran_once(vcpu->kvm)) {
+               if (val != read_id_reg(vcpu, rd))
+                       ret = -EBUSY;
+               else
+                       ret = 0;
+
+               mutex_unlock(&vcpu->kvm->arch.config_lock);
+               return ret;
+       }
+
+       ret = arm64_check_features(vcpu, rd, val);
+       if (!ret)
+               IDREG(vcpu->kvm, id) = val;
+
+       mutex_unlock(&vcpu->kvm->arch.config_lock);
+
+       /*
+        * arm64_check_features() returns -E2BIG to indicate the register's
+        * feature set is a superset of the maximally-allowed register value.
+        * While it would be nice to precisely describe this to userspace, the
+        * existing UAPI for KVM_SET_ONE_REG has it that invalid register
+        * writes return -EINVAL.
+        */
+       if (ret == -E2BIG)
+               ret = -EINVAL;
+       return ret;
 }
 
 static int get_raz_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
@@ -1530,7 +1657,7 @@ static bool access_clidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
  * Fabricate a CLIDR_EL1 value instead of using the real value, which can vary
  * by the physical CPU which the vcpu currently resides in.
  */
-static void reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static u64 reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
        u64 clidr;
@@ -1578,6 +1705,8 @@ static void reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
                clidr |= 2 << CLIDR_TTYPE_SHIFT(loc);
 
        __vcpu_sys_reg(vcpu, r->reg) = clidr;
+
+       return __vcpu_sys_reg(vcpu, r->reg);
 }
 
 static int set_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
@@ -1677,6 +1806,17 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
        .visibility = elx2_visibility,          \
 }
 
+/*
+ * Since reset() callback and field val are not used for idregs, they will be
+ * used for specific purposes for idregs.
+ * The reset() would return KVM sanitised register value. The value would be the
+ * same as the host kernel sanitised value if there is no KVM sanitisation.
+ * The val would be used as a mask indicating writable fields for the idreg.
+ * Only bits with 1 are writable from userspace. This mask might not be
+ * necessary in the future whenever all ID registers are enabled as writable
+ * from userspace.
+ */
+
 /* sys_reg_desc initialiser for known cpufeature ID registers */
 #define ID_SANITISED(name) {                   \
        SYS_DESC(SYS_##name),                   \
@@ -1684,6 +1824,8 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
        .get_user = get_id_reg,                 \
        .set_user = set_id_reg,                 \
        .visibility = id_visibility,            \
+       .reset = kvm_read_sanitised_id_reg,     \
+       .val = 0,                               \
 }
 
 /* sys_reg_desc initialiser for known cpufeature ID registers */
@@ -1693,6 +1835,8 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
        .get_user = get_id_reg,                 \
        .set_user = set_id_reg,                 \
        .visibility = aa32_id_visibility,       \
+       .reset = kvm_read_sanitised_id_reg,     \
+       .val = 0,                               \
 }
 
 /*
@@ -1705,7 +1849,9 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
        .access = access_id_reg,                        \
        .get_user = get_id_reg,                         \
        .set_user = set_id_reg,                         \
-       .visibility = raz_visibility                    \
+       .visibility = raz_visibility,                   \
+       .reset = kvm_read_sanitised_id_reg,             \
+       .val = 0,                                       \
 }
 
 /*
@@ -1719,6 +1865,8 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
        .get_user = get_id_reg,                 \
        .set_user = set_id_reg,                 \
        .visibility = raz_visibility,           \
+       .reset = kvm_read_sanitised_id_reg,     \
+       .val = 0,                               \
 }
 
 static bool access_sp_el1(struct kvm_vcpu *vcpu,
@@ -1826,9 +1974,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        /* 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, },
+       { 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,
+         .reset = read_sanitised_id_dfr0_el1,
+         .val = ID_DFR0_EL1_PerfMon_MASK, },
        ID_HIDDEN(ID_AFR0_EL1),
        AA32_ID_SANITISED(ID_MMFR0_EL1),
        AA32_ID_SANITISED(ID_MMFR1_EL1),
@@ -1857,8 +2009,12 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
        /* 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, },
+       { SYS_DESC(SYS_ID_AA64PFR0_EL1),
+         .access = access_id_reg,
+         .get_user = get_id_reg,
+         .set_user = set_id_reg,
+         .reset = read_sanitised_id_aa64pfr0_el1,
+         .val = ID_AA64PFR0_EL1_CSV2_MASK | ID_AA64PFR0_EL1_CSV3_MASK, },
        ID_SANITISED(ID_AA64PFR1_EL1),
        ID_UNALLOCATED(4,2),
        ID_UNALLOCATED(4,3),
@@ -1868,8 +2024,12 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        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, },
+       { SYS_DESC(SYS_ID_AA64DFR0_EL1),
+         .access = access_id_reg,
+         .get_user = get_id_reg,
+         .set_user = set_id_aa64dfr0_el1,
+         .reset = read_sanitised_id_aa64dfr0_el1,
+         .val = ID_AA64DFR0_EL1_PMUVer_MASK, },
        ID_SANITISED(ID_AA64DFR1_EL1),
        ID_UNALLOCATED(5,2),
        ID_UNALLOCATED(5,3),
@@ -2203,7 +2363,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
        EL2_REG(HCR_EL2, access_rw, reset_val, 0),
        EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
-       EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_EL2_DEFAULT ),
+       EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
        EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
        EL2_REG(HACR_EL2, access_rw, reset_val, 0),
 
@@ -2260,6 +2420,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        EL2_REG(SP_EL2, NULL, reset_unknown, 0),
 };
 
+static const struct sys_reg_desc *first_idreg;
+
 static bool trap_dbgdidr(struct kvm_vcpu *vcpu,
                        struct sys_reg_params *p,
                        const struct sys_reg_desc *r)
@@ -2950,6 +3112,28 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu,
        return false;
 }
 
+static void kvm_reset_id_regs(struct kvm_vcpu *vcpu)
+{
+       const struct sys_reg_desc *idreg = first_idreg;
+       u32 id = reg_to_encoding(idreg);
+       struct kvm *kvm = vcpu->kvm;
+
+       if (test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
+               return;
+
+       lockdep_assert_held(&kvm->arch.config_lock);
+
+       /* Initialize all idregs */
+       while (is_id_reg(id)) {
+               IDREG(kvm, id) = idreg->reset(vcpu, idreg);
+
+               idreg++;
+               id = reg_to_encoding(idreg);
+       }
+
+       set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
+}
+
 /**
  * kvm_reset_sys_regs - sets system registers to reset value
  * @vcpu: The VCPU pointer
@@ -2961,9 +3145,17 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
 {
        unsigned long i;
 
-       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]);
+       kvm_reset_id_regs(vcpu);
+
+       for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) {
+               const struct sys_reg_desc *r = &sys_reg_descs[i];
+
+               if (is_id_reg(reg_to_encoding(r)))
+                       continue;
+
+               if (r->reset)
+                       r->reset(vcpu, r);
+       }
 }
 
 /**
@@ -3064,19 +3256,21 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id,
  */
 
 #define FUNCTION_INVARIANT(reg)                                                \
-       static void get_##reg(struct kvm_vcpu *v,                       \
+       static u64 get_##reg(struct kvm_vcpu *v,                        \
                              const struct sys_reg_desc *r)             \
        {                                                               \
                ((struct sys_reg_desc *)r)->val = read_sysreg(reg);     \
+               return ((struct sys_reg_desc *)r)->val;                 \
        }
 
 FUNCTION_INVARIANT(midr_el1)
 FUNCTION_INVARIANT(revidr_el1)
 FUNCTION_INVARIANT(aidr_el1)
 
-static void get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r)
+static u64 get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r)
 {
        ((struct sys_reg_desc *)r)->val = read_sanitised_ftr_reg(SYS_CTR_EL0);
+       return ((struct sys_reg_desc *)r)->val;
 }
 
 /* ->val is filled in by kvm_sys_reg_table_init() */
@@ -3368,6 +3562,7 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 
 int __init kvm_sys_reg_table_init(void)
 {
+       struct sys_reg_params params;
        bool valid = true;
        unsigned int i;
 
@@ -3386,5 +3581,11 @@ int __init kvm_sys_reg_table_init(void)
        for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
                invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);
 
+       /* Find the first idreg (SYS_ID_PFR0_EL1) in sys_reg_descs. */
+       params = encoding_to_params(SYS_ID_PFR0_EL1);
+       first_idreg = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+       if (!first_idreg)
+               return -EINVAL;
+
        return 0;
 }