KVM: arm64: Make most GICv3 accesses UNDEF if they trap
authorMarc Zyngier <maz@kernel.org>
Tue, 27 Aug 2024 15:25:15 +0000 (16:25 +0100)
committerMarc Zyngier <maz@kernel.org>
Tue, 27 Aug 2024 17:32:56 +0000 (18:32 +0100)
We don't expect to trap any GICv3 register for host handling,
apart from ICC_SRE_EL1 and the SGI registers. If they trap,
that's because the guest is playing with us despite being
told it doesn't have a GICv3.

If it does, UNDEF is what it will get.

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Link: https://lore.kernel.org/r/20240827152517.3909653-10-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/hyp/vgic-v3-sr.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/sys_regs.h

index 39f6363caa1f3a818ebc9a08d8d506cdabe437dc..18d4677002b1a603bd70831b2e555ef2862cb37d 100644 (file)
@@ -1120,6 +1120,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
        bool is_read;
        u32 sysreg;
 
+       if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+               return 0;
+
        esr = kvm_vcpu_get_esr(vcpu);
        if (vcpu_mode_is_32bit(vcpu)) {
                if (!kvm_condition_valid(vcpu)) {
index a57374de69686ad423fd95a8bd8639cf3b3c6cd7..b93ad721fb7f570990a5b11e9fcbbfea2d3d3ac6 100644 (file)
@@ -47,6 +47,13 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      u64 val);
 
+static bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+                        const struct sys_reg_desc *r)
+{
+       kvm_inject_undefined(vcpu);
+       return false;
+}
+
 static bool bad_trap(struct kvm_vcpu *vcpu,
                     struct sys_reg_params *params,
                     const struct sys_reg_desc *r,
@@ -484,6 +491,9 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
                           struct sys_reg_params *p,
                           const struct sys_reg_desc *r)
 {
+       if (!kvm_has_gicv3(vcpu->kvm))
+               return undef_access(vcpu, p, r);
+
        if (p->is_write)
                return ignore_write(vcpu, p);
 
@@ -1344,14 +1354,6 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
          .reset = reset_pmevtyper,                                     \
          .access = access_pmu_evtyper, .reg = (PMEVTYPER0_EL0 + n), }
 
-static bool undef_access(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)), undef_access }
 #define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), undef_access }
@@ -2454,6 +2456,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_SPSR_EL1), access_spsr},
        { SYS_DESC(SYS_ELR_EL1), access_elr},
 
+       { SYS_DESC(SYS_ICC_PMR_EL1), undef_access },
+
        { SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 },
        { SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 },
        { SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 },
@@ -2508,18 +2512,31 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 },
        { SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 },
 
-       { SYS_DESC(SYS_ICC_IAR0_EL1), write_to_read_only },
-       { SYS_DESC(SYS_ICC_EOIR0_EL1), read_from_write_only },
-       { SYS_DESC(SYS_ICC_HPPIR0_EL1), write_to_read_only },
-       { SYS_DESC(SYS_ICC_DIR_EL1), read_from_write_only },
-       { SYS_DESC(SYS_ICC_RPR_EL1), write_to_read_only },
+       { SYS_DESC(SYS_ICC_IAR0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_EOIR0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_HPPIR0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_BPR0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP0R0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP0R1_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP0R2_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP0R3_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP1R0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_DIR_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
        { SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
        { SYS_DESC(SYS_ICC_ASGI1R_EL1), access_gic_sgi },
        { SYS_DESC(SYS_ICC_SGI0R_EL1), access_gic_sgi },
-       { SYS_DESC(SYS_ICC_IAR1_EL1), write_to_read_only },
-       { SYS_DESC(SYS_ICC_EOIR1_EL1), read_from_write_only },
-       { SYS_DESC(SYS_ICC_HPPIR1_EL1), write_to_read_only },
+       { SYS_DESC(SYS_ICC_IAR1_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_HPPIR1_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_BPR1_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_CTLR_EL1), undef_access },
        { SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
+       { SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
+       { SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
 
        { SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
        { SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
@@ -3394,6 +3411,7 @@ static const struct sys_reg_desc cp15_regs[] = {
        /* TTBCR2 */
        { AA32(HI), Op1( 0), CRn( 2), CRm( 0), Op2( 3), access_vm_reg, NULL, TCR_EL1 },
        { Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, DACR32_EL2 },
+       { CP15_SYS_DESC(SYS_ICC_PMR_EL1), undef_access },
        /* DFSR */
        { Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, ESR_EL1 },
        { Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, IFSR32_EL2 },
@@ -3443,8 +3461,28 @@ static const struct sys_reg_desc cp15_regs[] = {
        /* AMAIR1 */
        { AA32(HI), Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, AMAIR_EL1 },
 
-       /* ICC_SRE */
-       { Op1( 0), CRn(12), CRm(12), Op2( 5), access_gic_sre },
+       { CP15_SYS_DESC(SYS_ICC_IAR0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_EOIR0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_HPPIR0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_BPR0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP0R0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP0R1_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP0R2_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP0R3_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP1R0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_DIR_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_IAR1_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_HPPIR1_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_BPR1_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_CTLR_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
+       { CP15_SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
+       { CP15_SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
 
        { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, CONTEXTIDR_EL1 },
 
index 7c9b4eb0baa628403d7e4542d3bf0f3cb2c0bea9..dfb2ec83b28429c89572367ccc6aaa65875201b3 100644 (file)
@@ -250,4 +250,11 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
        CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)),   \
        Op2(sys_reg_Op2(reg))
 
+#define CP15_SYS_DESC(reg)                             \
+       .name = #reg,                                   \
+       .aarch32_map = AA32_DIRECT,                     \
+       Op0(0), Op1(sys_reg_Op1(reg)),                  \
+       CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)),   \
+       Op2(sys_reg_Op2(reg))
+
 #endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */