Merge tag 'kvmarm-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm...
[linux-2.6-microblaze.git] / arch / arm64 / kvm / sys_regs.c
index 138961d..077293b 100644 (file)
@@ -94,6 +94,7 @@ static bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
        case TPIDR_EL1:         *val = read_sysreg_s(SYS_TPIDR_EL1);    break;
        case AMAIR_EL1:         *val = read_sysreg_s(SYS_AMAIR_EL12);   break;
        case CNTKCTL_EL1:       *val = read_sysreg_s(SYS_CNTKCTL_EL12); break;
+       case ELR_EL1:           *val = read_sysreg_s(SYS_ELR_EL12);     break;
        case PAR_EL1:           *val = read_sysreg_s(SYS_PAR_EL1);      break;
        case DACR32_EL2:        *val = read_sysreg_s(SYS_DACR32_EL2);   break;
        case IFSR32_EL2:        *val = read_sysreg_s(SYS_IFSR32_EL2);   break;
@@ -133,6 +134,7 @@ static bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
        case TPIDR_EL1:         write_sysreg_s(val, SYS_TPIDR_EL1);     break;
        case AMAIR_EL1:         write_sysreg_s(val, SYS_AMAIR_EL12);    break;
        case CNTKCTL_EL1:       write_sysreg_s(val, SYS_CNTKCTL_EL12);  break;
+       case ELR_EL1:           write_sysreg_s(val, SYS_ELR_EL12);      break;
        case PAR_EL1:           write_sysreg_s(val, SYS_PAR_EL1);       break;
        case DACR32_EL2:        write_sysreg_s(val, SYS_DACR32_EL2);    break;
        case IFSR32_EL2:        write_sysreg_s(val, SYS_IFSR32_EL2);    break;
@@ -242,6 +244,25 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
        return true;
 }
 
