Merge tag 'v3.10.71' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / arch / arm / kvm / coproc.c
index db9cf692d4dded3e2a6cc7e5622ba90ee5bef2e8..7928dbdf210239a71f4f35e8ef289e9c2e8f0375 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/kvm_host.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
 #include <asm/cacheflush.h>
 #include <asm/cputype.h>
 #include <trace/events/kvm.h>
@@ -43,6 +44,31 @@ static u32 cache_levels;
 /* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
 #define CSSELR_MAX 12
 
+/*
+ * kvm_vcpu_arch.cp15 holds cp15 registers as an array of u32, but some
+ * of cp15 registers can be viewed either as couple of two u32 registers
+ * or one u64 register. Current u64 register encoding is that least
+ * significant u32 word is followed by most significant u32 word.
+ */
+static inline void vcpu_cp15_reg64_set(struct kvm_vcpu *vcpu,
+                                      const struct coproc_reg *r,
+                                      u64 val)
+{
+       vcpu->arch.cp15[r->reg] = val & 0xffffffff;
+       vcpu->arch.cp15[r->reg + 1] = val >> 32;
+}
+
+static inline u64 vcpu_cp15_reg64_get(struct kvm_vcpu *vcpu,
+                                     const struct coproc_reg *r)
+{
+       u64 val;
+
+       val = vcpu->arch.cp15[r->reg + 1];
+       val = val << 32;
+       val = val | vcpu->arch.cp15[r->reg];
+       return val;
+}
+
 int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        kvm_inject_undefined(vcpu);
@@ -71,6 +97,98 @@ int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
        return 1;
 }
 
+static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+       /*
+        * Compute guest MPIDR. We build a virtual cluster out of the
+        * vcpu_id, but we read the 'U' bit from the underlying
+        * hardware directly.
+        */
+       vcpu->arch.cp15[c0_MPIDR] = ((read_cpuid_mpidr() & MPIDR_SMP_BITMASK) |
+                                    ((vcpu->vcpu_id >> 2) << MPIDR_LEVEL_BITS) |
+                                    (vcpu->vcpu_id & 3));
+}
+
+/* TRM entries A7:4.3.31 A15:4.3.28 - RO WI */
+static bool access_actlr(struct kvm_vcpu *vcpu,
+                        const struct coproc_params *p,
+                        const struct coproc_reg *r)
+{
+       if (p->is_write)
+               return ignore_write(vcpu, p);
+
+       *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
+       return true;
+}
+
+/* TRM entries A7:4.3.56, A15:4.3.60 - R/O. */
+static bool access_cbar(struct kvm_vcpu *vcpu,
+                       const struct coproc_params *p,
+                       const struct coproc_reg *r)
+{
+       if (p->is_write)
+               return write_to_read_only(vcpu, p);
+       return read_zero(vcpu, p);
+}
+
+/* TRM entries A7:4.3.49, A15:4.3.48 - R/O WI */
+static bool access_l2ctlr(struct kvm_vcpu *vcpu,
+                         const struct coproc_params *p,
+                         const struct coproc_reg *r)
+{
+       if (p->is_write)
+               return ignore_write(vcpu, p);
+
+       *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
+       return true;
+}
+
+static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+       u32 l2ctlr, ncores;
+
+       asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
+       l2ctlr &= ~(3 << 24);
+       ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
+       /* How many cores in the current cluster and the next ones */
+       ncores -= (vcpu->vcpu_id & ~3);
+       /* Cap it to the maximum number of cores in a single cluster */
+       ncores = min(ncores, 3U);
+       l2ctlr |= (ncores & 3) << 24;
+
+       vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
+}
+
+static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+       u32 actlr;
+
+       /* ACTLR contains SMP bit: make sure you create all cpus first! */
+       asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
+       /* Make the SMP bit consistent with the guest configuration */
+       if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
+               actlr |= 1U << 6;
+       else
+               actlr &= ~(1U << 6);
+
+       vcpu->arch.cp15[c1_ACTLR] = actlr;
+}
+
+/*
+ * TRM entries: A7:4.3.50, A15:4.3.49
+ * R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored).
+ */
+static bool access_l2ectlr(struct kvm_vcpu *vcpu,
+                          const struct coproc_params *p,
+                          const struct coproc_reg *r)
+{
+       if (p->is_write)
+               return ignore_write(vcpu, p);
+
+       *vcpu_reg(vcpu, p->Rt1) = 0;
+       return true;
+}
+
 /* See note at ARM ARM B1.14.4 */
 static bool access_dcsw(struct kvm_vcpu *vcpu,
                        const struct coproc_params *p,
@@ -112,6 +230,44 @@ done:
        return true;
 }
 
