arm64: KVM: Expose sanitised cache type register to guest
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Thu, 31 Jan 2019 13:17:17 +0000 (14:17 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Tue, 19 Feb 2019 21:05:48 +0000 (21:05 +0000)
We currently permit CPUs in the same system to deviate in the exact
topology of the caches, and we subsequently hide this fact from user
space by exposing a sanitised value of the cache type register CTR_EL0.

However, guests running under KVM see the bare value of CTR_EL0, which
could potentially result in issues with, e.g., JITs or other pieces of
code that are sensitive to misreported cache line sizes.

So let's start trapping cache ID instructions if there is a mismatch,
and expose the sanitised version of CTR_EL0 to guests. Note that CTR_EL0
is treated as an invariant to KVM user space, so update that part as well.

Acked-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kvm/sys_regs.c

index a0d1ce9ae12b3e9f2a0f504a7d30b3accca85f9d..9acccb1e3746394ac6575219bf57d7a345025048 100644 (file)
@@ -77,6 +77,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
         */
        if (!vcpu_el1_is_32bit(vcpu))
                vcpu->arch.hcr_el2 |= HCR_TID3;
+
+       if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE))
+               vcpu->arch.hcr_el2 |= HCR_TID2;
 }
 
 static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
index 6482e8bcf1b8f9ee4ffda2996a675c2b72ec487d..5b267dec6194e9675bb48f710a0d16b58eca3d64 100644 (file)
 
 #define SYS_CNTKCTL_EL1                        sys_reg(3, 0, 14, 1, 0)
 
+#define SYS_CCSIDR_EL1                 sys_reg(3, 1, 0, 0, 0)
 #define SYS_CLIDR_EL1                  sys_reg(3, 1, 0, 0, 1)
 #define SYS_AIDR_EL1                   sys_reg(3, 1, 0, 0, 7)
 
index 0d348500b24bbb45c51364e69e95048fddd2f2eb..45a07cfc57edb94902ec4b4438f31a7e078ca075 100644 (file)
@@ -1146,6 +1146,49 @@ static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
        return __set_id_reg(rd, uaddr, true);
 }
 
+static bool access_ctr(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_sanitised_ftr_reg(SYS_CTR_EL0);
+       return true;
+}
+
+static bool access_clidr(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_sysreg(clidr_el1);
+       return true;
+}
+
+static bool access_csselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+                         const struct sys_reg_desc *r)
+{
+       if (p->is_write)
+               vcpu_write_sys_reg(vcpu, p->regval, r->reg);
+       else
+               p->regval = vcpu_read_sys_reg(vcpu, r->reg);
+       return true;
+}
+
+static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+                         const struct sys_reg_desc *r)
+{
+       u32 csselr;
+
+       if (p->is_write)
+               return write_to_read_only(vcpu, p, r);
+
+       csselr = vcpu_read_sys_reg(vcpu, CSSELR_EL1);
+       p->regval = get_ccsidr(csselr);
+       return true;
+}
+
 /* sys_reg_desc initialiser for known cpufeature ID registers */
 #define ID_SANITISED(name) {                   \
        SYS_DESC(SYS_##name),                   \
@@ -1363,7 +1406,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
        { SYS_DESC(SYS_CNTKCTL_EL1), NULL, reset_val, CNTKCTL_EL1, 0},
 
-       { SYS_DESC(SYS_CSSELR_EL1), NULL, reset_unknown, CSSELR_EL1 },
+       { SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
+       { SYS_DESC(SYS_CLIDR_EL1), access_clidr },
+       { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
+       { SYS_DESC(SYS_CTR_EL0), access_ctr },
 
        { SYS_DESC(SYS_PMCR_EL0), access_pmcr, reset_pmcr, },
        { SYS_DESC(SYS_PMCNTENSET_EL0), access_pmcnten, reset_unknown, PMCNTENSET_EL0 },
@@ -1663,6 +1709,7 @@ static const struct sys_reg_desc cp14_64_regs[] = {
  * register).
  */
 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( 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 },
@@ -1779,6 +1826,10 @@ static const struct sys_reg_desc cp15_regs[] = {
        PMU_PMEVTYPER(30),
        /* PMCCFILTR */
        { Op1(0), CRn(14), CRm(15), Op2(7), access_pmu_evtyper },
+
+       { Op1(1), CRn( 0), CRm( 0), Op2(0), access_ccsidr },
+       { Op1(1), CRn( 0), CRm( 0), Op2(1), access_clidr },
+       { Op1(2), CRn( 0), CRm( 0), Op2(0), access_csselr, NULL, c0_CSSELR },
 };
 
 static const struct sys_reg_desc cp15_64_regs[] = {
@@ -2192,11 +2243,15 @@ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
        }
 
 FUNCTION_INVARIANT(midr_el1)
-FUNCTION_INVARIANT(ctr_el0)
 FUNCTION_INVARIANT(revidr_el1)
 FUNCTION_INVARIANT(clidr_el1)
 FUNCTION_INVARIANT(aidr_el1)
 
+static void 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);
+}
+
 /* ->val is filled in by kvm_sys_reg_table_init() */
 static struct sys_reg_desc invariant_sys_regs[] = {
        { SYS_DESC(SYS_MIDR_EL1), NULL, get_midr_el1 },