arm64/kvm: disable access to AMU registers from kvm guests
authorIonela Voinescu <ionela.voinescu@arm.com>
Thu, 5 Mar 2020 09:06:23 +0000 (09:06 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 6 Mar 2020 16:02:50 +0000 (16:02 +0000)
Access to the AMU counters should be disabled by default in kvm guests,
as information from the counters might reveal activity in other guests
or activity on the host.

Therefore, disable access to AMU registers from EL0 and EL1 in kvm
guests by:
 - Hiding the presence of the extension in the feature register
   (SYS_ID_AA64PFR0_EL1) on the VCPU.
 - Disabling access to the AMU registers before switching to the guest.
 - Trapping accesses and injecting an undefined instruction into the
   guest.

Signed-off-by: Ionela Voinescu <ionela.voinescu@arm.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: Valentin Schneider <valentin.schneider@arm.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Julien Thierry <julien.thierry.kdev@gmail.com>
Cc: James Morse <james.morse@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/kvm_arm.h
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/sys_regs.c

index 6e5d839f42b580821f04fe60fdc0ba6b87370965..51c1d9918999205d9034781f5ea8a68a335201b2 100644 (file)
 
 /* Hyp Coprocessor Trap Register */
 #define CPTR_EL2_TCPAC (1 << 31)
+#define CPTR_EL2_TAM   (1 << 30)
 #define CPTR_EL2_TTA   (1 << 20)
 #define CPTR_EL2_TFP   (1 << CPTR_EL2_TFP_SHIFT)
 #define CPTR_EL2_TZ    (1 << 8)
index dfe8dd1725128405a1661a946782d812695d2d15..46292a37078167553912b0b77ad1b6d0e17da876 100644 (file)
@@ -98,6 +98,18 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
        val = read_sysreg(cpacr_el1);
        val |= CPACR_EL1_TTA;
        val &= ~CPACR_EL1_ZEN;
+
+       /*
+        * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to
+        * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2,
+        * except for some missing controls, such as TAM.
+        * In this case, CPTR_EL2.TAM has the same position with or without
+        * VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM
+        * shift value for trapping the AMU accesses.
+        */
+
+       val |= CPTR_EL2_TAM;
+
        if (update_fp_enabled(vcpu)) {
                if (vcpu_has_sve(vcpu))
                        val |= CPACR_EL1_ZEN;
@@ -119,7 +131,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
        __activate_traps_common(vcpu);
 
        val = CPTR_EL2_DEFAULT;
-       val |= CPTR_EL2_TTA | CPTR_EL2_TZ;
+       val |= CPTR_EL2_TTA | CPTR_EL2_TZ | CPTR_EL2_TAM;
        if (!update_fp_enabled(vcpu)) {
                val |= CPTR_EL2_TFP;
                __activate_traps_fpsimd32(vcpu);
index 3e909b117f0cd8e5bb704463c363e9ba23fb6041..44354c812783da8d64e3f597b9d691b7ea74a6db 100644 (file)
@@ -1003,6 +1003,20 @@ 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)
+{
+       kvm_inject_undefined(vcpu);
+
+       return false;
+}
+
+/* Macro to expand the AMU counter and type registers*/
+#define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), access_amu }
+#define AMU_AMEVTYPE0_EL0(n) { SYS_DESC(SYS_AMEVTYPE0_EL0(n)), access_amu }
+#define AMU_AMEVCNTR1_EL0(n) { SYS_DESC(SYS_AMEVCNTR1_EL0(n)), access_amu }
+#define AMU_AMEVTYPE1_EL0(n) { SYS_DESC(SYS_AMEVTYPE1_EL0(n)), access_amu }
+
 static bool trap_ptrauth(struct kvm_vcpu *vcpu,
                         struct sys_reg_params *p,
                         const struct sys_reg_desc *rd)
@@ -1078,8 +1092,10 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                         (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
        u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
 
-       if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
-               val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
+       if (id == SYS_ID_AA64PFR0_EL1) {
+               if (!vcpu_has_sve(vcpu))
+                       val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
+               val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT);
        } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) {
                val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) |
                         (0xfUL << ID_AA64ISAR1_API_SHIFT) |
@@ -1565,6 +1581,79 @@ 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 },
+       AMU_AMEVCNTR0_EL0(0),
+       AMU_AMEVCNTR0_EL0(1),
+       AMU_AMEVCNTR0_EL0(2),
+       AMU_AMEVCNTR0_EL0(3),
+       AMU_AMEVCNTR0_EL0(4),
+       AMU_AMEVCNTR0_EL0(5),
+       AMU_AMEVCNTR0_EL0(6),
+       AMU_AMEVCNTR0_EL0(7),
+       AMU_AMEVCNTR0_EL0(8),
+       AMU_AMEVCNTR0_EL0(9),
+       AMU_AMEVCNTR0_EL0(10),
+       AMU_AMEVCNTR0_EL0(11),
+       AMU_AMEVCNTR0_EL0(12),
+       AMU_AMEVCNTR0_EL0(13),
+       AMU_AMEVCNTR0_EL0(14),
+       AMU_AMEVCNTR0_EL0(15),
+       AMU_AMEVTYPE0_EL0(0),
+       AMU_AMEVTYPE0_EL0(1),
+       AMU_AMEVTYPE0_EL0(2),
+       AMU_AMEVTYPE0_EL0(3),
+       AMU_AMEVTYPE0_EL0(4),
+       AMU_AMEVTYPE0_EL0(5),
+       AMU_AMEVTYPE0_EL0(6),
+       AMU_AMEVTYPE0_EL0(7),
+       AMU_AMEVTYPE0_EL0(8),
+       AMU_AMEVTYPE0_EL0(9),
+       AMU_AMEVTYPE0_EL0(10),
+       AMU_AMEVTYPE0_EL0(11),
+       AMU_AMEVTYPE0_EL0(12),
+       AMU_AMEVTYPE0_EL0(13),
+       AMU_AMEVTYPE0_EL0(14),
+       AMU_AMEVTYPE0_EL0(15),
+       AMU_AMEVCNTR1_EL0(0),
+       AMU_AMEVCNTR1_EL0(1),
+       AMU_AMEVCNTR1_EL0(2),
+       AMU_AMEVCNTR1_EL0(3),
+       AMU_AMEVCNTR1_EL0(4),
+       AMU_AMEVCNTR1_EL0(5),
+       AMU_AMEVCNTR1_EL0(6),
+       AMU_AMEVCNTR1_EL0(7),
+       AMU_AMEVCNTR1_EL0(8),
+       AMU_AMEVCNTR1_EL0(9),
+       AMU_AMEVCNTR1_EL0(10),
+       AMU_AMEVCNTR1_EL0(11),
+       AMU_AMEVCNTR1_EL0(12),
+       AMU_AMEVCNTR1_EL0(13),
+       AMU_AMEVCNTR1_EL0(14),
+       AMU_AMEVCNTR1_EL0(15),
+       AMU_AMEVTYPE1_EL0(0),
+       AMU_AMEVTYPE1_EL0(1),
+       AMU_AMEVTYPE1_EL0(2),
+       AMU_AMEVTYPE1_EL0(3),
+       AMU_AMEVTYPE1_EL0(4),
+       AMU_AMEVTYPE1_EL0(5),
+       AMU_AMEVTYPE1_EL0(6),
+       AMU_AMEVTYPE1_EL0(7),
+       AMU_AMEVTYPE1_EL0(8),
+       AMU_AMEVTYPE1_EL0(9),
+       AMU_AMEVTYPE1_EL0(10),
+       AMU_AMEVTYPE1_EL0(11),
+       AMU_AMEVTYPE1_EL0(12),
+       AMU_AMEVTYPE1_EL0(13),
+       AMU_AMEVTYPE1_EL0(14),
+       AMU_AMEVTYPE1_EL0(15),
+
        { SYS_DESC(SYS_CNTP_TVAL_EL0), access_arch_timer },
        { SYS_DESC(SYS_CNTP_CTL_EL0), access_arch_timer },
        { SYS_DESC(SYS_CNTP_CVAL_EL0), access_arch_timer },