aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kvm/hyp/vgic-v3-sr.c
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2021-03-05 18:52:53 +0000
committerPaolo Bonzini <pbonzini@redhat.com>2021-03-06 04:18:41 -0500
commit9739f6ef053f104a997165701c6e15582c4307ee (patch)
tree9d587b064d86e522cce5ffb4cdb9183baf908fb4 /arch/arm64/kvm/hyp/vgic-v3-sr.c
parentKVM: arm64: Rename __vgic_v3_get_ich_vtr_el2() to __vgic_v3_get_gic_config() (diff)
downloadlinux-dev-9739f6ef053f104a997165701c6e15582c4307ee.tar.xz
linux-dev-9739f6ef053f104a997165701c6e15582c4307ee.zip
KVM: arm64: Workaround firmware wrongly advertising GICv2-on-v3 compatibility
It looks like we have broken firmware out there that wrongly advertises a GICv2 compatibility interface, despite the CPUs not being able to deal with it. To work around this, check that the CPU initialising KVM is actually able to switch to MMIO instead of system registers, and use that as a precondition to enable GICv2 compatibility in KVM. Note that the detection happens on a single CPU. If the firmware is lying *and* that the CPUs are asymetric, all hope is lost anyway. Reported-by: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com> Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Message-Id: <20210305185254.3730990-8-maz@kernel.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/arm64/kvm/hyp/vgic-v3-sr.c')
-rw-r--r--arch/arm64/kvm/hyp/vgic-v3-sr.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 005daa0c9dd7..ee3682b9873c 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -408,11 +408,42 @@ void __vgic_v3_init_lrs(void)
/*
* Return the GIC CPU configuration:
* - [31:0] ICH_VTR_EL2
- * - [63:32] RES0
+ * - [62:32] RES0
+ * - [63] MMIO (GICv2) capable
*/
u64 __vgic_v3_get_gic_config(void)
{
- return read_gicreg(ICH_VTR_EL2);
+ u64 val, sre = read_gicreg(ICC_SRE_EL1);
+ unsigned long flags = 0;
+
+ /*
+ * To check whether we have a MMIO-based (GICv2 compatible)
+ * CPU interface, we need to disable the system register
+ * view. To do that safely, we have to prevent any interrupt
+ * from firing (which would be deadly).
+ *
+ * Note that this only makes sense on VHE, as interrupts are
+ * already masked for nVHE as part of the exception entry to
+ * EL2.
+ */
+ if (has_vhe())
+ flags = local_daif_save();
+
+ write_gicreg(0, ICC_SRE_EL1);
+ isb();
+
+ val = read_gicreg(ICC_SRE_EL1);
+
+ write_gicreg(sre, ICC_SRE_EL1);
+ isb();
+
+ if (has_vhe())
+ local_daif_restore(flags);
+
+ val = (val & ICC_SRE_EL1_SRE) ? 0 : (1ULL << 63);
+ val |= read_gicreg(ICH_VTR_EL2);
+
+ return val;
}
u64 __vgic_v3_read_vmcr(void)