KVM: arm64: Handle SCXTNUM_ELx traps
[linux-2.6-microblaze.git] / arch / arm64 / kvm / sys_regs.c
index 9ca2706..c1726fb 100644 (file)
@@ -769,10 +769,7 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        if (pmu_access_el0_disabled(vcpu))
                return false;
 
-       if (!(p->Op2 & 1))
-               pmceid = read_sysreg(pmceid0_el0);
-       else
-               pmceid = read_sysreg(pmceid1_el0);
+       pmceid = kvm_pmu_get_pmceid(vcpu, (p->Op2 & 1));
 
        p->regval = pmceid;
 
@@ -1041,8 +1038,8 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        { SYS_DESC(SYS_PMEVTYPERn_EL0(n)),                                      \
          access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
 
-static bool access_amu(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
-                            const struct sys_reg_desc *r)
+static bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+                        const struct sys_reg_desc *r)
 {
        kvm_inject_undefined(vcpu);
 
@@ -1050,33 +1047,25 @@ static bool access_amu(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 }
 
 /* Macro to expand the AMU counter and type registers*/
-#define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), access_amu }
-#define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), access_amu }
-#define AMU_AMEVCNTR1_EL0(n) { SYS_DESC(SYS_AMEVCNTR1_EL0(n)), access_amu }
-#define AMU_AMEVTYPER1_EL0(n) { SYS_DESC(SYS_AMEVTYPER1_EL0(n)), access_amu }
-
-static bool trap_ptrauth(struct kvm_vcpu *vcpu,
-                        struct sys_reg_params *p,
-                        const struct sys_reg_desc *rd)
-{
-       /*
-        * If we land here, that is because we didn't fixup the access on exit
-        * by allowing the PtrAuth sysregs. The only way this happens is when
-        * the guest does not have PtrAuth support enabled.
-        */
-       kvm_inject_undefined(vcpu);
-
-       return false;
-}
+#define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), undef_access }
+#define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), undef_access }
+#define AMU_AMEVCNTR1_EL0(n) { SYS_DESC(SYS_AMEVCNTR1_EL0(n)), undef_access }
+#define AMU_AMEVTYPER1_EL0(n) { SYS_DESC(SYS_AMEVTYPER1_EL0(n)), undef_access }
 
 static unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu,
                        const struct sys_reg_desc *rd)
 {
-       return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN_USER | REG_HIDDEN_GUEST;
+       return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN;
 }
 
+/*
+ * If we land here on a PtrAuth access, that is because we didn't
+ * fixup the access on exit by allowing the PtrAuth sysregs. The only
+ * way this happens is when the guest does not have PtrAuth support
+ * enabled.
+ */
 #define __PTRAUTH_KEY(k)                                               \
-       { SYS_DESC(SYS_## k), trap_ptrauth, reset_unknown, k,           \
+       { SYS_DESC(SYS_## k), undef_access, reset_unknown, k,           \
        .visibility = ptrauth_visibility}
 
 #define PTRAUTH_KEY(k)                                                 \
@@ -1131,9 +1120,8 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                if (!vcpu_has_sve(vcpu))
                        val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
                val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT);
-               if (!(val & (0xfUL << ID_AA64PFR0_CSV2_SHIFT)) &&
-                   arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED)
-                       val |= (1UL << ID_AA64PFR0_CSV2_SHIFT);
+               val &= ~(0xfUL << ID_AA64PFR0_CSV2_SHIFT);
+               val |= ((u64)vcpu->kvm->arch.pfr0_csv2 << ID_AA64PFR0_CSV2_SHIFT);
        } else if (id == SYS_ID_AA64PFR1_EL1) {
                val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT);
        } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) {
@@ -1156,6 +1144,22 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
        return val;
 }
 
+static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
+                                 const struct sys_reg_desc *r)
+{
+       u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
+                        (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
+
+       switch (id) {
+       case SYS_ID_AA64ZFR0_EL1:
+               if (!vcpu_has_sve(vcpu))
+                       return REG_RAZ;
+               break;
+       }
+
+       return 0;
+}
+
 /* cpufeature ID register access trap handlers */
 
 static bool __access_id_reg(struct kvm_vcpu *vcpu,
@@ -1174,7 +1178,9 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
                          struct sys_reg_params *p,
                          const struct sys_reg_desc *r)
 {
-       return __access_id_reg(vcpu, p, r, false);
+       bool raz = sysreg_visible_as_raz(vcpu, r);
+
+       return __access_id_reg(vcpu, p, r, raz);
 }
 
 static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
@@ -1195,71 +1201,40 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
        if (vcpu_has_sve(vcpu))
                return 0;
 
-       return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
-}
-
-/* Visibility overrides for SVE-specific ID registers */
-static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
-                                     const struct sys_reg_desc *rd)
-{
-       if (vcpu_has_sve(vcpu))
-               return 0;
-
-       return REG_HIDDEN_USER;
-}
-
-/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
-static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
-{
-       if (!vcpu_has_sve(vcpu))
-               return 0;
-
-       return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
-}
-
-static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
-                                  struct sys_reg_params *p,
-                                  const struct sys_reg_desc *rd)
-{
-       if (p->is_write)
-               return write_to_read_only(vcpu, p, rd);
-
-       p->regval = guest_id_aa64zfr0_el1(vcpu);
-       return true;
-}
-
-static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
-               const struct sys_reg_desc *rd,
-               const struct kvm_one_reg *reg, void __user *uaddr)
-{
-       u64 val;
-
-       if (WARN_ON(!vcpu_has_sve(vcpu)))
-               return -ENOENT;
-
-       val = guest_id_aa64zfr0_el1(vcpu);
-       return reg_to_user(uaddr, &val, reg->id);
+       return REG_HIDDEN;
 }
 
-static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
-               const struct sys_reg_desc *rd,
-               const struct kvm_one_reg *reg, void __user *uaddr)
+static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
+                              const struct sys_reg_desc *rd,
+                              const struct kvm_one_reg *reg, void __user *uaddr)
 {
        const u64 id = sys_reg_to_index(rd);
        int err;
        u64 val;
-
-       if (WARN_ON(!vcpu_has_sve(vcpu)))
-               return -ENOENT;
+       u8 csv2;
 
        err = reg_from_user(&val, uaddr, id);
        if (err)
                return err;
 
-       /* This is what we mean by invariant: you can't change it. */
-       if (val != guest_id_aa64zfr0_el1(vcpu))
+       /*
+        * 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_CSV2_SHIFT);
+       if (csv2 > 1 ||
+           (csv2 && arm64_get_spectre_v2_state() != SPECTRE_UNAFFECTED))
                return -EINVAL;
 
+       /* We can only differ with CSV2, and anything else is an error */
+       val ^= read_id_reg(vcpu, rd, false);
+       val &= ~(0xFUL << ID_AA64PFR0_CSV2_SHIFT);
+       if (val)
+               return -EINVAL;
+
+       vcpu->kvm->arch.pfr0_csv2 = csv2;
+
        return 0;
 }
 
@@ -1302,13 +1277,17 @@ static int __set_id_reg(const struct kvm_vcpu *vcpu,
 static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __get_id_reg(vcpu, rd, uaddr, false);
+       bool raz = sysreg_visible_as_raz(vcpu, rd);
+
+       return __get_id_reg(vcpu, rd, uaddr, raz);
 }
 
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __set_id_reg(vcpu, rd, uaddr, false);
+       bool raz = sysreg_visible_as_raz(vcpu, rd);
+
+       return __set_id_reg(vcpu, rd, uaddr, raz);
 }
 
 static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
@@ -1387,19 +1366,13 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        return true;
 }
 
-static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
-                           const struct sys_reg_desc *r)
-{
-       kvm_inject_undefined(vcpu);
-       return false;
-}
-
 /* 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,            \
 }
 
 /*
@@ -1517,11 +1490,12 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
        /* AArch64 ID registers */
        /* CRm=4 */
-       ID_SANITISED(ID_AA64PFR0_EL1),
+       { 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),
-       { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
+       ID_SANITISED(ID_AA64ZFR0_EL1),
        ID_UNALLOCATED(4,5),
        ID_UNALLOCATED(4,6),
        ID_UNALLOCATED(4,7),
@@ -1560,8 +1534,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_ACTLR_EL1), access_actlr, reset_actlr, ACTLR_EL1 },
        { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
 
-       { SYS_DESC(SYS_RGSR_EL1), access_mte_regs },
-       { SYS_DESC(SYS_GCR_EL1), access_mte_regs },
+       { SYS_DESC(SYS_RGSR_EL1), undef_access },
+       { SYS_DESC(SYS_GCR_EL1), undef_access },
 
        { SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
        { SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
@@ -1587,8 +1561,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_ERXMISC0_EL1), trap_raz_wi },
        { SYS_DESC(SYS_ERXMISC1_EL1), trap_raz_wi },
 
-       { SYS_DESC(SYS_TFSR_EL1), access_mte_regs },
-       { SYS_DESC(SYS_TFSRE0_EL1), access_mte_regs },
+       { SYS_DESC(SYS_TFSR_EL1), undef_access },
+       { SYS_DESC(SYS_TFSRE0_EL1), undef_access },
 
        { SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
        { SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
@@ -1624,6 +1598,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
        { SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
 
+       { SYS_DESC(SYS_SCXTNUM_EL1), undef_access },
+
        { SYS_DESC(SYS_CNTKCTL_EL1), NULL, reset_val, CNTKCTL_EL1, 0},
 
        { SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
@@ -1652,14 +1628,16 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
        { SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
 
-       { SYS_DESC(SYS_AMCR_EL0), access_amu },
-       { SYS_DESC(SYS_AMCFGR_EL0), access_amu },
-       { SYS_DESC(SYS_AMCGCR_EL0), access_amu },
-       { SYS_DESC(SYS_AMUSERENR_EL0), access_amu },
-       { SYS_DESC(SYS_AMCNTENCLR0_EL0), access_amu },
-       { SYS_DESC(SYS_AMCNTENSET0_EL0), access_amu },
-       { SYS_DESC(SYS_AMCNTENCLR1_EL0), access_amu },
-       { SYS_DESC(SYS_AMCNTENSET1_EL0), access_amu },
+       { SYS_DESC(SYS_SCXTNUM_EL0), undef_access },
+
+       { SYS_DESC(SYS_AMCR_EL0), undef_access },
+       { SYS_DESC(SYS_AMCFGR_EL0), undef_access },
+       { SYS_DESC(SYS_AMCGCR_EL0), undef_access },
+       { SYS_DESC(SYS_AMUSERENR_EL0), undef_access },
+       { SYS_DESC(SYS_AMCNTENCLR0_EL0), undef_access },
+       { SYS_DESC(SYS_AMCNTENSET0_EL0), undef_access },
+       { SYS_DESC(SYS_AMCNTENCLR1_EL0), undef_access },
+       { SYS_DESC(SYS_AMCNTENSET1_EL0), undef_access },
        AMU_AMEVCNTR0_EL0(0),
        AMU_AMEVCNTR0_EL0(1),
        AMU_AMEVCNTR0_EL0(2),
@@ -1900,9 +1878,9 @@ static const struct sys_reg_desc cp14_regs[] = {
        { Op1( 0), CRn( 0), CRm( 1), Op2( 0), trap_raz_wi },
        DBG_BCR_BVR_WCR_WVR(1),
        /* DBGDCCINT */
-       { Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32 },
+       { Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32, NULL, cp14_DBGDCCINT },
        /* DBGDSCRext */
-       { Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32 },
+       { Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32, NULL, cp14_DBGDSCRext },
        DBG_BCR_BVR_WCR_WVR(2),
        /* DBGDTR[RT]Xint */
        { Op1( 0), CRn( 0), CRm( 3), Op2( 0), trap_raz_wi },
@@ -1917,7 +1895,7 @@ static const struct sys_reg_desc cp14_regs[] = {
        { Op1( 0), CRn( 0), CRm( 6), Op2( 2), trap_raz_wi },
        DBG_BCR_BVR_WCR_WVR(6),
        /* DBGVCR */
-       { Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32 },
+       { Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32, NULL, cp14_DBGVCR },
        DBG_BCR_BVR_WCR_WVR(7),
        DBG_BCR_BVR_WCR_WVR(8),
        DBG_BCR_BVR_WCR_WVR(9),
@@ -2188,7 +2166,7 @@ static void perform_access(struct kvm_vcpu *vcpu,
        trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
 
        /* Check for regs disabled by runtime config */
-       if (sysreg_hidden_from_guest(vcpu, r)) {
+       if (sysreg_hidden(vcpu, r)) {
                kvm_inject_undefined(vcpu);
                return;
        }
@@ -2687,7 +2665,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
                return get_invariant_sys_reg(reg->id, uaddr);
 
        /* Check for regs disabled by runtime config */
-       if (sysreg_hidden_from_user(vcpu, r))
+       if (sysreg_hidden(vcpu, r))
                return -ENOENT;
 
        if (r->get_user)
@@ -2712,7 +2690,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
                return set_invariant_sys_reg(reg->id, uaddr);
 
        /* Check for regs disabled by runtime config */
-       if (sysreg_hidden_from_user(vcpu, r))
+       if (sysreg_hidden(vcpu, r))
                return -ENOENT;
 
        if (r->set_user)
@@ -2783,7 +2761,7 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
        if (!(rd->reg || rd->get_user))
                return 0;
 
-       if (sysreg_hidden_from_user(vcpu, rd))
+       if (sysreg_hidden(vcpu, rd))
                return 0;
 
        if (!copy_reg_to_user(rd, uind))