+static bool access_actlr(struct kvm_vcpu *vcpu,
+                        struct sys_reg_params *p,
+                        const struct sys_reg_desc *r)
+{
+       if (p->is_write)
+               return ignore_write(vcpu, p);
+
+       p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
+
+       if (p->is_aarch32) {
+               if (r->Op2 & 2)
+                       p->regval = upper_32_bits(p->regval);
+               else
+                       p->regval = lower_32_bits(p->regval);
+       }
+
+       return true;
+}
+
 /*
  * Trap handler for the GICv3 SGI generation system register.
  * Forward the request to the VGIC emulation.
@@ -615,6 +636,12 @@ static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
        vcpu_write_sys_reg(vcpu, amair, AMAIR_EL1);
 }
 
+static void 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);
+}
+
 static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 mpidr;
@@ -1518,6 +1545,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        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 },
        { 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 },
@@ -1957,6 +1985,8 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 static const struct sys_reg_desc cp15_regs[] = {
        { Op1( 0), CRn( 0), CRm( 0), Op2( 1), access_ctr },
        { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, c1_SCTLR },
+       { Op1( 0), CRn( 1), CRm( 0), Op2( 1), access_actlr },
+       { Op1( 0), CRn( 1), CRm( 0), Op2( 3), access_actlr },
        { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
        { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
        { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
@@ -2109,36 +2139,6 @@ static int check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
        return 0;
 }
 
-/* Target specific emulation tables */
-static struct kvm_sys_reg_target_table *target_tables[KVM_ARM_NUM_TARGETS];
-
-void kvm_register_target_sys_reg_table(unsigned int target,
-                                      struct kvm_sys_reg_target_table *table)
-{
-       if (check_sysreg_table(table->table64.table, table->table64.num, false) ||
-           check_sysreg_table(table->table32.table, table->table32.num, true))
-               return;
-
-       target_tables[target] = table;
-}
-
-/* Get specific register table for this target. */
-static const struct sys_reg_desc *get_target_table(unsigned target,
-                                                  bool mode_is_64,
-                                                  size_t *num)
-{
-       struct kvm_sys_reg_target_table *table;
-
-       table = target_tables[target];
-       if (mode_is_64) {
-               *num = table->table64.num;
-               return table->table64.table;
-       } else {
-               *num = table->table32.num;
-               return table->table32.table;
-       }
-}
-
 static int match_sys_reg(const void *key, const void *elt)
 {
        const unsigned long pval = (unsigned long)key;
@@ -2220,10 +2220,10 @@ static int emulate_cp(struct kvm_vcpu *vcpu,
 static void unhandled_cp_access(struct kvm_vcpu *vcpu,
                                struct sys_reg_params *params)
 {
-       u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+       u8 esr_ec = kvm_vcpu_trap_get_class(vcpu);
        int cp = -1;
 
-       switch(hsr_ec) {
+       switch (esr_ec) {
        case ESR_ELx_EC_CP15_32:
        case ESR_ELx_EC_CP15_64:
                cp = 15;
@@ -2249,22 +2249,20 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu,
  */
 static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
                            const struct sys_reg_desc *global,
-                           size_t nr_global,
-                           const struct sys_reg_desc *target_specific,
-                           size_t nr_specific)
+                           size_t nr_global)
 {
        struct sys_reg_params params;
-       u32 hsr = kvm_vcpu_get_hsr(vcpu);
+       u32 esr = kvm_vcpu_get_esr(vcpu);
        int Rt = kvm_vcpu_sys_get_rt(vcpu);
-       int Rt2 = (hsr >> 10) & 0x1f;
+       int Rt2 = (esr >> 10) & 0x1f;
 
        params.is_aarch32 = true;
        params.is_32bit = false;
-       params.CRm = (hsr >> 1) & 0xf;
-       params.is_write = ((hsr & 1) == 0);
+       params.CRm = (esr >> 1) & 0xf;
+       params.is_write = ((esr & 1) == 0);
 
        params.Op0 = 0;
-       params.Op1 = (hsr >> 16) & 0xf;
+       params.Op1 = (esr >> 16) & 0xf;
        params.Op2 = 0;
        params.CRn = 0;
 
@@ -2278,14 +2276,11 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
        }
 
        /*
-        * Try to emulate the coprocessor access using the target
-        * specific table first, and using the global table afterwards.
-        * If either of the tables contains a handler, handle the
+        * If the table contains a handler, handle the
         * potential register operation in the case of a read and return
         * with success.
         */
-       if (!emulate_cp(vcpu, &params, target_specific, nr_specific) ||
-           !emulate_cp(vcpu, &params, global, nr_global)) {
+       if (!emulate_cp(vcpu, &params, global, nr_global)) {
                /* Split up the value between registers for the read side */
                if (!params.is_write) {
                        vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval));
@@ -2306,26 +2301,23 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
  */
 static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
                            const struct sys_reg_desc *global,
-                           size_t nr_global,
-                           const struct sys_reg_desc *target_specific,
-                           size_t nr_specific)
+                           size_t nr_global)
 {
        struct sys_reg_params params;
-       u32 hsr = kvm_vcpu_get_hsr(vcpu);
+       u32 esr = kvm_vcpu_get_esr(vcpu);
        int Rt  = kvm_vcpu_sys_get_rt(vcpu);
 
        params.is_aarch32 = true;
        params.is_32bit = true;
-       params.CRm = (hsr >> 1) & 0xf;
+       params.CRm = (esr >> 1) & 0xf;
        params.regval = vcpu_get_reg(vcpu, Rt);
-       params.is_write = ((hsr & 1) == 0);
-       params.CRn = (hsr >> 10) & 0xf;
+       params.is_write = ((esr & 1) == 0);
+       params.CRn = (esr >> 10) & 0xf;
        params.Op0 = 0;
-       params.Op1 = (hsr >> 14) & 0x7;
-       params.Op2 = (hsr >> 17) & 0x7;
+       params.Op1 = (esr >> 14) & 0x7;
+       params.Op2 = (esr >> 17) & 0x7;
 
-       if (!emulate_cp(vcpu, &params, target_specific, nr_specific) ||
-           !emulate_cp(vcpu, &params, global, nr_global)) {
+       if (!emulate_cp(vcpu, &params, global, nr_global)) {
                if (!params.is_write)
                        vcpu_set_reg(vcpu, Rt, params.regval);
                return 1;
@@ -2337,38 +2329,22 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
 
 int kvm_handle_cp15_64(struct kvm_vcpu *vcpu)
 {
-       const struct sys_reg_desc *target_specific;
-       size_t num;
-
-       target_specific = get_target_table(vcpu->arch.target, false, &num);
-       return kvm_handle_cp_64(vcpu,
-                               cp15_64_regs, ARRAY_SIZE(cp15_64_regs),
-                               target_specific, num);
+       return kvm_handle_cp_64(vcpu, cp15_64_regs, ARRAY_SIZE(cp15_64_regs));
 }
 
 int kvm_handle_cp15_32(struct kvm_vcpu *vcpu)
 {
-       const struct sys_reg_desc *target_specific;
-       size_t num;
-
-       target_specific = get_target_table(vcpu->arch.target, false, &num);
-       return kvm_handle_cp_32(vcpu,
-                               cp15_regs, ARRAY_SIZE(cp15_regs),
-                               target_specific, num);
+       return kvm_handle_cp_32(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs));
 }
 
 int kvm_handle_cp14_64(struct kvm_vcpu *vcpu)
 {
-       return kvm_handle_cp_64(vcpu,
-                               cp14_64_regs, ARRAY_SIZE(cp14_64_regs),
-                               NULL, 0);
+       return kvm_handle_cp_64(vcpu, cp14_64_regs, ARRAY_SIZE(cp14_64_regs));
 }
 
 int kvm_handle_cp14_32(struct kvm_vcpu *vcpu)
 {
-       return kvm_handle_cp_32(vcpu,
-                               cp14_regs, ARRAY_SIZE(cp14_regs),
-                               NULL, 0);
+       return kvm_handle_cp_32(vcpu, cp14_regs, ARRAY_SIZE(cp14_regs));
 }
 
 static bool is_imp_def_sys_reg(struct sys_reg_params *params)
@@ -2380,15 +2356,9 @@ static bool is_imp_def_sys_reg(struct sys_reg_params *params)
 static int emulate_sys_reg(struct kvm_vcpu *vcpu,
                           struct sys_reg_params *params)
 {
-       size_t num;
-       const struct sys_reg_desc *table, *r;
+       const struct sys_reg_desc *r;
 
-       table = get_target_table(vcpu->arch.target, true, &num);
-
-       /* Search target-specific then generic table. */
-       r = find_reg(params, table, num);
-       if (!r)
-               r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+       r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
 
        if (likely(r)) {
                perform_access(vcpu, params, r);
@@ -2403,14 +2373,20 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
        return 1;
 }
 
-static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
-                               const struct sys_reg_desc *table, size_t num)
+/**
+ * kvm_reset_sys_regs - sets system registers to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on the
+ * virtual CPU struct to their architecturally defined reset values.
+ */
+void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
 {
        unsigned long i;
 
-       for (i = 0; i < num; i++)
-               if (table[i].reset)
-                       table[i].reset(vcpu, &table[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]);
 }
 
 /**
@@ -2420,7 +2396,7 @@ static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
 int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)
 {
        struct sys_reg_params params;
-       unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+       unsigned long esr = kvm_vcpu_get_esr(vcpu);
        int Rt = kvm_vcpu_sys_get_rt(vcpu);
        int ret;
 
@@ -2491,8 +2467,7 @@ const struct sys_reg_desc *find_reg_by_id(u64 id,
 static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
                                                    u64 id)
 {
-       size_t num;
-       const struct sys_reg_desc *table, *r;
+       const struct sys_reg_desc *r;
        struct sys_reg_params params;
 
        /* We only do sys_reg for now. */
@@ -2502,10 +2477,7 @@ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
        if (!index_to_params(id, &params))
                return NULL;
 
-       table = get_target_table(vcpu->arch.target, true, &num);
-       r = find_reg(&params, table, num);
-       if (!r)
-               r = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+       r = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
 
        /* Not saved in the sys_reg array and not otherwise accessible? */
        if (r && !(r->reg || r->get_user))
@@ -2805,35 +2777,17 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
 /* Assumed ordered tables, see kvm_sys_reg_table_init. */
 static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
 {
-       const struct sys_reg_desc *i1, *i2, *end1, *end2;
+       const struct sys_reg_desc *i2, *end2;
        unsigned int total = 0;
-       size_t num;
        int err;
 
-       /* We check for duplicates here, to allow arch-specific overrides. */
-       i1 = get_target_table(vcpu->arch.target, true, &num);
-       end1 = i1 + num;
        i2 = sys_reg_descs;
        end2 = sys_reg_descs + ARRAY_SIZE(sys_reg_descs);
 
-       BUG_ON(i1 == end1 || i2 == end2);
-
-       /* Walk carefully, as both tables may refer to the same register. */
-       while (i1 || i2) {
-               int cmp = cmp_sys_reg(i1, i2);
-               /* target-specific overrides generic entry. */
-               if (cmp <= 0)
-                       err = walk_one_sys_reg(vcpu, i1, &uind, &total);
-               else
-                       err = walk_one_sys_reg(vcpu, i2, &uind, &total);
-
+       while (i2 != end2) {
+               err = walk_one_sys_reg(vcpu, i2++, &uind, &total);
                if (err)
                        return err;
-
-               if (cmp <= 0 && ++i1 == end1)
-                       i1 = NULL;
-               if (cmp >= 0 && ++i2 == end2)
-                       i2 = NULL;
        }
        return total;
 }
@@ -2900,22 +2854,3 @@ void kvm_sys_reg_table_init(void)
        /* Clear all higher bits. */
        cache_levels &= (1 << (i*3))-1;
 }
-
-/**
- * kvm_reset_sys_regs - sets system registers to reset value
- * @vcpu: The VCPU pointer
- *
- * This function finds the right table above and sets the registers on the
- * virtual CPU struct to their architecturally defined reset values.
- */
-void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
-{
-       size_t num;
-       const struct sys_reg_desc *table;
-
-       /* Generic chip reset first (so target could override). */
-       reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
-
-       table = get_target_table(vcpu->arch.target, true, &num);
-       reset_sys_reg_descs(vcpu, table, num);
-}