+/*
+ * Generic accessor for VM registers. Only called as long as HCR_TVM
+ * is set.
+ */
+static bool access_vm_reg(struct kvm_vcpu *vcpu,
+                         const struct coproc_params *p,
+                         const struct coproc_reg *r)
+{
+       BUG_ON(!p->is_write);
+
+       vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1);
+       if (p->is_64bit)
+               vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2);
+
+       return true;
+}
+
+/*
+ * SCTLR accessor. Only called as long as HCR_TVM is set.  If the
+ * guest enables the MMU, we stop trapping the VM sys_regs and leave
+ * it in complete control of the caches.
+ *
+ * Used by the cpu-specific code.
+ */
+bool access_sctlr(struct kvm_vcpu *vcpu,
+                 const struct coproc_params *p,
+                 const struct coproc_reg *r)
+{
+       access_vm_reg(vcpu, p, r);
+
+       if (vcpu_has_cache_enabled(vcpu)) {     /* MMU+Caches enabled? */
+               vcpu->arch.hcr &= ~HCR_TVM;
+               stage2_flush_vm(vcpu->kvm);
+       }
+
+       return true;
+}
+
 /*
  * We could trap ID_DFR0 and tell the guest we don't support performance
  * monitoring.  Unfortunately the patch to make the kernel check ID_DFR0 was
@@ -153,37 +309,52 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
  *            registers preceding 32-bit ones.
  */
 static const struct coproc_reg cp15_regs[] = {
+       /* MPIDR: we use VMPIDR for guest access. */
+       { CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
+                       NULL, reset_mpidr, c0_MPIDR },
+
        /* CSSELR: swapped by interrupt.S. */
        { CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32,
                        NULL, reset_unknown, c0_CSSELR },
 
-       /* TTBR0/TTBR1: swapped by interrupt.S. */
-       { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
-       { CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
+       /* ACTLR: trapped by HCR.TAC bit. */
+       { CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
+                       access_actlr, reset_actlr, c1_ACTLR },
 
-       /* TTBCR: swapped by interrupt.S. */
+       /* CPACR: swapped by interrupt.S. */
+       { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
+                       NULL, reset_val, c1_CPACR, 0x00000000 },
+
+       /* TTBR0/TTBR1/TTBCR: swapped by interrupt.S. */
+       { CRm64( 2), Op1( 0), is64, access_vm_reg, reset_unknown64, c2_TTBR0 },
+       { CRn(2), CRm( 0), Op1( 0), Op2( 0), is32,
+                       access_vm_reg, reset_unknown, c2_TTBR0 },
+       { CRn(2), CRm( 0), Op1( 0), Op2( 1), is32,
+                       access_vm_reg, reset_unknown, c2_TTBR1 },
        { CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
-                       NULL, reset_val, c2_TTBCR, 0x00000000 },
+                       access_vm_reg, reset_val, c2_TTBCR, 0x00000000 },
+       { CRm64( 2), Op1( 1), is64, access_vm_reg, reset_unknown64, c2_TTBR1 },
+
 
        /* DACR: swapped by interrupt.S. */
        { CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32,
-                       NULL, reset_unknown, c3_DACR },
+                       access_vm_reg, reset_unknown, c3_DACR },
 
        /* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */
        { CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32,
-                       NULL, reset_unknown, c5_DFSR },
+                       access_vm_reg, reset_unknown, c5_DFSR },
        { CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32,
-                       NULL, reset_unknown, c5_IFSR },
+                       access_vm_reg, reset_unknown, c5_IFSR },
        { CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32,
-                       NULL, reset_unknown, c5_ADFSR },
+                       access_vm_reg, reset_unknown, c5_ADFSR },
        { CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32,
-                       NULL, reset_unknown, c5_AIFSR },
+                       access_vm_reg, reset_unknown, c5_AIFSR },
 
        /* DFAR/IFAR: swapped by interrupt.S. */
        { CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32,
-                       NULL, reset_unknown, c6_DFAR },
+                       access_vm_reg, reset_unknown, c6_DFAR },
        { CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
-                       NULL, reset_unknown, c6_IFAR },
+                       access_vm_reg, reset_unknown, c6_IFAR },
 
        /* PAR swapped by interrupt.S */
        { CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
@@ -194,6 +365,13 @@ static const struct coproc_reg cp15_regs[] = {
        { CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw},
        { CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw},
        { CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw},
+       /*
+        * L2CTLR access (guest wants to know #CPUs).
+        */
+       { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
+                       access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
+       { CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
+
        /*
         * Dummy performance monitor implementation.
         */
@@ -213,9 +391,15 @@ static const struct coproc_reg cp15_regs[] = {
 
        /* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */
        { CRn(10), CRm( 2), Op1( 0), Op2( 0), is32,
-                       NULL, reset_unknown, c10_PRRR},
+                       access_vm_reg, reset_unknown, c10_PRRR},
        { CRn(10), CRm( 2), Op1( 0), Op2( 1), is32,
-                       NULL, reset_unknown, c10_NMRR},
+                       access_vm_reg, reset_unknown, c10_NMRR},
+
+       /* AMAIR0/AMAIR1: swapped by interrupt.S. */
+       { CRn(10), CRm( 3), Op1( 0), Op2( 0), is32,
+                       access_vm_reg, reset_unknown, c10_AMAIR0},
+       { CRn(10), CRm( 3), Op1( 0), Op2( 1), is32,
+                       access_vm_reg, reset_unknown, c10_AMAIR1},
 
        /* VBAR: swapped by interrupt.S. */
        { CRn(12), CRm( 0), Op1( 0), Op2( 0), is32,
@@ -223,7 +407,7 @@ static const struct coproc_reg cp15_regs[] = {
 
        /* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */
        { CRn(13), CRm( 0), Op1( 0), Op2( 1), is32,
-                       NULL, reset_val, c13_CID, 0x00000000 },
+                       access_vm_reg, reset_val, c13_CID, 0x00000000 },
        { CRn(13), CRm( 0), Op1( 0), Op2( 2), is32,
                        NULL, reset_unknown, c13_TID_URW },
        { CRn(13), CRm( 0), Op1( 0), Op2( 3), is32,
@@ -234,6 +418,9 @@ static const struct coproc_reg cp15_regs[] = {
        /* CNTKCTL: swapped by interrupt.S. */
        { CRn(14), CRm( 1), Op1( 0), Op2( 0), is32,
                        NULL, reset_val, c14_CNTKCTL, 0x00000000 },
+
+       /* The Configuration Base Address Register. */
+       { CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
 };
 
 /* Target specific emulation tables */
@@ -241,6 +428,12 @@ static struct kvm_coproc_target_table *target_tables[KVM_ARM_NUM_TARGETS];
 
 void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table)
 {
+       unsigned int i;
+
+       for (i = 1; i < table->num; i++)
+               BUG_ON(cmp_reg(&table->table[i-1],
+                              &table->table[i]) >= 0);
+
        target_tables[table->target] = table;
 }
 
@@ -323,7 +516,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
        struct coproc_params params;
 
-       params.CRm = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
+       params.CRn = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
        params.Rt1 = (kvm_vcpu_get_hsr(vcpu) >> 5) & 0xf;
        params.is_write = ((kvm_vcpu_get_hsr(vcpu) & 1) == 0);
        params.is_64bit = true;
@@ -331,7 +524,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
        params.Op1 = (kvm_vcpu_get_hsr(vcpu) >> 16) & 0xf;
        params.Op2 = 0;
        params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf;
-       params.CRn = 0;
+       params.CRm = 0;
 
        return emulate_cp15(vcpu, &params);
 }
@@ -514,17 +707,23 @@ static struct coproc_reg invariant_cp15[] = {
        { CRn( 0), CRm( 0), Op1( 1), Op2( 7), is32, NULL, get_AIDR },
 };
 
+/*
+ * Reads a register value from a userspace address to a kernel
+ * variable. Make sure that register size matches sizeof(*__val).
+ */
 static int reg_from_user(void *val, const void __user *uaddr, u64 id)
 {
-       /* This Just Works because we are little endian. */
        if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
                return -EFAULT;
        return 0;
 }
 
+/*
+ * Writes a register value to a userspace address from a kernel variable.
+ * Make sure that register size matches sizeof(*__val).
+ */
 static int reg_to_user(void __user *uaddr, const void *val, u64 id)
 {
-       /* This Just Works because we are little endian. */
        if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0)
                return -EFAULT;
        return 0;
@@ -534,6 +733,7 @@ static int get_invariant_cp15(u64 id, void __user *uaddr)
 {
        struct coproc_params params;
        const struct coproc_reg *r;
+       int ret;
 
        if (!index_to_params(id, &params))
                return -ENOENT;
@@ -542,7 +742,15 @@ static int get_invariant_cp15(u64 id, void __user *uaddr)
        if (!r)
                return -ENOENT;
 
-       return reg_to_user(uaddr, &r->val, id);
+       ret = -ENOENT;
+       if (KVM_REG_SIZE(id) == 4) {
+               u32 val = r->val;
+
+               ret = reg_to_user(uaddr, &val, id);
+       } else if (KVM_REG_SIZE(id) == 8) {
+               ret = reg_to_user(uaddr, &r->val, id);
+       }
+       return ret;
 }
 
 static int set_invariant_cp15(u64 id, void __user *uaddr)
@@ -550,7 +758,7 @@ static int set_invariant_cp15(u64 id, void __user *uaddr)
        struct coproc_params params;
        const struct coproc_reg *r;
        int err;
-       u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
+       u64 val;
 
        if (!index_to_params(id, &params))
                return -ENOENT;
@@ -558,7 +766,16 @@ static int set_invariant_cp15(u64 id, void __user *uaddr)
        if (!r)
                return -ENOENT;
 
-       err = reg_from_user(&val, uaddr, id);
+       err = -ENOENT;
+       if (KVM_REG_SIZE(id) == 4) {
+               u32 val32;
+
+               err = reg_from_user(&val32, uaddr, id);
+               if (!err)
+                       val = val32;
+       } else if (KVM_REG_SIZE(id) == 8) {
+               err = reg_from_user(&val, uaddr, id);
+       }
        if (err)
                return err;
 
@@ -574,7 +791,7 @@ static bool is_valid_cache(u32 val)
        u32 level, ctype;
 
        if (val >= CSSELR_MAX)
-               return -ENOENT;
+               return false;
 
        /* Bottom bit is Instruction or Data bit.  Next 3 bits are level. */
         level = (val >> 1);
@@ -836,6 +1053,7 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
        const struct coproc_reg *r;
        void __user *uaddr = (void __user *)(long)reg->addr;
+       int ret;
 
        if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
                return demux_c15_get(reg->id, uaddr);
@@ -847,14 +1065,24 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        if (!r)
                return get_invariant_cp15(reg->id, uaddr);
 
-       /* Note: copies two regs if size is 64 bit. */
-       return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
+       ret = -ENOENT;
+       if (KVM_REG_SIZE(reg->id) == 8) {
+               u64 val;
+
+               val = vcpu_cp15_reg64_get(vcpu, r);
+               ret = reg_to_user(uaddr, &val, reg->id);
+       } else if (KVM_REG_SIZE(reg->id) == 4) {
+               ret = reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
+       }
+
+       return ret;
 }
 
 int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
        const struct coproc_reg *r;
        void __user *uaddr = (void __user *)(long)reg->addr;
+       int ret;
 
        if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
                return demux_c15_set(reg->id, uaddr);
@@ -866,8 +1094,18 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        if (!r)
                return set_invariant_cp15(reg->id, uaddr);
 
-       /* Note: copies two regs if size is 64 bit */
-       return reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id);
+       ret = -ENOENT;
+       if (KVM_REG_SIZE(reg->id) == 8) {
+               u64 val;
+
+               ret = reg_from_user(&val, uaddr, reg->id);
+               if (!ret)
+                       vcpu_cp15_reg64_set(vcpu, r, val);
+       } else if (KVM_REG_SIZE(reg->id) == 4) {
+               ret = reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id);
+       }
+
+       return ret;
 }
 
 static unsigned int num_demux_regs(void)